Kth sum in an array - c++

I have an array with n elements ,i need to calculate all n*n sum of pair of two elements (array[i]+array[j]).All sums are arranged in ascending order.I need to find Kth sum
for example:
array[] = {3,4,5}
all sums: {(3+3),(3+4),(4+3),(3+5),(5+3),(4+4),(4+5),(5+4),(5+5)}
K = 6
I need to find value for Kth sum ( in this case 6th sum is 4+4 ,i will return 8);
Solution might be very optimal
this is my solution; it isn't optimal:
for(i=0;i<n;i++)
fin>>a[i];
qsort(a, n, sizeof(int), int_cmp);
for(i=0;i<n;i++)
for(j=i;j<n;j++)
{
sum[k]=a[i]+a[j];
if(i!=j)
sum[++k]=a[i]+a[j];
k++;
}
qsort(sum, n*n, sizeof(int), int_cmp);
cout<<sum[nrs-1];

I have seen a similar kind of question from google interview question in that they use two sorted array instead of one but the solution works.One optimization which will work in O(klogk) can be given here.
To find the maximum value in such a case it is necessary to have calculated all the values lesser than it,ie let i,j be the maximum values in your case 5,5 to consider 5,5 to be max it is necessary to have evaluated both 4,5and 5,4.that is i-1,j and i,j-1 So a working code will be to use a heap in c++ it is a priority queue. The code is as follows
#include <iostream>
#include <queue>
using namespace std;
for(i=0;i<n;i++)
fin>>a[i];
qsort(a, n, sizeof(int), int_cmp);
std::priority_queue<int > heap;
heap.add(pair(n-1, n-1)); // biggest pair n=array size
// remove max k-1 times
for (int i = 0; i < k - 1; ++i) {
// get max and remove it from the heap
max = heap.pop();
// add next candidates
heap.push(pair(max.i - 1, max.j));
heap.push(pair(max.i, max.j - 1));
}
// get k-th maximum element
max = heap.pop();
maxVal = a[max.i] + a[max.j];
Now this one is optimized upto O(k.logk) there is another one which gives O(k).You can find it here.Kth sum in O(k)

Related

Finding the number of sub arrays that have a sum of K

