Longest subarray with sum greater than K - arrays

I was trying to understand the code at https://www.geeksforgeeks.org/largest-subarray-having-sum-greater-than-k/amp/
However, I am not following it.
Specifically, I did not understand the following:
what does minInd array hold?
What is the use of minInd in keeping track of largest subarray?
What does find method return?
Illustration with an example would be highly appreciated.

The trivial approach is to do it in O(N^2) time. However you can do it O(N log N) time on expense of space. This solution doesn't follow geeksforgeeks precisely but will give you O(N Log N) solution. I have attached image for better understanding.
Lets take an input array (-2, 3,1,-2,1,1) and create prefix sum array.
A prefix sum array is sum of all elements up to current element: [-2, 1, 2, 0, 1, 2]
e.g: at index 2 in input array sum of all the elements before and including it : -2+3+1=2
Please note that :In below approach Prefix sub array and array implies the same thing. For original input array I will call it original array.
you create a prefix sum array and store the index use to create this prefix sum array (0-5) and put it into a queue.
Take the first content ( prefix sum array) out of the queue. Now if your last value in the prefix sum array is greater than or equal to K then the index you used to create this array is the answer.
If not then lets break this prefix array in two sub prefix sum array and add both of them in the queue. Store their index too.
One consisting of sub prefix array from prefix sum array's start to its end -1. - Second part ( slight change) consisting of prefix sum array from start+1 to end. In the second part you have to subtract the first element from each element present in the sub array (if you check the attached image it will become quite apparent).
Go back to step 2 and repeat until either Queue is empty or you find solution.
Further optimization : you can use memoization to reduce branching . if you have already processed a prefix sub array sum then no need to re-evaluate it again.
Below is the diagram where input is transformed into Prefix array sum and broken down repeatedly into prefix sub array sum until last element of our prefix sub array sum >=k
Note: each node consist of key : the index we are considering for prefix sub array. Value = the actual prefix array sum
Hopefully it will be clearer from the diagram.
Lets say your k=3 and input array =(-2, 3,1,-2,1,1)
you create prefix sum array =[{0-5=[-2, 1, 2, 0, 1, 2]}]
since the last element in the prefix sum array <k you split into two parts
sub array from 0-4=> [-2, 1, 2, 0, 1]
sub array from 1-5=> [1, 2, 0, 1, 2] ( and subtract -2 from each element ) to get [3, 4, 2, 3, 4] a proper prefix sub array
Now your last element in the prefix sub array sum is 4 ( greater than K ) your answer giving you the index of such sub array is 1-5

Related

Given a sorted array of integers find subarrays such that the largest elements of the subarrays are within some distance of the smallest

For example, given an array
a = [1, 2, 3, 7, 8, 9]
and an integer
i = 2. Find maximal subarrays where the distance between the largest and the smallest elements is at most i. The output for the example above would be:
[1,2,3] [7,8,9]
The subarrays are maximal in the sense given two subarrays A and B. There exists no element b in B such that A + b satisfies the condition given. Does there exist a non-polynomial time algorithm for said problem ?
This problem might be solved in linear time using method of two pointers and two deques storing indices, the first deque keeps minimum, another keeps maximum in sliding window.
Deque for minimum (similar for maximum):
current_minimum = a[minq.front]
Adding i-th element of array: //at the right index
while (!minq.empty and a[minq.back] > a[i]):
//last element has no chance to become a minimum because newer one is better
minq.pop_back
minq.push_back(i)
Extracting j-th element: //at the left index
if (!minq.empty and minq.front == j)
minq.pop_front
So min-deque always contains non-decreasing sequence.
Now set left and right indices in 0, insert index 0 into deques, and start to move right. At every step add index in order into deques, and check than left..right interval range is good. When range becomes too wide (min-max distance is exceeded), stop moving right index, check length of the last good interval, compare with the best length.
Now move left index, removing elements from deques. When max-min becomes good, stop left and start with right again. Repeat until array end.

Array operations for maximum sum

