maximum subarray of an array with integers [duplicate] - algorithm

This question already has answers here:
Maximum sum sublist?
(13 answers)
Closed 8 years ago.
In an interview one of my friends was asked to find the subarray of an array with maximum sum, this my solution to the problem , how can I improve the solution make it more optimal , should i rather consider doing in a recursive fashion ?
def get_max_sum_subset(x):
max_subset_sum = 0
max_subset_i = 0
max_subset_j = 0
for i in range(0,len(x)+1):
for j in range(i+1,len(x)+1):
current_sum = sum(x[i:j])
if current_sum > max_subset_sum:
max_subset_sum = current_sum
max_subset_i = i
max_subset_j = j
return max_subset_sum,max_subset_i,max_subset_j

Your solution is O(n^2). The optimal solution is linear. It works so that you scan the array from left to right, taking note of the best sum and the current sum:
def get_max_sum_subset(x):
bestSoFar = 0
bestNow = 0
bestStartIndexSoFar = -1
bestStopIndexSoFar = -1
bestStartIndexNow = -1
for i in xrange(len(x)):
value = bestNow + x[i]
if value > 0:
if bestNow == 0:
bestStartIndexNow = i
bestNow = value
else:
bestNow = 0
if bestNow > bestSoFar:
bestSoFar = bestNow
bestStopIndexSoFar = i
bestStartIndexSoFar = bestStartIndexNow
return bestSoFar, bestStartIndexSoFar, bestStopIndexSoFar
This problem was also discussed thourougly in Programming Pearls: Algorithm Design Techniques (highly recommended). There you can also find a recursive solution, which is not optimal (O(n log n)), but better than O(n^2).

This is a well-known problem that displays overlapping optimal substructure, which suggests a dynamic programming (DP) solution. Although DP solutions are usually quite tricky (I think so at least!), this one is a great example to get introduced to the whole concept.
The first thing to note is that the maximal subarray (which must be a contiguous portion of the given array A) ending at position j either consists of the maximimal subarray ending at position j-1 plus A[j], or is empty (this only occurs if A[j] < 0). In other words, we are asking whether the element A[j] is contributing positively to the current maximum sum ending at position j-1. If yes, include it in the maximal subarray so far; if not, don't. Thus, from solving smaller subproblems that overlap we can build up an optimal solution.
The sum of the maximal subarray ending at position j can then be given recursively by the following relation:
sum[0] = max(0, A[0])
sum[j] = max(0, sum[j-1] + A[j])
We can build up these answers in a bottom-up fashion by scanning A from left to right. We update sum[j] as we consider A[j]. We can keep track of the overall maximum value and the location of the maximal subarray through this process as well. Here is a quick solution I wrote up in Ruby:
def max_subarray(a)
sum = [0]
max, head, tail = sum[0], -1, -1
cur_head = 0
(0...a.size).each do |j|
# base case included below since sum[-1] = sum[0]
sum[j] = [0, sum[j-1] + a[j]].max
cur_head = j if sum[j-1] == 0
if sum[j] > max
max, head, tail = sum[j], cur_head, j
end
end
return max, head, tail
end
Take a look at my gist if you'd like to test this for yourself.
This is clearly a linear O(N) algorithm since only one pass through the list is required. Hope this helps!

let n - elements count, a(i) - your array f(i) - maximum sum of subarray that ends at position i (minimum length is 1). Then:
f(0) = a(i);
f(i) = max(f(i-1), 0) + a(i); //f(i-1) when we continue subarray, or 0 - when start at i position
max(0, f(1), f(2), ... , f(n-1)) - the answer

A much better solution approach can be derived by thinking about what conditions must hold for a maximum-sum sub-array: the first item on either end that is not included (if any) must be negative and the last item on either end that is included must be non-negative. You don't need to consider any other end points for the sub-array except where these changes occur in the original data.

There is a short video from MIT that helps you understand this dynamic programming problem.
http://people.csail.mit.edu/bdean/6.046/dp/
Click on the first link under the 'problems' section and you will see it.

