Find max sum of two non-intersecting sub arrays - algorithm

Given an array of integers, take any two non-intersecting subarrays, A1 and A2. A subarray could be empty too. we have to return the max(sum(A1,A2)). The return value is the maximum possible sum of two subarrays of the given array.
My Thoughts:
Find the max sum subarray. This will give two new subarrays, the left of it and the right of it. Find the max sum subarray left and right and choose the optimal one. I am not sure if this will yield the max answer.
Any ideas or approach?

Find the max subarray ending at index i going left and find the max subarray ending at index i going right. Then for each candidate, update the best result with the larger of the current best or max_subarray_sum_on_the_left[i] + max_subarray_sum_on_the_right[i+1].
In case it was unclear -- when performing Kadane's algorithm for each direction, save for each index the best seen from that direction. This leads to an O(n) overall solution.

Create array left[] such that left[i] = max subarray sum ending at index i (takes O(N) time)
Create array right[] such that right[i] = max subarray sum starting at index i (takes O(N) time)
Iterate over the arrays and keep track of the max value visited such that left[i] = max possible sum over all subarrays ending at i and right[i] = max possible sum over all subarrays starting at i. (takes O(N) time)
Loop i from 1 to N-1, where i is the index about which we'll "partition" our array and choose non-intersecting subarrays. For a given i, the answer will be left[i] + right[i]
The solution has O(N) space and time complexity.

Related

count the number of subarrays in a given array with its average being k

Given an integer array a, and an integer k, we want to design an algorithm to count the number of subarrays with the average of that subarray being k. The most naive method is to traverse all possible subarrays and calculate the corresponding average. The time complexity of this naive method is O(n^2) where $n$ is the length of a. I wonder whether it is possible to do better than O(n^2).
Usually for this kind of problem, one uses prefix sum together with a hashmap, but this technique does not seem to apply here.
Consider a prefix sum array, call it a.
You want to find all such pairs (i, j) that (a[j]-a[i])/(j-i) == k.
Now watch the hands:
(a[j]-a[i])/(j-i) == k
a[j]-a[i] == k*(j-i)
a[j]-a[i] == k*j-k*i
a[j]-k*j == a[i]-k*i
So if you subtract k*j from jth element of the prefix sum array, you are left with the task of counting identical pairs.

What is the complexity of this approach to finding K largest of N numbers