Given an array A consisting of N elements. Our task is to find the maximal subarray sum after applying the following operation exactly once:
. Select any subarray and set all the elements in it to zero.
Eg:- array is -1 4 -1 2 then answer is 6 because we can choose -1 at index 2 as a subarray and make it 0. So the resultatnt array will be after applying the operation is : -1 4 0 2. Max sum subarray is 4+0+2 = 6.
My approach was to find start and end indexes of minimum sum subarray and make all elements as 0 of that subarray and after that find maximum sum subarray. But this approach is wrong.
Starting simple:
First, let us start with the part of the question: Finding the maximal subarray sum.
This can be done via dynamic programming:
a = [1, 2, 3, -2, 1, -6, 3, 2, -4, 1, 2, 3]
a = [-1, -1, 1, 2, 3, 4, -6, 1, 2, 3, 4]
def compute_max_sums(a):
res = []
currentSum = 0
for x in a:
if currentSum > 0:
res.append(x + currentSum)
currentSum += x
else:
res.append(x)
currentSum = x
return res
res = compute_max_sums(a)
print(res)
print(max(res))
Quick explanation: we iterate through the array. As long as the sum is non-negative, it is worth appending the whole block to the next number. If we dip below zero at any point, we discard whole "tail" sequence since it will not be profitable to keep it anymore and we start anew. At the end, we have an array, where j-th element is the maximal sum of a subarray i:j where 0 <= i <= j.
Rest is just the question of finding the maximal value in the array.
Back to the original question
Now that we solved the simplified version, it is time to look further. We can now select a subarray to be deleted to increase the maximal sum. The naive solution would be to try every possible subarray and to repeat the steps above. This would unfortunately take too long1. Fortunately, there is a way around this: we can think of the zeroes as a bridge between two maxima.
There is one more thing to address though - currently, when we have the j-th element, we only know that the tail is somewhere behind it so if we were to take maximum and 2nd biggest element from the array, it could happen that they would overlap which would be a problem since we would be counting some of the elements more than once.
Overlapping tails
How to mitigate this "overlapping tails" issue?
The solution is to compute everything once more, this time from the end to start. This gives us two arrays - one where j-th element has its tail i pointing towards the left end of the array(e.g. i <=j) and the other where the reverse is true. Now, if we take x from first array and y from second array we know that if index(x) < index(y) then their respective subarrays are non-overlapping.
We can now proceed to try every suitable x, y pair - there is O(n2) of them. However since we don't need any further computation as we already precomputed the values, this is the final complexity of the algorithm since the preparation cost us only O(n) and thus it doesn't impose any additional penalty.
Here be dragons
So far the stuff we did was rather straightforward. This following section is not that complex but there are going to be some moving parts. Time to brush up the max heaps:
Accessing the max is in constant time
Deleting any element is O(log(n)) if we have a reference to that element. (We can't find the element in O(log(n)). However if we know where it is, we can swap it with the last element of the heap, delete it, and bubble down the swapped element in O(log(n)).
Adding any element into the heap is O(log(n)) as well.
Building a heap can be done in O(n)
That being said, since we need to go from start to the end, we can build two heaps, one for each of our pre-computed arrays.
We will also need a helper array that will give us quick index -> element-in-heap access to get the delete in log(n).
The first heap will start empty - we are at the start of the array, the second one will start full - we have the whole array ready.
Now we can iterate over whole array. In each step i we:
Compare the max(heap1) + max(heap2) with our current best result to get the current maximum. O(1)
Add the i-th element from the first array into the first heap - O(log(n))
Remove the i-th indexed element from the second heap(this is why we have to keep the references in a helper array) - O(log(n))
The resulting complexity is O(n * log(n)).
Update:
Just a quick illustration of the O(n2) solution since OP nicely and politely asked. Man oh man, I'm not your bro.
Note 1: Getting the solution won't help you as much as figuring out the solution on your own.
Note 2: The fact that the following code gives the correct answer is not a proof of its correctness. While I'm fairly certain that my solution should work it is definitely worth looking into why it works(if it works) than looking at one example of it working.
input = [100, -50, -500, 2, 8, 13, -160, 5, -7, 100]
reverse_input = [x for x in reversed(input)]
max_sums = compute_max_sums(input)
rev_max_sums = [x for x in reversed(compute_max_sums(reverse_input))]
print(max_sums)
print(rev_max_sums)
current_max = 0
for i in range(len(max_sums)):
if i < len(max_sums) - 1:
for j in range(i + 1, len(rev_max_sums)):
if max_sums[i] + rev_max_sums[j] > current_max:
current_max = max_sums[i] + rev_max_sums[j]
print(current_max)
1 There are n possible beginnings, n possible ends and the complexity of the code we have is O(n) resulting in a complexity of O(n3). Not the end of the world, however it's not nice either.

Two arrays one with time in, another with time out of something

Lets say we have 2 arrays, one of them (i.e. A) contains the time an object i will come into a room, and the other (i.e. B) contains the time i will leave. Neither of these are in any way sorted and their contents are Real numbers.
For example, object 3 has: A[3]=0.785 and B[3]=4.829.
How would you in O(nlogn) find the max objects in the room at any given time t?
You can try this:
initialize number of objects as zero
sort both arrays
while there are elements left in either array
determine which array's first value is smaller
if the first value in "enter" is smaller, increment number of objects and pop that value
if the first value in "leave" is smaller, decrement number of objects and pop that value
check whether you found a new maximum number of objects
If you can not "pop" elements from the arrays, you can use two index variables instead; also, you will have to add cases for when one of the arrays is already empty.
Sorting has O(nlogn), and the following loop has O(2*n), thus O(nlogn) in total.
Get all times from both arrays and make pairs {time from A or from B; f = +1 for A/ -1 for B}
Sort array of all pairs by time key (in case of tie +1 goes before -1)
Make count = 0
Traverse array of pairs, adding f value to count.
Max value of count is " the max objects in the room"
Example:
A = [2, 5], B = [7, 9]
pairs = (2,1),(5,1),(7,-1),(9,-1)
count = 1, 2, 1, 0
maxcount=2 at interval 5..7

sum of maximum element in all subarays of size >1 starting from every element in an array

We are given an array and we are asked to find the sum of the maximum element of every sub arrays of size >1 starting from every element of an array. for example if the array is [1,2,3,4] then the result should be [9, 7, 4, 0]. We are asked only to find the maximum element of every sub array of size > 1. so for 1 it is max(1,2) + max(1, 2, 3) + max(1, 2, 3, 4) which is 9. The given array need not be sorted. How to solve this question. Thanks in advance.
Create a result array. Sort the input array, then iterate through it backwards 2 elements at a time, appending the sum of the two elements at each iteration to the result array. This is the fastest way to solve this problem. I won't write you the exact answer, but this should be enough to help you.

Finding the k'th element in unsorted array using external function

I need to design an algorithm that finds the k'th smallest element in unsorted array using function that called "MED3":
This function finds the n/3 (floor) and 2n/3 (ceil) elements of the array if it was sorted (very similar to median, but instead of n/2 it returns those values).
I thought about kind of partition around those 2 values, and than to continue like QuickSelect, but the problem is that "MED3" doesn't return indices of the 2 values, only the values.
for example, if the array is: 1, 2, 10, 1, 7, 6, 3, 4, 4 it returns 2 (n/3 value) and 4 (2n/3 value).
I also thought to run over the array and to take all the values between 2 and 4 (for example, in the given array above) to new array and then use "MED3" again, but can be duplicates (if the array is 2, 2, 2, 2, ..., 2 I would take all the elements each time).
Any ideas? I must use "MED3".
* MED3 is like a black box, it runs in linear time.
Thank you.
I think you're on the right track, but instead of taking 2 to 4, I'd suggest removing the first n/3 values that are <= MED3.floor() and the first n/3 values that are >= MED3.ceil(). That avoids issues with too many duplicates. If two passes/cycle aren't too expensive, you can remove all values < MED3.floor() + up to a total of n/3 values = MED3.floor() (do the same for ceil())
then repeat until you are at the k'th smallest target.

Resources