I am trying to find the number of sub arrays that have a sum equal to k:
int subarraySum(vector<int>& nums, int k)
{
int start, end, curr_sum = 0, count = 0;
start = 0, end = 0;
while (end < (int)nums.size())
{
curr_sum = curr_sum + nums[end];
end++;
while (start < end && curr_sum >= k)
{
if (curr_sum == k)
count++;
curr_sum = curr_sum - nums[start];
start++;
}
}
return count;
}
The above code I have written, works for most cases, but fails for the following:
array = {-1, -1, 1} with k = 0
I have tried to add another while loop to iterate from the start and go up the array until it reaches the end:
int subarraySum(vector<int>& nums, int k)
{
int start, end, curr_sum = 0, count = 0;
start = 0, end = 0;
while (end < (int)nums.size())
{
curr_sum = curr_sum + nums[end];
end++;
while (start < end && curr_sum >= k)
{
if (curr_sum == k)
count++;
curr_sum = curr_sum - nums[start];
start++;
}
}
while (start < end)
{
if (curr_sum == k)
count++;
curr_sum = curr_sum - nums[start];
start++;
}
return count;
}
Why is this not working? I am sliding the window until the last element is reached, which should have found a sum equal to k? How can I solve this issue?
Unfortunately, you did not program a sliding window in the correct way. And a sliding window is not really a solution for this problem. One of your main issues is, that you do not move the start of the window based on the proper conditions. You always sum up and wait until the sum is greater than the search value.
This will not really work. Especially for your example -1, -1, 1. The running sum of this is: -1, -2, -1 and you do not see the 0, although it is there. You may have the idea to write while (start < end && curr_sum != k), but this will also not work, because you handle the start pointer not correctly.
Your approach will lead to the brute force solution that typically takes something like N*N loop operations, where N is the size of the array. This, because we need a double nested loop.
That will of course always work, but maybe very time-consuming, and, in the end, too slow.
Anyway. Let us implement that. We will start from each value in the std::vector and try out all sub arrays starting from the beginning value. We must evaluate all following values in the std::vector, because for example the last value could be a big negative number and bring down the sum again to the search value.
We could implement this for example like the following:
#include <iostream>
#include <vector>
using namespace std;
int subarraySum(vector<int>& numbers, int searchSumValue) {
// Here we will store the result
int resultingCount{};
// Iterate over all values in the array. So, use all different start values
for (std::size_t i{}; i < numbers.size(); ++i) {
// Here we stor the running sum of the elements in the vector
int sum{ numbers[i] };
// Check for trivial case. A one-element sub-array does already match the search value
if (sum == searchSumValue) ++resultingCount;
// Now we build all subarrays beginning with the start value
for (std::size_t k{ i + 1 }; k < numbers.size(); ++k) {
sum += numbers[k];
if (sum == searchSumValue) ++resultingCount;
}
}
return resultingCount;
}
int main() {
vector v{ -1,-1,1 };
std::cout << subarraySum(v, 0);
}
.
But, as said, the above is often too slow for big vectors and there is indeed a better solution available, which is based on a DP (dynamic programming) algorithm.
It uses so-called prefix sums, running sums, based on the running sum before the current evaluated value.
We need to show an example. Let's use a std::vector with 5 values {1,2,3,4,5}. And we want to look subarrays with a sum of 9.
We can “guess” that there are 2 subarrays: {2,3,4} and {4,5} that have a sum of 9.
Let us investigate further
Index 0 1 2 3 4
Value 1 2 3 4 5
We can now add a running sum and see, how much delta we have between the current evaluated element and the left neighbor or over-next neighbor and so on. And if we have a delta that is equal to our search value, then we must have a subarray building this sum.
Running Sum 1 3 6 10 15
Deltas of 2 3 4 5 against next left
Running sum 5 7 9 against next next left
9 12 against next next next left
Example {2,3,4}. If we evaluate the 4 with a running sum of 10, and subtract the search value 9, then we get the previous running sum 1. “1+9=10” all values are there.
Example {4,5}. If we evaluate the 5 with a running sum of 15, and subtract the search value 9, then we get the previous running sum = 6. “6+9=15” all values are there.
We can find all solutions using the same approach.
So, the only thing we need to do, is to subtract the search value from the current running sum and see, if we have this running sum already calculated before.
Like: “Search-Value” + “previously Calculated Sum” = “Current Running Sum”.
Or: “Current Running Sum” – “Search-Value” = “previously Calculated Sum”
Again, we need to do the subtraction and check, if we already calculated such a sum previously.
So, we need to store all previously calculated running sums. And, because such a sum may appear more than one, we need to find occurrences of equal running sums and count them.
It is very hard to digest, and you need to think a while to understand.
With the above wisdom, you can draft the below potential solution.
#include <iostream>
#include <vector>
#include <unordered_map>
int subarraySum(std::vector<int>& numbers, int searchSumValue) {
// Here we will store the result
int resultingSubarrayCount{};
// Here we will stor all running sums and how ofthen their value appeared
std::unordered_map<int, int> countOfRunningSums;
// Continuosly calculating the running sum
int runningSum{};
// And initialize the first value
countOfRunningSums[runningSum] = 1;
// Now iterate over all values in the vector
for (const int n : numbers) {
// Calculate the running sum
runningSum += n;
// Check, if we have the searched value already available
// And add the number of occurences to our resulting number of subarrays
resultingSubarrayCount += countOfRunningSums[runningSum - searchSumValue];
// Store the new running sum. Respectively. Add 1 to the counter, if the running sum was alreadyy existing
countOfRunningSums[runningSum]++;
}
return resultingSubarrayCount;
}
int main() {
std::vector v{ 1,2,3,4,5 };
std::cout << subarraySum(v, 9);
}

Counting number of longest increasing subsequences by evolving recursive solution

