Given an input array we can find a single sub-array which sums to K (given) in linear time, by keeping track of sum found so far and the start position. If the current sum b
There is no linear-time algorithm for the case of both positive and negative numbers.
Since you need all sub-arrays which sum to K
, time complexity of any algorithm cannot be better than size of the resulting set of sub-arrays. And this size may be quadratic. For example, any sub-array of [K, -K, K, -K, K, -K, ...]
, starting and ending at positive 'K' has the required sum, and there are N2/8 such sub-arrays.
Still it is possible to get the result in O(N) expected time if O(N) additional space is available.
Compute prefix sum for each element of the array and insert the pair (prefix_sum, index)
to a hash map, where prefix_sum
is the key and index
is the value associated with this key. Search prefix_sum - K
in this hash map to get one or several array indexes where the resulting sub-arrays start:
hash_map[0] = [-1]
prefix_sum = 0
for index in range(0 .. N-1):
prefix_sum += array[index]
start_list = hash_map[prefix_sum - K]
for each start_index in start_list:
print start_index+1, index
start_list2 = hash_map[prefix_sum]
start_list2.append(index)
I found the following to be using Time Complexity of O(n).
function maxSumArr(arr) {
var s = [];
s.length = arr.length;
for (var i in arr){
s[i] = (s[i-1] + arr[i]) > arr[i] ? s[i-1] + arr[i] : arr[i];
}
s = s.reduce((T,c) => (T > c ? T : c))
return s; // gives array of all possible max sub arrays at each index.
}
I also faced this problem in couple of interviews and came up with following best approach:
class MazSubArraySum {
public static void main(String[] args) {
int[] a = { -2, -3, 4, -1, -2, 1, 5, -3 };
System.out.println("Maximum contiguous sum is " + maxSubArraySum(a));
}
static int maxSubArraySum(int a[]) {
int size = a.length;
int currentindex = 0, end = 0, begin = 0;
int max_so_far = Integer.MIN_VALUE, max_ending_here = 0;
for (int i = 0; i < size; i++) {
max_ending_here = max_ending_here + a[i];
if (max_so_far < max_ending_here) {
max_so_far = max_ending_here;
begin = currentindex;
end = i;
}
if (max_ending_here < 0) {
max_ending_here = 0;
currentindex++;
}
}
System.out.println("begin and end: " + begin + "&" + end);
return max_so_far;
}
}
Below is the output:
begin and end: 2&6
Maximum contiguous sum is 7
Above solution is the best solution in terms of time and space complexity that is O(n).