I've been stuck on this problem for some time, and I don't want to just look at an answer. I'd like a hint(s) so that I can get myself thinking in the right direction so that I might gain more insight into solving similar types of algorithm problems. This exercise is actually from CLRS on the section on Divide-and-Conquer algorithms, soon after it introduced what recursion is.
I figured out the pseudocode for (easier) then coded up an n^2-time solution (though I thought it should be n(n-1)/2-time since I thought there were exactly n Choose 2 possible subarrays, but I guess that's a different issue), and I understand the provided O(nlogn) recursive solution.
Here's the problem-statement from CLRS 4.1-5:
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 subarray of A[1..j], extend the answer to find a maximum subarray ending at index j+1 by using the following observation: a maximum subarray of A[1..j+1] is either a maximum subarray of A[1..j] or a subarray A[i..j+1], for some 1 <= i <= j+1. Determine a maximum subarray of the form A[i..j+1] in constant time based on knowing a maximum subarray ending at index j.
Also, of course, the input is A[1..n].
Ok, so I think I understand why the hint makes sense by supposing not then choosing a counter-example (i.e., the following array: [-|+|+|-|neg_1|anything|neg_2|anything|anything] where A[-] represents some non-positive number and A[+] represents some positive number, and A[neg_1] and A[neg_2] are negative; suppose A[neg_1+1..neg_1+1] is a current maximum subarray up till that index, then we find that |A[neg_2]| > A[1..neg_1+1], but A[neg_2+1] > |A[neg_2]| so then the current maximum subarray is A[1..neg_2+1] up till that index. This example shows why the hint makes sense, and it also finds a fault in my attempted O(n)-time solution):
Inside a loop from 1 to n:
- we call the maximum-sum interval "interval"
- we call the soonest negative number after the max-sum interval "neg"
- If sum_from_neg > neg, take {interval[1], j+1} as "interval"
- Otherwise, if sum_from_neg > max_sum take that interval (A[neg+1..j+1]).
This idea doesn't quite work, as I tried to illustrate with my example array from above.
Edit: @ryan's comment (the first comment to this post) didn't really help me much. Anybody have other hints?