Counting Descending numbers? - java

I've been working on taking an array, lets say : {5,4,3,8,9,8,8,7,6} is my array. My goal is to find out how many sets of descending numbers there are in this array.
So far I've used my code to compare if the number in that index is less than the previous number. This is as far as I've gotten, and it prints out all the values that were smaller than the previous index value.
I'm semi new to java and have worked in python before, so I'm not quite sure how I would store the values that are less than the previous and how many total sets there are
public class Descending {
public static void main(final String[] args) {
int[] x = {5, 4, 3, 8, 9, 8, 8, 7, 6 };
countDescents(x);
}
public static void countDescents(final int[] xs) {
int total = 0;
// start with first index value.
// Compare to previous index value to see if it is descending.
for (int i = 1; i < xs.length; i++) {
if (xs[i] < xs[i - 1]) {
System.out.print(xs[i]);
}
}
}
}
In this example the total amount of descending sets would be 3 (desired output), those being 5,4,3 & 9,8 & 8,7,6
(The only reason my print statement is at that point in the loop is just to see if it was the right numbers as descending)

Given you don't need to know the length of the runs, just the number of them, then you are really just looking for how many times a run starts: i.e. an elements is one less than the previous but the same is not true for the previous element:
int runCount = 0;
boolean inRun = false;
for (int i = 1; i < array.length; i++) {
if (array[i] < array[i - 1] && !inRun)
runCount++;
inRun = array[i] < array[i - 1];
}
If you are using Java 8 you could do this with an IntStream instead of iteration:
int runCount = IntStream(1, array.length)
.filter(i -> array[i] < array[i - 1])
.filter(i -> i == 1 || array[i - 1] >= array[i - 2])
.count();
It's a bit unclear if you are looking to actually store the descending runs rather than just count them. If you need to know what the runs are then you will need to collect them in a list. Let me know in the comments if you want help with that.

Related

Find all combinations of an array and get top k sum elements