How can I count the number of longest increasing LIS by evolving my recursive solution for example [1,3,5,4,7] returns 2 where the LIS is 1,3,5,7 and 1,3,4,7similarly for [3,3,3,3] it will be 4 where LIS is 3 and there are 4 of them
I compute LIS recursively as follows: (I can optimize this using memoisation and go further to DP and then to a segmented tree as per various solutions but I would like to intuitively lead myself to them)
int numberOfLis(vector<int>& nums)
{
//Set the size of count to the size of num, since there cannot be an LIS greater than the size of nums
vector<int> count(nums.size(), 0);
//Get the size of the maximum LIS and update the frequency of how many similar sizes have been encountered in the count array
int maxcount = LIS(nums, INT32_MIN, 0, count);
//Return the number of occurances by looking it up in our count.
return count[maxcount];
}
int LIS(vector<int>& nums, int prev, int index, vector<int>& count)
{
if (index == nums.size()) return 0;
int with = 0;
//Increasing sequence, lets select it.
if (nums[index] > prev) with = 1 + helper(nums, nums[index], index + 1, count);
//See if we can do better without the current number
int without = helper(nums, prev, index + 1, count);
//Get the maximum seen so far and update the frequency in count array
int maxcount = max(with, without);
++count[maxcount];
return maxcount;
}
I used a count array vector<int>(nums.size(), 0) to increment the max value as I encounter it as ++count[max(with,without)] where the count of the returned max value would be the answer. This lead the count array to have 4 a count of 1 not 2 which is wrong. I am looking for a way to move forward from here.
Updated: Added code for the count array and added comments
The count for a subsequence is more than an increment, as there can be multiple subsequences that end up with the same length.
Working with your example data, when index is 1, both with and without are 3. count[3] is only incremented once, though, even though there are two subsequences with this length, and 3 is returned as the maximum length. When this is used by the previous call (when index is 0), with will be 4 and without 3. count[4] is only increased by 1, even though there are two subsequences of length 4.
You need to change helper to return not just the length of the longest subsequence, but the number of subsequences that have that length.
First, calculate the longest increasing subsequence length starting at kth element of the array.
Then, using this data use something like:
int numberoflis(int k){
if(LIS(k)==1) return 1;
int ret = 0;
for(int i=k+1; i<N; ++i){
if(A[i] > A[k] && LIS(i) == LIS(k)-1){
ret += numberoflis(i);
}
}
return ret;
}
Now you have number of longest increasing subsequences starting at point k. Use a simple loop to figure out the total number of LISs. Also, you should memoize this - but it is easy.

Finding MIN MAX pairs from array

Given a sorted array of N integers, I need to find to all pairs with different indexes(i!=j). I need the maximum (a[j]+a[i]-1) and minimum (a[j]-a[i]+1) out of all pairs with (j>i). Numbers aren't unique but their pairing is allowed. Numbers can't pair with themselves.
What I'm doing right now :
for(i=0;i<n;i++)
{
for(j=i+1;j<n;j++)
{
MAX= max(MAX,a[j] + a[i] -1);
MIN=min(MIN,a[j]-a[i]+1);
}
}
This gives the time complexity of O(n^2). Is there a way to reduce it to O(nlogn) or even less ?
To find the max you just need to add the elements at index n-1 and n-2, as the array is already sorted and the 2 biggest elements will be only at the end of the array. No other element in the array will be bigger than these and hence their sum will also be greater than the sum of any other elements.
MAX = a[n-1] + a[n-2] - 1;
Time complexity : O(1)
For finding the min , you should look for pivot in the array. I choose to start from a[0]. If space is not a constraint create another array of similar size and populate it with the delta values from your pivot.
int[] b = new int[n];
for(int i=1; i<n; i++)
{
b[i] = a[i] - a[0];
}
Now the second array will have the delta values from your pivot. All you have to find is the indices of the Minimum and next-Minimum values of Array b. These 2 will be the closest values to each and hence their difference will also be the least.
Time Complexity : O(n) + O(n) = O(n)
Space Complexity : O(n) as a new array of same size has to be created.

Is this the way the dynamic programming version of maximum subarray sum algorithm works?