Here is a simple O(N) algorithm from http://en.wikipedia.org/wiki/Maximum_subarray_problem
int maxsofar=0;
int maxendinghere=0;
for i=[0 n] {
maxendinghere=max(maxendinghere+x[i],0);
maxsofar=max(maxsofar,maxendinghere);
}

Unless I'm missing something important, if they are positive integers the subset would include the whole array, if they're integers, it would include only positive integers. Is there another constraint there?

Java solution:
Does not work for an array with all negatives.
public static int[] maxsubarray(int[] array) {
//empty array check
if (array.length == 0){
return new int[]{};
}
int max = 0;
int maxsofar = 0;
//indices
int maxsofarstart = 0;
int maxsofarend = 0;
int maxstartindex = 0;
for (int i = 0; i < array.length; i++) {
if (array[i] > 0) {
if (max == 0) {
maxstartindex = i;
}
max = max + array[i];
if (max > maxsofar) {
maxsofar = max;
maxsofarstart = maxstartindex;
maxsofarend = i;
}
} else {
max = 0;
}
}
return Arrays.copyOfRange(array, maxsofarstart, maxsofarend + 1);
}

here is one of most well-expained, tested, working solution - http://rerun.me/blog/2012/08/30/maximum-continuous-subarray-problem-kandanes-algorithm/
package me.rerun;
public class Kadane {
public static void main(String[] args) {
int[] intArr={3, -1, -1, -1, -1, -1, 2, 0, 0, 0 };
//int[] intArr = {-1, 3, -5, 4, 6, -1, 2, -7, 13, -3};
//int[] intArr={-6,-2,-3,-4,-1,-5,-5};
findMaxSubArray(intArr);
}
public static void findMaxSubArray(int[] inputArray){
int maxStartIndex=0;
int maxEndIndex=0;
int maxSum = Integer.MIN_VALUE;
int cumulativeSum= 0;
int maxStartIndexUntilNow=0;
for (int currentIndex = 0; currentIndex < inputArray.length; currentIndex++) {
int eachArrayItem = inputArray[currentIndex];
cumulativeSum+=eachArrayItem;
if(cumulativeSum>maxSum){
maxSum = cumulativeSum;
maxStartIndex=maxStartIndexUntilNow;
maxEndIndex = currentIndex;
}
else if (cumulativeSum<0){
maxStartIndexUntilNow=currentIndex+1;
cumulativeSum=0;
}
}
System.out.println("Max sum : "+maxSum);
System.out.println("Max start index : "+maxStartIndex);
System.out.println("Max end index : "+maxEndIndex);
}
}

This is the correct Java Code which will handle scenarios including all negative numbers.
public static long[] leftToISumMaximize(int N, long[] D) {
long[] result = new long[N];
result[0] = D[0];
long currMax = D[0];
for (int i = 1; i < N; i++) {
currMax = Math.max(D[i], currMax + D[i]);
result[i] = Math.max(result[i - 1], currMax);
}
return result;
}

Not sure but Accepted Solution didn't for work me for all the scenarios (May be I misunderstood it)
So I did small modification, instead of
if(value > 0)
I changed it yo
if(value > bestNow)
.....(I wrote it in Scala)
And it is working for the all scenarios
def findMaxSubArray(list: List[Int]): (Int, Int, Int) = {
var (bestNow,bestSoFar) = (0, 0)
var ( startIndexNow, startIndexSoFar, endIndex) = (-1, -1, -1)
for (i <- 0 until list.length) {
var value = bestNow + list(i)
if (value > bestNow) {
if (bestNow == 0)
startIndexNow = i
bestNow = value
} else
bestNow = 0
if (bestNow > bestSoFar) {
bestSoFar = bestNow
startIndexSoFar = startIndexNow
endIndex = i
}
}
return (bestSoFar, startIndexSoFar, endIndex)
}
def main(args: Array[String]) {
println(findMaxSubArray(List(3, -1, 5, 3, -6, -9, 6, 1)).toString)
println(findMaxSubArray(List(3, -1, 5, 3, -6, -9, 6, 3)).toString)
println(findMaxSubArray(List(20, -1, 5, 3, -6, -9, 6)).toString)
}
Output.....
(max =8, start=2, end=3)
(max=9, start=6, end=7)
(max=20, start=0, end= 0)