I have an array of numbers say [1,2,3,1,1000] , now I want to get all possible combinations of this array and calculate its sum. Combinations are valid such that two combinations have different subset of elements. Then order all the sum values in descending order and get the top k elements.
Example:
[1,2,3,1,1000]
Combinations:
Duplicates of earlier ones are striked out, for example (3,1) matches the earlier (1,3).
(), (1), (2), (3), (1), (1000), (1,2), (1,3), (1,1), (1,1000), (2,3), (2,1), (2,1000), (3,1), (3,1000), (1,1000), (1,2,3), (1,2,1), (1,2,1000), (1,3,1), (1,3,1000), (1,1,1000), (2,3,1), (2,3,1000), (2,1,1000), (3,1,1000), (1,2,3,1), (1,2,3,1000), (1,2,1,1000), (1,3,1,1000), (2,3,1,1000), (1,2,3,1,1000)
And the corresponding sums:
0, 1, 2, 3, 1, 1000, 3, 4, 2, 1001, 5, 3, 1002, 4, 1003, 1001, 6, 4, 1003, 5, 1004, 1002, 6, 1005, 1003, 1004, 7, 1006, 1004, 1005, 1006, 1007
Getting top k=3, sums = 1007, 1006, 1005
So output is [1007, 1006, 1005].
Constraints:
Array size n = 1 to 105
Array elements -109 to 109
k ranges from 1 to 2000
This is my code, reference taken from here:
static List<Long> printDistSum(int arr[]) {
List<Long> list = new ArrayList<>();
int n = arr.length;
// There are totoal 2^n subsets
long total = (long) Math.pow(2, n);
// Consider all numbers from 0 to 2^n - 1
for (int i = 0; i < total; i++) {
long sum = 0;
// Consider binary representation of
// current i to decide which elements
// to pick.
for (int j = 0; j < n; j++)
if ((i & (1 << j)) != 0)
sum += arr[j];
// Print sum of picked elements.
list.add(sum);
}
return list;
}
This code works for small range of inputs but times out for large range of inputs. How to solve this program.
I probably have solution that should be good enough. It has time complexity O(n * k * log(k)).
First we need to calculate max sum - sum of all positive values.
Next we need to iterate over positive values, from smallest to largest. For each of these values we calculate sums of new combinations (at the start we have one combination with max sum).
New combinations will not contains given value so we need to substract it from sum.
At the end we need to iterate over negative values. These values are not belongs to combinations from previous step so we need to add these values to sums.
In every iteration are needed only k maximum sums. I used the PriorityQueue to store these sums. That class use heap data structure so adding/removing values has logarithmic time.
Code:
private static long[] findSums(int[] array, int k) {
long maxSum = Arrays.stream(array).filter(it -> it >= 0).sum();
int[] positives = Arrays.stream(array).filter(it -> it >= 0).sorted().toArray();
int[] negatives = Arrays.stream(array).filter(it -> it < 0).sorted().toArray();
// sort time complexity is O(n*log(n))
PriorityQueue<Long> sums = new PriorityQueue<>(k); // priority queue is implemented using heap so adding element has time complexity O(log(n))
sums.add(maxSum); // we start with max sum - combination of all positive elements
int previous = Integer.MIN_VALUE;
Long[] previousAddedSums = {};
Long[] sumsToIterate;
// iterate over positive values
for (int i = 0; i < positives.length; i++) {
if (positives[i] == previous) {
sumsToIterate = previousAddedSums;
} else {
sumsToIterate = sums.toArray(new Long[sums.size()]);
}
previousAddedSums = new Long[sumsToIterate.length];
for (int j = 0; j < sumsToIterate.length; j++) {
long newSum = sumsToIterate[j] - positives[i];
// new sum is calculated - value positives[i] is removed from combination (subtracted from sum of that combination)
sums.add(newSum);
previousAddedSums[j] = newSum;
if (sums.size() > k) {
sums.poll(); // only first k maximum sums are needed at the moment
}
}
previous = positives[i];
}
previous = Integer.MAX_VALUE;
// iterate over negative values in reverse order
for (int i = negatives.length - 1; i >= 0; i--) {
if (negatives[i] == previous) {
sumsToIterate = previousAddedSums;
} else {
sumsToIterate = sums.toArray(new Long[sums.size()]);
}
previousAddedSums = new Long[sumsToIterate.length];
for (int j = 0; j < sumsToIterate.length; j++) {
long newSum = sumsToIterate[j] + negatives[i]; // value negatives[i] is added to combination (added to sum of that combination)
sums.add(newSum);
previousAddedSums[j] = newSum;
if (sums.size() > k) {
sums.poll();
}
}
previous = negatives[i];
}
long[] result = new long[sums.size()];
for (int i = sums.size() - 1; i >=0 ; i--) {
result[i] = sums.poll();
}
// get sums from priority queue in proper order
return result;
// this whole method has time complexity O(n * k * log(k))
// k is less than or equal 2000 so it should be good enough ;)
}
Demo: https://ideone.com/yf6POI
Edit: I have fixed my solution. Instead of iterating over distinct values I check if current value is same like previous. In that case I use combinations (sums) created in previous step. This prevents from creating duplicates of combinations.
I'm sorry if I didn't explain this well enough. I don't have experience in describing algorithmic / mathematical things in english.
Pls ignore all previous posts cuz they are all wrong.
Intuitively, we gotta use backtrack to find all desired combos, but it's impossible to backtrack on 10^5 elements.
Constraint 1 <= n <= 10^5 alludes that our algorithm bottlenecked by O(nlogn) sorting
Constraint 1 <= k <= min(2000,2^n) alludes that we can backtrack on k elements since k is less than 11. 2^11=2024/log(2000)=11 -- actually this "2^n" gives away solution :)
My algorithm (nlog(n) + 2^k)
sort the array
Record the highest score combo which is the sum of all positive integers
Find a window in the sorted array of math.min(log(k)--which is less than 11,n) elements -- worst case, this window consists of the
lowest 11 absolute values in the sorted array. Several approaches to
achieve that, since the candidates must be inside 22 elements
window(11 smallest positive values + 11 biggest negative values), we
can use PriorityQueue of size 11 scanning over these 22 elements. or
we can use two pointers to find the sliding window of size 11.
backtrack on this 11 absolute value elements window, find sum of each combo and put them into a size k/k-1 PriorityQueue. (k is for
the case that there's no positive elements)
result is the sum of all positive integers plus (sum deducted by each of k-1 elements in PriorityQueue).
I was also asked the same question yesterday but sadly I was not able to solve it yesterday. I have tried solving it today and think I have the answer today.
First of all I don't think that different subsets mean different costs in a set i.e in array of [1,2,3,1] both subsets are valid => [1,2,3] and [2,3,1] as they both use different 1's. Now here is my solution keeping this in mind. But if you really want to keep distinct elements in set then you can simply remove the multiple elements and do partial_sort then.
Logic
Store sum of all +ve nos. in a variable, say maxsum.
Convert the negative nos. to their absolute values.
Get lowest min(k-1, n) elements in sorted order.
Find all their combinations and subtract them from the maxsum.
While finding all their combinations we only need lowest k-1 combos. So we have to find a way to keep the number of combinations to that. For that use a sorted data structure and limit its size to k and then for every element in the sorted array iterate through the combos and add those combos to the sorted data structure if the end element of that data structure is greater. Also pop the end element after that.
For taking care of the above point I am using 2 vectors since the order already remains sorted.
The proposed solution has time complexity of O(n*log(k) + k^2).
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long int ll;
template <class T>
void print(vector<T> topSumm)
{
for (ll itr : topSumm)
cout << itr << '\t';
cout << '\n';
}
vector<ll> mergeSortedArrays(vector<ll> &minns, vector<ll> &temp)
{
vector<ll> ans(minns.size() + temp.size());
int i{0}, j{0}, k{0};
while (i < minns.size() && j < temp.size())
{
if (temp[j] < minns[i])
ans[k++] = temp[j++];
else
ans[k++] = minns[i++];
}
while (i < minns.size())
ans[k++] = minns[i++];
while (j < temp.size())
ans[k++] = temp[j++];
return ans;
}
vector<ll> topKSum(vector<int> &arr, int k)
{
int n{(int)arr.size()};
ll maxSumm{0};
for (int i{0}; i < n; ++i)
{
if (arr[i] > 0)
maxSumm += arr[i];
else
arr[i] = -arr[i];
}
int nk{min(k - 1, n)};
partial_sort(arr.begin(), arr.begin() + nk, arr.end());
vector<ll> minns{0, maxSumm};
ll summ{};
bool breakOuter{false};
for (int i{0}; i < nk; ++i)
{
vector<ll> temp;
for (ll nums : minns)
{
summ = nums + arr[i];
if (minns.size() + temp.size() < k)
temp.push_back(summ);
else
{
if (minns.back() > summ)
{
minns.pop_back();
temp.push_back(summ);
}
else
{
if (nums == 0)
breakOuter = true;
break;
}
}
}
if (breakOuter)
break;
minns = mergeSortedArrays(minns, temp);
}
vector<ll> ans(k);
int i{0};
for (ll nums : minns)
ans[i++] = maxSumm - nums;
return ans;
}
int main()
{
int t;
cin >> t;
while (t--)
{
int n, k;
cin >> n >> k;
vector<int> arr(n);
ll maxSumm{0};
for (int i{0}; i < n; ++i)
cin >> arr[i];
vector<ll> topSums = topKSum(arr, k);
print<ll>(topSums);
}
return 0;
}

Sorting 2 sets of scores with array in java

I wrote following code to rank 2 sets of scores:
public class ScoreRanking {
public static void main(String[] args) {
int[] score1 = { 9, 3, 6, 19 };
int[] score2 = { 3, 3, 3, 3, 3, 5, 1 };
int[] rank1 = sortScores(score1);
int[] rank2 = sortScores(score2);
for (int i = 0; i < rank1.length; i++) {
System.out.println((i + 1) + ": " + rank1[i]);
}
System.out.println("_________\n");
for (int j = 0; j < rank2.length; j++) {
System.out.println((j + 1) + ": " + rank2[j]);
}
}
static int[] sortScores(int[] sort) {
for (int i = 0; i < sort.length - 1; i++) {
if (sort[i] < sort[i + 1]) {
continue;
} else {
int temp = sort[i];
sort[i] = sort[i + 1];
sort[i + 1] = temp;
}
}
return sort;
}
}
The first set is ordered but the second isn't. I played around with the brackets, tried a different order (int score 1... int rank1... int score2... int rank2... / int score2..., int rank2... int score1... int rank1...) - but the score2 is always "ignored". Can someone please tell me why?
I made a cold debug and I think that you're problem is with the sortScores method.
if I'm not wrong the rank2 array is sorted like this {3, 3, 3, 3, 3, 1, 5}.
The main problem that your facing is that your algorithm only change the i and i+1 elements, but what happen when your i+2 elements in lower than the i element, there the method fails doesn't do the job correctly.
If you want to develop a sorting algorithm by you I recommend that first make sort an array with 5 or 4 elements in paper and them try to understand what are you doing, them write the steps in pseudo code and finally translate into Java is longer but I guaranteed you that it will be more satisfactory, but if you want to sort the array write now them you should check the sorting algorithms on Wikipedia and take a special look on the Insertion sort is easy to understand and doesn't have much complexity.
At last, if you want to used java libraries to save time and code them you should check the Array class the sort(int[] a) method.
I hope that my answers help you to understand better this world.
Bye, Greetings from Venezuela
PD. The Insertion Sort Algorithm is this one:
public static void insertionSort (int[] array) {
for (int i=1; i < array.length; i++) {
int aux = array[i];
int j;
for (j=i-1; j >= 0 && array[j] > aux; j--){
array[j+1] = array[j];
}
array[j+1] = aux;
}
}
I'd suggest you looked up sorting algorithms as dev8080 suggested. Your sorting algorithm only goes through the list once, which is unheard of. And while your sorting algorithm may end up working for the first array, for the second array it has problems:
if (sort[i] < sort[i + 1])
With this condition you're swapping values even if they're equal, which means you're unnecessarily swapping those 3's. This might not have a visible effect, but it is a wasteful operation, and for more complex objects could produce undesirable effects.
At any rate your code only swaps the values when
sort[i] = 5
sort[i + 1] = 1
because this is the only place where the first value is less than the second one. This is why you get the result
1: 3
2: 3
3: 3
4: 3
5: 3
6: 1
7: 5
It looks like you're trying to implement an variant of bubble sort, in which case you should check out this link:
https://en.wikipedia.org/wiki/Bubble_sort
keep in mind bubble sort is not very efficient for larger lists

Even numbers before odd numbers using array and only one loop

I attempted the problem. I am not getting the right solution. Kindly help.
Problem : Return an array that contains the exact same numbers as the given array, but rearranged so that all the even numbers come before all the odd numbers. Other than that, the numbers can be in any order. You may modify and return the given array, or make a new array.
evenOdd([1, 0, 1, 0, 0, 1, 1]) → [0, 0, 0, 1, 1, 1, 1]
evenOdd([3, 3, 2]) → [2, 3, 3]
evenOdd([2, 2, 2]) → [2, 2, 2]
public int[] evenOdd(int[] nums) {
int l = nums.length;
if(l<2)
return nums;
int j=l-1;
for(int i=0;i<l;i++)
{
if(nums[i]%2==1)
{
while(j>i && nums[j]%2!=0) {
j--;
}
int t=nums[i];
nums[i]=nums[j];
nums[j]=t;
j--;
}
}
return nums;
}
As order of array doesn't matter and you need only one loop, you can try below function,
public int[] evenOdd(int[] nums) {
if (nums.length < 2) return nums;
int[] result = new int[nums.length];
int even = 0;
int odd = nums.length - 1;
for (int i = 0; i < nums.length; i++) {
if (nums[i] % 2 == 0)
result[even++] = nums[i];
else
result[odd--] = nums[i];
}
return result;
}
You're actually super close. If you just wrap this code that you have:
int t = nums[i];
nums[i] = nums[j];
nums[j] = t;
j--;
inside of an if
if (j > i)
your code actually works.
Not sure if this is "cheating", but you could create 2 arrays, 1 to hold the evens and 1 to hold the odds. In your loop, you would copy all the numbers of each value to their even or odd array, and then after the loop, join/merge the arrays together in a new array and return the new array.
If performance is not too important, you could use a stream:
static int[] evenOdd(int[] nums) {
return Arrays.stream(nums)
.boxed()
.sorted(Comparator.comparingInt(i -> i % 2))
.mapToInt(i -> i)
.toArray();
}
Unfortunately, IntStream doesn't have a sorted method that takes a Comparator (only a parameterless method, that's why you have to box and unbox to use Stream.sorted(Comparator).
Here is a code that takes O(N) time and O(1) space to accomplish your task. I apologise for the Python code.
arr = list(map(int, raw_input().split()))
i = 0
j = len(arr) - 1
while i<j:
if arr[i]%2 != 0 and arr[j]%2 == 0:
t = arr[i]
arr[i] = arr[j]
arr[j] = t
i = i + 1
j = j -1
elif arr[i]%2 == 0 and arr[j]%2 == 0:
i = i + 1
elif arr[i]%2 == 0 and arr[j]%2 != 0:
j = j - 1
else:
j = j - 1
print arr
Explanation: The code logic is quite self explanatory. We have two counters, i starting from left end and j starting from right end. If the left counter is pointing to an even then we just increment it, as it is in its correct place. [Remember you want to shift evens to the left. So this even is already in the left side of the array.So we just increment i]. Please look at the code logic to find out what actions are taken based on the current pointers on an even or an odd element.
For example:
If we find i pointing to an odd and j pointing to an `even, then we swap and move both pointers. This is understandable, I hope
The above solution is in-place and takes O(1) space and O(N) time... Hope this helps!!

Finding all possible subset sum which is equal to 0 out of set of positive and negative numbers? [duplicate]

This question already has answers here:
given a set of n integers, return all subsets of k elements that sum to 0
(3 answers)
Closed 6 years ago.
You have an array which has a set of positive and negative numbers, print all the subset sum which is equal to 0.
I can think of approach where i can cam make all powersets of givcen array and check if their sum is 0. BUt that does not llok like optimized solution to
me.
After reading looks a bit similar problem on net , looks like it can be solved with dynamic programming like below program to find if there is combination exist
to make sum 11 just an example ?
public boolean subsetSum(int input[], int total) {
boolean T[][] = new boolean[input.length + 1][total + 1];
for (int i = 0; i <= input.length; i++) {
T[i][0] = true;
}
for (int i = 1; i <= input.length; i++) {
for (int j = 1; j <= total; j++) {
if (j - input[i - 1] >= 0) {
T[i][j] = T[i - 1][j] || T[i - 1][j - input[i - 1]];
} else {
T[i][j] = T[i-1][j];
}
}
}
return T[input.length][total];
}
public static void main(String args[]) {
TestDynamic ss = new TestDynamic();
int arr1[] = {2, 3, 7, 8};
System.out.print(ss.subsetSum(arr1, 11));
}
But i am not sure how to extend above programe to
1) Include negative number
2) find combination of elements whick makes sum as zero( Above program just finds whether its possible to make given sum but does not
find which set of numbers makes it zero)
Here is a full implementation in Javascript. You can run it with node.js.
function target_sum(a, k, x)
{
if (k == a.length) return [];
if (a[k] == x) {
return [[a[k]]];
} else {
var s = target_sum(a, k + 1, x); // not using a[k]
var t = target_sum(a, k + 1, x - a[k]); // using a[k]
for (var i = 0; i < t.length; ++i) {
t[i].unshift(a[k]); // a[k] is part of the solution
s.push(t[i]); // merge t[] into s[]
}
return s;
}
}
var s = target_sum([1,4,5,2,7,8,-3,-5,-6,9,3,-7,-1,5,6], 0, 0);
for (var i = 0; i < s.length; ++i)
console.log(s[i].join(","));
Note that this is an exponential algorithm. Don't use it on large arrays.
Erwin Rooijakkers also pointed to the right direction. In particular, this post gives another algorithm. I could be wrong about the following – I believe that algorithm trades speed for space. It avoids staging arrays into the call stack, but it has to do more recursions to achieve that.
EDIT: about the algorithm you mentioned. It is not exponential, but it only works for positive numbers if I am right. Its time complexity is also proportional to the target sum, which may not be ideal depending on input.

finding longest sequence of consecutive numbers

Problem H (Longest Natural Successors):
Two consecutive integers are natural successors if the second is the successor of the first in the sequence of natural numbers (1 and 2 are natural successors). Write a program that reads a number N followed by N integers, and then prints the length of the longest sequence of consecutive natural successors.
Example:
Input 7 2 3 5 6 7 9 10 Output 3 this is my code so far and i have no idea why it does not work
import java.util.Scanner;
public class Conse {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int x = scan.nextInt();
int[] array = new int[x];
for (int i = 0; i < array.length; i++) {
array[i] = scan.nextInt();
}
System.out.println(array(array));
}
public static int array(int[] array) {
int count = 0, temp = 0;
for (int i = 0; i < array.length; i++) {
count = 0;
for (int j = i, k = i + 1; j < array.length - 1; j++, k++) {
if (Math.abs(array[j] - array[k]) == 1) {
count++;
} else {
if (temp <= count) {
temp = count;
}
break;
}
}
}
return temp + 1;
}
}
Why two loops? What about
public static int array(final int[] array) {
int lastNo = -100;
int maxConsecutiveNumbers = 0;
int currentConsecutiveNumbers = 0;
for (int i = 0; i < array.length; i++) {
if (array[i] == lastNo + 1) {
currentConsecutiveNumbers++;
maxConsecutiveNumbers = Math.max(maxConsecutiveNumbers,
currentConsecutiveNumbers);
} else {
currentConsecutiveNumbers = 1;
}
lastNo = array[i];
}
return Math.max(maxConsecutiveNumbers, currentConsecutiveNumbers);
}
This seems to work:
public static int longestConsecutive(int[] array) {
int longest = 0;
// For each possible start
for (int i = 0; i < array.length; i++) {
// Count consecutive.
for (int j = i + 1; j < array.length; j++) {
// This one consecutive to last?
if (Math.abs(array[j] - array[j - 1]) == 1) {
// Is it longer?
if (j - i > longest) {
// Yup! Remember it.
longest = j - i;
}
} else {
// Start again.
break;
}
}
}
return longest + 1;
}
public void test() {
int[] a = new int[]{7, 2, 3, 5, 6, 7, 9, 10};
System.out.println("Longest: " + Arrays.toString(a) + "=" + longestConsecutive(a));
}
prints
Longest: [7, 2, 3, 5, 6, 7, 9, 10]=3
Since your question has "Problem H" associated with it, I'm assuming you are just learning. Simpler is always better, so it usually pays to break it down into "what has to be done" before starting on a particular road by writing code that approaches the problem with "how can this be done."
In this case, you may be over-complicating things with arrays. A number is a natural successor if it is one greater than the previous number. If this is true, increment the count of the current sequence. If not, we're starting a new sequence. If the current sequence length is greater than the maximum sequence length we've seen, set the max sequence length to the current sequence length. No arrays needed - you only need to compare two numbers (current and last numbers read).
For example:
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int N = scan.nextInt();
int maxSequenceLen = 0; // longest sequence ever
int curSequenceLen = 0; // when starting new sequence, reset to 1 (count the reset #)
int last = 0;
for(int i = 0; i < N; i++) {
int cur = scan.nextInt();
if ((last+1) == cur){
++curSequenceLen;
}
else{
curSequenceLen = 1;
}
if (curSequenceLen > maxSequenceLen){
maxSequenceLen = curSequenceLen;
}
last = cur;
}
System.out.println(maxSequenceLen);
Caveat: I'm answering this on a computer that does not have my Java development environment on it, so the code is untested.
I'm not sure I understand this question correctly. The answer's written here assumes that the the natural successors occur contiguously. But if this is not the same then the solution here might not give the correct answer.
Suppose instead of [7 2 3 5 6 7 9 10] the input was [7 2 6 3 7 5 6 9 10] then the answer becomes 2 while the natural successor [5 6 7] is present in the array.
If the input is not sorted we'll have to use a different approach. Like using HashSet
Load the entire array into a HashSet which removes duplicates.
Pick the first value from the HashSet and assigned it to start and end and remove it from the set.
Now decrements start and check if it is present in the HashSet and continue till a particular value for start is not present int the HashSetwhile removing the value being searched from the set.
Do the same for end except that you will have to increase the value of end for each iteration.
We now have to continuous range from start to end present in the set and whose range is current_Max = end - start + 1
In each iteration we keep track of this current_Max to arrive at the longest natural successor for the entire array.
And since HashSet supports Add, Remove, Update in O(1) time. This algorithm will run in O(n) time, where n is the length of the input array.
The code for this approach in C# can be found here

Categories