In this post on how to find the K largest of N elements the 2nd method proposed is:
Store the first k elements in a temporary array temp[0..k-1].
Find the smallest element in temp[], let the smallest element be min.
For each element x in arr[k] to arr[n-1]
If x is greater than the min then remove min from temp[] and insert x.
Print final k elements of temp[]
While I understand the approach, I do not understand their computed
Time Complexity of O((n-k)*k).
From my perspective, you are making a linear traversal of n-k elements and doing a single comparison on each element. And then perhaps replacing one elements of the temporary array of K elements.
More specifically, where does the *k aspect of their computed
Time Complexity of O((n-k)*k) come from? Why do they multipy n-k by that?
Lets consider that at kth iteration :
arr[k] > min(temp[0..k-1]
Now you will replace min(temp[0..k-1]) with arr[k].
And now you again need to compute the updated min of temp[0..k-1], because that would have changed. It can be any number in your updated temp[0..k-1]
So in worst case, u update the min everytime and hence the O(k).
Thus, time complexity = O((n-k)*k)

Finding sub-array sum in an integer array

Given an array of N positive integers. It can have n*(n+1)/2 sub-arrays including single element sub-arrays. Each sub-array has a sum S. Find S's for all sub-arrays is obviously O(n^2) as number of sub-arrays are O(n^2). Many sums S's may be repeated also. Is there any way to find count of all distinct sum (not the exact values of sums but only count) in O(n logn).
I tried an approach but stuck on the way. I iterated the array from index 1 to n.
Say a[i] is the given array. For each index i, a[i] will add to all the sums in which a[i-1] is involved and will include itself also as individual element. But duplicate will emerge if among sums in which a[i-1] is involved, the difference of two sums is a[i]. I mean that, say sums Sp and Sq end up at a[i-1] and difference of both is a[i]. Then Sp + a[i] equals Sq, giving Sq as a duplicate.
Say C[i] is count of the distinct sums in which end up at a[i].
So C[i] = C[i-1] + 1 - numbers of pairs of sums in which a[i-1] is involved whose difference is a[i].
But problem is to find the part of number of pairs in O(log n). Please give me some hint about this or if I am on wrong way and completely different approach is required problem point that out.
When S is not too large, we can count the distinct sums with one (fast) polynomial multiplication. When S is larger, N is hopefully small enough to use a quadratic algorithm.
Let x_1, x_2, ..., x_n be the array elements. Let y_0 = 0 and y_i = x_1 + x_2 + ... + x_i. Let P(z) = z^{y_0} + z^{y_1} + ... + z^{y_n}. Compute the product of polynomials P(z) * P(z^{-1}); the coefficient of z^k with k > 0 is nonzero if and only if k is a sub-array sum, so we just have to read off the number of nonzero coefficients of positive powers. The powers of z, moreover, range from -S to S, so the multiplication takes time on the order of S log S.
You can look at the sub-arrays as a kind of tree. In the sense that subarray [0,3] can be divided to [0,1] and [2,3].
So build up a tree, where nodes are defined by length of the subarray and it's staring offset in the original array, and whenever you compute a subarray, store the result in this tree.
When computing a sub-array, you can check this tree for existing pre-computed values.
Also, when dividing, parts of the array can be computed on different CPU cores, if that matters.
This solution assumes that you don't need all values at once, rather ad-hoc.
For the former, there could be some smarter solution.
Also, I assume that we're talking about counts of elements in 10000's and more. Otherwise, such work is a nice excercise but has not much of a practical value.

Find the farthest sum of two elements from zero in an array

Given an array, what is the most time- and space-efficient algorithm to find the sum of two elements farthest from zero in that array?
Edit
For example, [1, -1, 3, 6, -10] has the farthest sum equal to -11 which is equal to (-1)+(-10).
Using a tournament comparison method to find the largest and second largest elements uses the fewest comparisons, in total n+log(n)-2. Do this twice, once to find the largest and second largest elements, say Z and Y, and again to find the smallest and second smallest elements, say A and B. Then the answer is either Z+Y or -A-B, so one more comparison solves the problem. Overall, this takes 2n+2log(n)-3 comparisons. This is still O(n), but in practice is faster than scanning the entire list 4 times to find A,B,Y,Z (in total uses 4n-5 comparisons).
The tournament method is nicely explained with pictures and sample code in these two tutorials: one and two
If you mean the sum whose absolute value is maximum, it is either the largest sum or the smallest sum. The largest sum is the sum of the two maximal elements. The smallest sum is the sum of the two minimal elements.
So you need to find the four values: Maximal, second maximal, minimal, second minimal. You can do it in a single pass in O(n) time and O(1) memory. I suspect that this question might be about minimizing the constant in O(n) - you can do it by taking elements in fives, sorting each five (it can be done in 7 comparisons) and comparing the two top elements with current-max elements (3 comparisons at worst) and the two bottom elements with current-min elements (ditto.) This gives 2.6 comparisons per element which is a small improvement over the 3 comparisons per element of the obvious algorithm.
Then just sum the two max elements, sum the two min elements and take whichever value has the larger abs().
Let's look at the problem from a general perspective:
Find the largest sum of k integers in your array.
Begin by tracking the FIRST k integers - keep them sorted as you go.
Iterate over the array, testing each integer against the min value of the saved integers thus far.
If it is larger than the min value of the saved integers, replace it with the smallest value, and bubble it up to its proper sorted position.
When you've finished the array, you have your largest k integers.
Now you can easily apply this to k=2.
Just iterate over the array keeping track of the smallest and the largest elements encountered so far. This is time O(n), space O(1) and obviously you can't do better than that.
int GetAnswer(int[] arr){
int min = arr[0];
int max = arr[0];
int maxDistSum = 0;
for (int i = 1; i < arr.Length; ++i)
{
int x = arr[i];
if(Math.Abs(maxDistSum) < Math.Abs(max+x)) maxDistSum = max+x;
if(Math.Abs(maxDistSum) < Math.Abs(min+x)) maxDistSum = min+x;
if(x < min) min = x;
if(x > max) max = x;
}
return maxDistSum;
}
The key observation is that the furthest distance is either the sum of the two smallest elements or the sum of the two largest.

How to find k nearest neighbors to the median of n distinct numbers in O(n) time?

I can use the median of medians selection algorithm to find the median in O(n). Also, I know that after the algorithm is done, all the elements to the left of the median are less that the median and all the elements to the right are greater than the median. But how do I find the k nearest neighbors to the median in O(n) time?
If the median is n, the numbers to the left are less than n and the numbers to the right are greater than n.
However, the array is not sorted in the left or the right sides. The numbers are any set of distinct numbers given by the user.
The problem is from Introduction to Algorithms by Cormen, problem 9.3-7
No one seems to quite have this. Here's how to do it. First, find the median as described above. This is O(n). Now park the median at the end of the array, and subtract the median from every other element. Now find element k of the array (not including the last element), using the quick select algorithm again. This not only finds element k (in order), it also leaves the array so that the lowest k numbers are at the beginning of the array. These are the k closest to the median, once you add the median back in.
The median-of-medians probably doesn't help much in finding the nearest neighbours, at least for large n. True, you have each column of 5 partitioned around it's median, but this isn't enough ordering information to solve the problem.
I'd just treat the median as an intermediate result, and treat the nearest neighbours as a priority queue problem...
Once you have the median from the median-of-medians, keep a note of it's value.
Run the heapify algorithm on all your data - see Wikipedia - Binary Heap. In comparisons, base the result on the difference relative to that saved median value. The highest priority items are those with the lowest ABS(value - median). This takes O(n).
The first item in the array is now the median (or a duplicate of it), and the array has heap structure. Use the heap extract algorithm to pull out as many nearest-neighbours as you need. This is O(k log n) for k nearest neighbours.
So long as k is a constant, you get O(n) median of medians, O(n) heapify and O(log n) extracting, giving O(n) overall.
med=Select(A,1,n,n/2) //finds the median
for i=1 to n
B[i]=mod(A[i]-med)
q=Select(B,1,n,k) //get the kth smallest difference
j=0
for i=1 to n
if B[i]<=q
C[j]=A[i] //A[i], the real value should be assigned instead of B[i] which is only the difference between A[i] and median.
j++
return C
You can solve your problem like that:
You can find the median in O(n), w.g. using the O(n) nth_element algorithm.
You loop through all elements substutiting each with a pair:
the absolute difference to the median, element's value.
Once more you do nth_element with n = k. after applying this algorithm you are guaranteed to have the k smallest elements in absolute difference first in the new array. You take their indices and DONE!
Four Steps:
Use Median of medians to locate the median of the array - O(n)
Determine the absolute difference between the median and each element in the array and store them in a new array - O(n)
Use Quickselect or Introselect to pick k smallest elements out of the new array - O(k*n)
Retrieve the k nearest neighbours by indexing the original array - O(k)
When k is small enough, the overall time complexity becomes O(n).
Find the median in O(n). 2. create a new array, each element is the absolute value of the original value subtract the median 3. Find the kth smallest number in O(n) 4. The desired values are the elements whose absolute difference with the median is less than or equal to the kth smallest number in the new array.
You could use a non-comparison sort, such as a radix sort, on the list of numbers L, then find the k closest neighbors by considering windows of k elements and examining the window endpoints. Another way of stating "find the window" is find i that minimizes abs(L[(n-k)/2+i] - L[n/2]) + abs(L[(n+k)/2+i] - L[n/2]) (if k is odd) or abs(L[(n-k)/2+i] - L[n/2]) + abs(L[(n+k)/2+i+1] - L[n/2]) (if k is even). Combining the cases, abs(L[(n-k)/2+i] - L[n/2]) + abs(L[(n+k)/2+i+!(k&1)] - L[n/2]). A simple, O(k) way of finding the minimum is to start with i=0, then slide to the left or right, but you should be able to find the minimum in O(log(k)).
The expression you minimize comes from transforming L into another list, M, by taking the difference of each element from the median.
m=L[n/2]
M=abs(L-m)
i minimizes M[n/2-k/2+i] + M[n/2+k/2+i].
You already know how to find the median in O(n)
if the order does not matter, selection of k smallest can be done in O(n)
apply for k smallest to the rhs of the median and k largest to the lhs of the median
from wikipedia
function findFirstK(list, left, right, k)
if right > left
select pivotIndex between left and right
pivotNewIndex := partition(list, left, right, pivotIndex)
if pivotNewIndex > k // new condition
findFirstK(list, left, pivotNewIndex-1, k)
if pivotNewIndex < k
findFirstK(list, pivotNewIndex+1, right, k)
don't forget the special case where k==n return the original list
Actually, the answer is pretty simple. All we need to do is to select k elements with the smallest absolute differences from the median moving from m-1 to 0 and m+1 to n-1 when the median is at index m. We select the elements using the same idea we use in merging 2 sorted arrays.
If you know the index of the median, which should just be ceil(array.length/2) maybe, then it just should be a process of listing out n(x-k), n(x-k+1), ... , n(x), n(x+1), n(x+2), ... n(x+k)
where n is the array, x is the index of the median, and k is the number of neighbours you need.(maybe k/2, if you want total k, not k each side)
First select the median in O(n) time, using a standard algorithm of that complexity.
Then run through the list again, selecting the elements that are nearest to the median (by storing the best known candidates and comparing new values against these candidates, just like one would search for a maximum element).
In each step of this additional run through the list O(k) steps are needed, and since k is constant this is O(1). So the total for time needed for the additional run is O(n), as is the total runtime of the full algorithm.
Since all the elements are distinct, there can be atmost 2 elements with the same difference from the mean. I think it is easier for me to have 2 arrays A[k] and B[k] the index representing the absolute value of the difference from the mean. Now the task is to just fill up the arrays and choose k elements by reading the first k non empty values of the arrays reading A[i] and B[i] before A[i+1] and B[i+1]. This can be done in O(n) time.
All the answers suggesting to subtract the median from the array would produce incorrect results. This method will find the elements closest in value, not closest in position.
For example, if the array is 1,2,3,4,5,10,20,30,40. For k=2, the value returned would be (3,4); which is incorrect. The correct output should be (4,10) as they are the nearest neighbor.
The correct way to find the result would be using the selection algorithm to find upper and lower bound elements. Then by direct comparison find the remaining elements from the list.

Resources