I have made a function for a little more general problem:
Find maximum sum subarray (meaning its bounds and sum, not only the sum)
If two subarrays have equal sums then pick the shorter one
If two equally long subarrays have equal sums then pick the one that appears first.
Function is based on Kadane's algorithm and it runs in O(n) time. Basically, this is it:
function MaxSumSubarray(a, n, start out, len out)
-- a - Array
-- n - Length of the array
-- start - On output starting position of largest subarray
-- len - On output length of largest subarray
-- Returns sum of the largest subarray
begin
start = 0
len = 1
int sum = a[0]
curStart = 0
curLen = 1
curSum = a[0]
for i = 2 to n
begin
if a[i] >= curSum + a[i] then
begin
curStart = i
curLen = 1
curSum = a[i]
end
else
begin
curLen = curLen + 1
curSum = curSum + a[i]
end
if (curSum > sum) OR
(curSum = sum AND curLen < len) OR
(curSum = sum AND curLen = len AND curStart < start) then
begin
start = curStart
len = curLen
sum = curSum
end
end
return sum
end
I've uploaded the whole solution in C#, with analysis and examples, in this article: Maximum Sum Subarray

Related

Looking for largest sum inside array

I have a given array [-2 -3 4 -1 -2 1 5 -3] so the largest sum would be 7 (numbers from 3rd to 7th index). This array is just a simple example, the program should be user input elements and length of the array.
My question is, how to determine which sum would be largest?
I created a sum from all numbers and the sum of only positive numbers and yet the positive sum would be great but I didn't used the -1 and -2 after that 3rd index because of the "IF statement" so my sum is 10 and the solution is not good.
I assume your questions is to find the contiguous subarray(containing at least one number) which has the largest sum. Otherwise, the problem is pretty trivial as you can just pick all the positive numbers.
There are 3 solutions that are better than the O(N^2) brute force solution. N is the length of the input array.
Dynamic programming. O(N) runtime, O(N) space
Since the subarray contains at least one number, we know that there are only N possible candidates: subarray that ends at A[0], A[1]...... A[N - 1]
For the subarray that ends at A[i], we have the following optimal substructure:
maxSum[i] = max of {maxSum[i - 1] + A[i], A[i]};
class Solution {
public int maxSubArray(int[] nums) {
int max = Integer.MIN_VALUE;
if(nums == null || nums.length == 0) {
return max;
}
int[] maxSum = new int[nums.length + 1];
for(int i = 1; i < maxSum.length; i++) {
maxSum[i] = Math.max(maxSum[i - 1] + nums[i - 1], nums[i - 1]);
}
for(int i = 1; i < maxSum.length; i++) {
max = Math.max(maxSum[i], max);
}
return max;
}
}
Prefix sum, O(N) runtime, O(1) space
Maintain a minimum sum variable as you iterate through the entire array. When visiting each number in the input array, update the prefix sum variable currSum. Then update the maximum sum and minimum sum shown in the following code.
class Solution {
public int maxSubArray(int[] nums) {
if(nums == null || nums.length == 0) {
return 0;
}
int maxSum = Integer.MIN_VALUE, currSum = 0, minSum = 0;
for(int i = 0; i < nums.length; i++) {
currSum += nums[i];
maxSum = Math.max(maxSum, currSum - minSum);
minSum = Math.min(minSum, currSum);
}
return maxSum;
}
}
Divide and conquer, O(N * logN) runtime
Divide the original problem into two subproblems and apply this principle recursively using the following formula.
Let A[0,.... midIdx] be the left half of A, A[midIdx + 1, ..... A.length - 1] be the right half of A. leftSumMax is the answer of the left subproblem, rightSumMax is the answer of the right subproblem.
The final answer will be one of the following 3:
1. only uses numbers from the left half (solved by the left subproblem)
2. only uses numbers from the right half (solved by the right subproblem)
3. uses numbers from both left and right halves (solved in O(n) time)
class Solution {
public int maxSubArray(int[] nums) {
if(nums == null || nums.length == 0)
{
return 0;
}
return maxSubArrayHelper(nums, 0, nums.length - 1);
}
private int maxSubArrayHelper(int[] nums, int startIdx, int endIdx){
if(startIdx == endIdx){
return nums[startIdx];
}
int midIdx = startIdx + (endIdx - startIdx) / 2;
int leftMax = maxSubArrayHelper(nums, startIdx, midIdx);
int rightMax = maxSubArrayHelper(nums, midIdx + 1, endIdx);
int leftIdx = midIdx, rightIdx = midIdx + 1;
int leftSumMax = nums[leftIdx], rightSumMax = nums[rightIdx];
int leftSum = nums[leftIdx], rightSum = nums[rightIdx];
for(int i = leftIdx - 1; i >= startIdx; i--){
leftSum += nums[i];
leftSumMax = Math.max(leftSumMax, leftSum);
}
for(int j = rightIdx + 1; j <= endIdx; j++){
rightSum += nums[j];
rightSumMax = Math.max(rightSumMax, rightSum);
}
return Math.max(Math.max(leftMax, rightMax), leftSumMax + rightSumMax);
}
}
Try this:
locate the first positive number, offset i.
add the following positive numbers, giving a sum of sum, last offset is j. If this sum is greater than your current best sum, it becomes the current best sum with offsets i to j.
add the negative numbers that follow until you get another positive number. If this negative sum is greater in absolute value than sum, start a new sum at this offset, otherwise continue with the current sum.
go back to step 2.
Stop this when you get to the end of the array. The best positive sum has been found.
If no positive sum can be found, locate the least negative value, this single entry would be your best non-trivial sum.

