I\'m looking for an more efficient alternative to brute force for finding the longest sub array of an array with a non-negative sum. The numbers range from -5 to 5 in this a
This is called the "longest biased interval" and is a common problem in biology. Here is the algorithm (where in your case L==0
):
Input: A nonempty array of n real numbers `A[1 . . . n]` and a lower bound `L`.
Output: The start and end index of the longest segment of `A` with sum at least `L`.
C[0 . . . n] and M[0 . . . n] are arrays of size n +1, as defined in the context.
M[0]←C[0]←0; x←y←0;
for i←1 to n do
C[i]←C[i −1] + A[i];
if C[i −1]<C[M[i −1]] then M[i]←i −1 else M[i] = M[i −1];
k←i −y +x − 1;
while k >0 do
if C[i] − C[M[k]] >= L then k←M[k] else break;
x←k +1; y←i;
end while
OUTPUT A(x, y);
end for
See Chen, Kuan-Yu, and Kun-Mao Chao. "Optimal algorithms for locating the longest and shortest segments satisfying a sum or an average constraint." Information Processing Letters 96.6 (2005): 197-201.
Here is an illustration of the concept:
you can keep track of 11 things for each element while using dynamic programming, moving from left to right. Those 11 things correspond to the following possible sum :
-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5
For each of these you need to store the left most index, such that sum of the subarray starting at that index and ending in the current index gives that much sum.
This is not a complete solution, but I believe this may serve the purpose of hint.
You can do this in linear time by:
Both B and C will be non-increasing arrays.
Then for each start position in array C, compute the greatest end position in array B such that B[end]>C[start]. This can be done in linear time by:
The greatest value of end-start corresponds to the longest subarray.
The main idea is that once you have a cumulative sum of your array you can compute the value of a subarray by doing a subtraction.
For example, the array:
4 2 -5 3 0 -2
has cumulative values:
A = [4 6 1 4 4 2]
So to find the sum of the second, third, fourth entries (indices 1,2,3 with values 2,-5,3) we can compute:
A[3]-A[0] = 4 - 4 = 0
and so your problem now reduces to finding pairs of values in array A that are furthest apart and also have A[end]>A[start].