At the dynamic programming chapter in my algorithms textbook I have an example of how to solve the maximum sub array sum problem using this technique. I am not sure if I got the idea behind the algorithm so I will describe here how I think it works (after reading several times about it and doing several examples).
Basically, you have an array A of size n, and you want to find the maximum sub array sum of that array. The sub array with maximum sum can be somewhere in the right half of the array, left half, or somewhere in the middle. So you recursively call the function to compute the maximum sub array sum from the left and, then, from the right side of the array. Then, you compute the maximum sub array sum that from the middle of the array to the end, then compute the maximum sub array sum from the middle to the beginning of the array (it's length is not necessarily n/2). Then, if the sum of maximum sub array sum form left plus maximum sub array sum from the right is bigger than the maximum sub array sum from the left half (the one computed recursively ) and the maximum sub array sum from the right half (also computed recursively), then the maximum sub array sum is in the one in middle. Otherwise is the maximum of the one from left half and the one from right half (those were computed recursively).
Did I got the working mechanism of the algorithm?
This is the function that I was analyzing:
int maxSubArraySum(int* arr, int n)
{
if(n == 1)
{
return arr[0];
}
int m = n / 2;
int left = maxSubArraySum(arr, m);
int right = maxSubArraySum(arr + m, n - m);
int leftsum = INT_MIN, rightsum = INT_MIN, sum = 0;
for(int i = m; i < n; i++)
{
sum += arr[i];
rightsum = std::max(rightsum, sum);
}
sum = 0;
for(int i = (m - 1); i >= 0; i--)
{
sum += arr[i];
leftsum = std::max(leftsum, sum);
}
int retval = std::max(left, right);
return std::max(retval, leftsum + rightsum);
}
One does not need always Recursion to achieve dynamic programming. The Kadane's algorithm is a simple example of dynamic programming by breaking down the problem into subproblems reused n-1 times (compare the last so far maximum sub array to the current one n-1 times).

Array balancing point

What is the best way to solve this?
A balancing point of an N-element array A is an index i such that all elements on lower indexes have values <= A[i] and all elements on higher indexes have values higher or equal A[i].
For example, given:
A[0]=4 A[1]=2 A[2]=7 A[3]=11 A[4]=9
one of the correct solutions is: 2. All elements below A[2] is less than A[2], all elements after A[2] is more than A[2].
One solution that appeared to my mind is O(nsquare) solution. Is there any better solution?
Start by assuming A[0] is a pole. Then start walking the array; comparing each element A[i] in turn against A[0], and also tracking the current maximum.
As soon as you find an i such that A[i] < A[0], you know that A[0] can no longer be a pole, and by extension, neither can any of the elements up to and including A[i]. So now continue walking until you find the next value that's bigger than the current maximum. This then becomes the new proposed pole.
Thus, an O(n) solution!
In code:
int i_pole = 0;
int i_max = 0;
bool have_pole = true;
for (int i = 1; i < N; i++)
{
if (A[i] < A[i_pole])
{
have_pole = false;
}
if (A[i] > A[i_max])
{
i_max = i;
if (!have_pole)
{
i_pole = i;
}
have_pole = true;
}
}
If you want to know where all the poles are, an O(n log n) solution would be to create a sorted copy of the array, and look to see where you get matching values.
EDIT: Sorry, but this doesn't actually work. One counterexample is [2, 5, 3, 1, 4].
Make two auxiliary arrays, each with as many elements as the input array, called MIN and MAX.
Each element M of MAX contains the maximum of all the elements in the input from 0..M. Each element M of MIN contains the minimum of all the elements in the input from M..N-1.
For each element M of the input array, compare its value to the corresponding values in MIN and MAX. If INPUT[M] == MIN[M] and INPUT[M] == MAX[M] then M is a balancing point.
Building MIN takes N steps, and so does MAX. Testing the array then takes N more steps. This solution has O(N) complexity and finds all balancing points. In the case of sorted input every element is a balancing point.
Create a double-linked list such as i-th node of this list contains A[i] and i. Traverse this list while elements grow (counting maximum of these elements). If some A[bad] < maxSoFar it can't be MP. Remove it and go backward removing elements until you find A[good] < A[bad] or reach the head of the list. Continue (starting with maxSoFar as maximum) until you reach end of the list. Every element in result list is MP and every MP is in this list. Complexity is O(n) since is maximum of steps is performed for descending array - n steps forward and n removals.
Update
Oh my, I confused "any" with "every" in problem definition :).
You can combine bmcnett's and Oli's answers to find all the poles as quickly as possible.
std::vector<int> i_poles;
i_poles.push_back(0);
int i_max = 0;
for (int i = 1; i < N; i++)
{
while (!i_poles.empty() && A[i] < A[i_poles.back()])
{
i_poles.pop_back();
}
if (A[i] >= A[i_max])
{
i_poles.push_back(i);
}
}
You could use an array preallocated to size N if you wanted to avoid reallocations.