Maximum Sum of Product

I have a following problem.
Given N numbers, in range -100..100.
It is required to rearrange elements to have maximum sum of product value.
Sum of Product in this task is defined as A1*A2+A2*A3...AN-1*AN
For example, given numbers 10 20 50 40 30.
Then, we can rearrange them following way:
10, 30, 50, 40, 20 from the left to have maximum 10×30+30×50+50×40+40×20=4600
The idea is to sort the sequence, and then put max number in the middle of new sequence, then put next max number to the right, then to the left, and so on.
But, regarding negative numbers this is not working.
I have tried following algorithm:
1) sort initial sequence
2) process positive numbers and zero values how described above
3) process negative numbers how described above
4) find minimum number from positive sequence, it would be either left or right element and add after of before this number processed negative sequence.
For example, given sequence:
1,-2,3,-4,5,-6,7,-8,9,10,11,12,13,14,15,-16
Expected maximum sum of product is 1342.
My algorithm gives next rearrangements:
3,7,10,12,14,15,13,11,9,5,1,-4,-8,-16,-6,-2
Sum of product is 1340.
This seem to work, but it does not.
Could you please advise?
Your approach is sound, but you have to separate the positive and negative numbers.
Sort the array and split it into left and right parts, one containing all the negative numbers, and one containing all the non-negative numbers. Rearrange them as you were doing before, with the largest (absolute) values in the middle and decreasing values placed alternately on either side, but make sure that the smallest values in each part are at opposite ends.
Specifically, the negative number with the smallest absolute value should be the last element of the left part, and the non-negative value with the smallest value should be the first element of the right part.
Then concatenate the two parts and calculate the sum of adjacent products.
Here's a worked example:
arr = [2, 3, 5, -6, -2, -5]
arr.sort() = [-6, -5, -2, 2, 3, 5]
left, right = [-5, -6, -2], [2, 5, 3]
max_sum_of_product = -5*-6 + -6*-2 + -2*2 + 2*5 + 5*3 = 63
I don't have a formal proof of correctness, but this method gives the same results as a brute force search over all permutations of the input array:
def max_sum_of_products(arr):
from itertools import permutations
n = len(arr)
###### brute force method
max1 = max([sum([a[x-1]*a[x] for x in range(1,n)]) for a in permutations(arr)])
###### split method
lo, hi = [x for x in arr if x<0], [x for x in arr if x>=0]
lo.sort()
hi.sort()
lo_ordered, hi_ordered = [], []
t = (len(lo)%2 == 1)
for x in lo:
if t:
lo_ordered = lo_ordered + [x]
else:
lo_ordered = [x] + lo_ordered
t = not t
t = (len(hi)%2 == 0)
for x in hi[::-1]:
if t:
hi_ordered = hi_ordered + [x]
else:
hi_ordered = [x] + hi_ordered
t = not t
arr = lo_ordered + hi_ordered
max2 = sum([arr[x-1]*arr[x] for x in range(1,n)])
return (max1, max2)
def test():
from random import randint
for i in range(10):
a = []
for j in range(randint(4,9)):
a = a + [randint(-10,10)]
print a,
(max1,max2) = max_sum_of_products(a)
if max2!=max1:
print "bad result :-("
else:
print max1
test()
I have written a method in java that will take the array as an input and return the maximum sum of product pairs as output.
First I compute the negative part, then the positive part and then return their computed sum.
While computing the negative part, if the number of elements are odd, then the remaining element needs to be avoided (as it can be multiplied by 0 and nullified), we do this so that that negative addition will lower the sum.
All other negative items are needed to multiplied in pair and summed.
Then coming to second positive part, when we see 1 we need to add it if number of elements are odd, otherwise simply multiply and go forward.
public static long sum(int arr[]) {
Arrays.sort(arr);
long ans = 0;
long ans1 = 0;
boolean flag = false;
boolean flag2 = false;
int[] arr1 = new int[arr.length];
int[] arr2 = new int[arr.length];
int i = 0;
while (arr[i] < 0) {
arr1[i] = arr[i];
i++;
}
if (arr[i] == 0) flag = true;
if (i % 2 == 0) { //even -6,-5,-3,-2,-1
for (int j = 0; j < i - 1; j += 2) {
ans = arr1[j] * arr1[j + 1];
}
} else {
if (flag) {
for (int j = 0; j < i - 2; j += 2) {
ans = arr1[j] * arr1[j + 1];
}
}
}
int j = 0;
while (i<arr.length) {
arr2[j] = arr[i];
i++;
j++;
}
if (arr2[j] == 1) flag2 = true;
if (i % 2 == 0) {
for (int k=i-1; k>0; k-=2) {
ans1 = arr2[k] * arr2[k-1];
}
if (flag2) ans1 = ans1 + 1;
} else {
for (int k=arr2.length-1; k>1; k-=2) {
ans1 = arr2[k] * arr2[k-1];
}
ans1 = ans1 + arr2[0];
}
return ans + ans1;
}

Finding minimal absolute sum of a subarray

There's an array A containing (positive and negative) integers. Find a (contiguous) subarray whose elements' absolute sum is minimal, e.g.:
A = [2, -4, 6, -3, 9]
|(−4) + 6 + (−3)| = 1 <- minimal absolute sum
I've started by implementing a brute-force algorithm which was O(N^2) or O(N^3), though it produced correct results. But the task specifies:
complexity:
- expected worst-case time complexity is O(N*log(N))
- expected worst-case space complexity is O(N)
After some searching I thought that maybe Kadane's algorithm can be modified to fit this problem but I failed to do it.
My question is - is Kadane's algorithm the right way to go? If not, could you point me in the right direction (or name an algorithm that could help me here)? I don't want a ready-made code, I just need help in finding the right algorithm.
If you compute the partial sums
such as
2, 2 +(-4), 2 + (-4) + 6, 2 + (-4) + 6 + (-3)...
Then the sum of any contiguous subarray is the difference of two of the partial sums. So to find the contiguous subarray whose absolute value is minimal, I suggest that you sort the partial sums and then find the two values which are closest together, and use the positions of these two partial sums in the original sequence to find the start and end of the sub-array with smallest absolute value.
The expensive bit here is the sort, so I think this runs in time O(n * log(n)).
This is C++ implementation of Saksow's algorithm.
int solution(vector<int> &A) {
vector<int> P;
int min = 20000 ;
int dif = 0 ;
P.resize(A.size()+1);
P[0] = 0;
for(int i = 1 ; i < P.size(); i ++)
{
P[i] = P[i-1]+A[i-1];
}
sort(P.begin(),P.end());
for(int i = 1 ; i < P.size(); i++)
{
dif = P[i]-P[i-1];
if(dif<min)
{
min = dif;
}
}
return min;
}
I was doing this test on Codility and I found mcdowella answer quite helpful, but not enough I have to say: so here is a 2015 answer guys!
We need to build the prefix sums of array A (called P here) like: P[0] = 0, P[1] = P[0] + A[0], P[2] = P[1] + A[1], ..., P[N] = P[N-1] + A[N-1]
The "min abs sum" of A will be the minimum absolute difference between 2 elements in P. So we just have to .sort() P and loop through it taking every time 2 successive elements. This way we have O(N + Nlog(N) + N) which equals to O(Nlog(N)).
That's it!
The answer is yes, Kadane's algorithm is definitely the way to go for solving your problem.
http://en.wikipedia.org/wiki/Maximum_subarray_problem
Source - I've closely worked with a PhD student who's entire PhD thesis was devoted to the maximum subarray problem.
def min_abs_subarray(a):
s = [a[0]]
for e in a[1:]:
s.append(s[-1] + e)
s = sorted(s)
min = abs(s[0])
t = s[0]
for x in s[1:]:
cur = abs(x)
min = cur if cur < min else min
cur = abs(t-x)
min = cur if cur < min else min
t = x
return min
You can run Kadane's algorithmtwice(or do it in one go) to find minimum and maximum sum where finding minimum works in same way as maximum with reversed signs and then calculate new maximum by comparing their absolute value.
Source-Someone's(dont remember who) comment in this site.
Here is an Iterative solution in python. It's 100% correct.
def solution(A):
memo = []
if not len(A):
return 0
for ind, val in enumerate(A):
if ind == 0:
memo.append([val, -1*val])
else:
newElem = []
for i in memo[ind - 1]:
newElem.append(i+val)
newElem.append(i-val)
memo.append(newElem)
return min(abs(n) for n in memo.pop())
Short Sweet and work like a charm. JavaScript / NodeJs solution
function solution(A, i=0, sum =0 ) {
//Edge case if Array is empty
if(A.length == 0) return 0;
// Base case. For last Array element , add and substart from sum
// and find min of their absolute value
if(A.length -1 === i){
return Math.min( Math.abs(sum + A[i]), Math.abs(sum - A[i])) ;
}
// Absolute value by adding the elem with the sum.
// And recusrively move to next elem
let plus = Math.abs(solution(A, i+1, sum+A[i]));
// Absolute value by substracting the elem from the sum
let minus = Math.abs(solution(A, i+1, sum-A[i]));
return Math.min(plus, minus);
}
console.log(solution([-100, 3, 2, 4]))
Here is a C solution based on Kadane's algorithm.
Hopefully its helpful.
#include <stdio.h>
int min(int a, int b)
{
return (a >= b)? b: a;
}
int min_slice(int A[], int N) {
if (N==0 || N>1000000)
return 0;
int minTillHere = A[0];
int minSoFar = A[0];
int i;
for(i = 1; i < N; i++){
minTillHere = min(A[i], minTillHere + A[i]);
minSoFar = min(minSoFar, minTillHere);
}
return minSoFar;
}
int main(){
int A[]={3, 2, -6, 4, 0}, N = 5;
//int A[]={3, 2, 6, 4, 0}, N = 5;
//int A[]={-4, -8, -3, -2, -4, -10}, N = 6;
printf("Minimum slice = %d \n", min_slice(A,N));
return 0;
}
public static int solution(int[] A) {
int minTillHere = A[0];
int absMinTillHere = A[0];
int minSoFar = A[0];
int i;
for(i = 1; i < A.length; i++){
absMinTillHere = Math.min(Math.abs(A[i]),Math.abs(minTillHere + A[i]));
minTillHere = Math.min(A[i], minTillHere + A[i]);
minSoFar = Math.min(Math.abs(minSoFar), absMinTillHere);
}
return minSoFar;
}
int main()
{
int n; cin >> n;
vector<int>a(n);
for(int i = 0; i < n; i++) cin >> a[i];
long long local_min = 0, global_min = LLONG_MAX;
for(int i = 0; i < n; i++)
{
if(abs(local_min + a[i]) > abs(a[i]))
{
local_min = a[i];
}
else local_min += a[i];
global_min = min(global_min, abs(local_min));
}
cout << global_min << endl;
}

Random integers in array. Find the greatest sum of a continuous subset [duplicate]

This question already has answers here:
Maximum sum sublist?
(13 answers)
Closed 8 years ago.
I had an interview question a while back that I never got a solution for. Apparently there is a "very efficient" algorithm to solve it.
The question: Given an array of random positive and negative numbers, find the continuous subset that has the greatest sum.
Example:
[1, -7, 4, 5, -1, 5]
The best subset here is {4, 5, -1, 5}
I can think of no solution but the brute-force method. What is the efficient method?
Iterate through the list, keeping track of the local sum of the list elements so far.
If the local sum is the highest sum so far, then keep a record of it.
If the local sum reaches 0 or below, then reset it and restart from the next element.
Theory
If the current subset sum is greater than zero it will contribute to future subset sums, so we keep it. On the other hand if the current subset sum is zero or below it will not contribute to future subset sums. So we throw it away and start fresh with a new subset sum. Then it's just a matter of keeping track of when the current subset sum is greater then any previous encountered.
Pseudocode
In-parameter is an array list of length N. The result is stored in best_start and best_end.
best_sum = -MAX
best_start = best_end = -1
local_start = local_sum = 0
for i from 0 to N-1 {
local_sum = local_sum + list[i]
if local_sum > best_sum {
best_sum = local_sum
best_start = local_start
best_end = i
}
if local_sum <= 0 {
local_sum = 0
local_start = i+1
}
}
Convert the list into a list of cumulative sums, [1,-7,4,5,-1,5] to [1, -6, -2, -3, 2]. Then walk through the list of cumulative sums, saving the smallest value so far and the maximum difference between what you see as the current value and what is currently the smallest value.
Got it from here
You can answer this question from CLRS, which includes a tip:
Use the following ideas to develop a nonrecursive, linear-time algorithm for the
maximum-subarray problem.
Start at the left end of the array, and progress toward
the right, keeping track of the maximum subarray seen so far.
Knowing a maximum sub array of A[1..j], extend the answer to find a maximum subarray ending at index j+1 by using the following observation:
a maximum sub array of A[1..j+1] is either a maximum sub array of A[1..j] or a sub array A[i..j+1], for some 1 <= i <= j + 1.
Determine a maximum sub array of the form A[i..j+1] in constant time based on knowing a maximum subarray ending at index j.
max-sum = A[1]
current-sum = A[1]
left = right = 1
current-left = current-right = 1
for j = 2 to n
if A[j] > current-sum + A[j]
current-sum = A[j]
current-left = current-right = j
else
current-sum += A[j]
current-right = j
if current-sum > max-sum
max-sum = current-sum
left = current-left
right = current-right
return (max-sum, left, right)
Too bad Java does not have tuple return type. So, had to print the indices and sum in the method.
public class Kadane {
public static void main(String[] args) {
int[] intArr = {-1, 3, -5, 4, 6, -1, 2, -7, 13, -3};
findMaxSubArray(intArr);
}
public static void findMaxSubArray(int[] inputArray){
int maxStartIndex=0;
int maxEndIndex=0;
int maxSum = Integer.MIN_VALUE;
int sum= 0;
for (int currentIndex = 0; currentIndex < inputArray.length; currentIndex++) {
int eachArrayItem = inputArray[currentIndex];
sum+=eachArrayItem;
if( eachArrayItem > sum){
maxStartIndex = currentIndex;
sum = eachArrayItem;
}
if(sum>maxSum){
maxSum = sum;
maxEndIndex = currentIndex;
}
}
System.out.println("Max sum : "+maxSum);
System.out.println("Max start index : "+maxStartIndex);
System.out.println("Max end index : "+maxEndIndex);
}
}
And here is some shameless marketing : I managed to pull together a slide on how this works
Here is the java class which runs in linear time
public class MaxSumOfContinousSubset {
public static void main(String[] args) {
System.out.println(maxSum(1, -7, 4, 5, -1, 5));
}
private static int maxSum (int... nums) {
int maxsofar = 0;
int maxhere = 0;
for (int i = 0; i < nums.length; i++) {
maxhere = Math.max(maxhere + nums[i], 0);
maxsofar = Math.max(maxhere, maxsofar);
}
return maxsofar;
}
}

Sub array that produces a given sum and product

Given an array of length N. How will you find the minimum length
contiguous sub-array of whose sum is S and whose product is P.
For eg 5 6 1 4 6 2 9 7 for S = 17, Ans = [6, 2, 9] for P = 24, Ans = [4 6].
Just go from left to right, and sum all the numbers, if the sum > S, then throw away left ones.
import java.util.Arrays;
public class test {
public static void main (String[] args) {
int[] array = {5, 6, 1, 4, 6, 2, 9, 7};
int length = array.length;
int S = 17;
int sum = 0; // current sum of sub array, assume all positive
int start = 0; // current start of sub array
int minLength = array.length + 1; // length of minimum sub array found
int minStart = 0; // start of of minimum sub array found
for (int index = 0; index < length; index++) {
sum = sum + array[index];
// Find by add to right
if (sum == S && index - start + 1 < minLength) {
minLength = index - start + 1;
minStart = start;
}
while (sum >= S) {
sum = sum - array[start];
start++;
// Find by minus from left
if (sum == S && index - start + 1 < minLength) {
minLength = index - start + 1;
minStart = start;
}
}
}
// Found
if (minLength != length + 1) {
System.out.println(Arrays.toString(Arrays.copyOfRange(array, minStart, minStart + minLength)));
}
}
}
For your example, I think it is OR.
Product is nothing different from sum, except for calculation.
pseudocode:
subStart = 0;
Sum = 0
for (i = 0; i< array.Length; i++)
Sum = Sum + array[i];
if (Sum < targetSum) continue;
if (Sum == targetSum) result = min(result, i - subStart +1);
while (Sum >= targetSum)
Sum = Sum - array[subStart];
subStart++;
I think that'll find the result with one pass through the array. There's a bit of detail missing there in the result value. Needs a bit more complexity there to be able to return the actual subarray if needed.
To find the Product sub-array just substitute multiplication/division for addition/subtraction in the above algorithm
Put two indices on the array. Lets call them i and j. Initially j = 1 and i =0. If the product between i and j is less than P, increment j. If it is greater than P, increment i. If we get something equal to p, sum up the elements (instead of summing up everytime, maintain an array where S(i) is the sum of everything to the left of it. Compute sum from i to j as S(i) - S(j)) and see whether you get S. Stop when j falls out of the array length.
This is O(n).
You can use a hashmap to find the answer for product in O(N) time with extra space.

Resources