/**
* File: Kadane.hh
* Author: Keith Schwarz (htiek@cs.stanford.edu)
*
* An implementation of Kadane's algorithm for solving the maximum subarray
* problem. In this problem, we are given an array A of real-valued entries
* and want to find the contiguous subarray of elements with maximum total sum.
* This problem can be solved very naively in O(n^3) time by computing all
* O(n^2) possible start and end points, then checking the sum of each range.
* However, using dynamic programming, it's possible to optimize this to run in
* O(n) time by looking more closely at the structure of an optimal solution.
*
* The idea behind Kadane's algorithm is to treat the problem recursively. In
* particular, we will consider the following question. If we think about any
* subarray, that subarray is defined by its start and endpoint. If we
* consider the optimal solution to the problem, then it must still be optimal
* if we were to truncate the array just after that subarray. That is, there
* must be some index in the array for which the maximum-value subarray is the
* largest subarray that ends at that particular index. If we can scan across
* the array and check which location this ends up being, and if we can check
* each possible location in O(1) time each, we'll have ourselves an O(n)
* algorithm for the problem.
*
* Fortunately, if we compute these values in a particular order, we can indeed
* compute all of these values in time O(1) each. The idea is as follows.
* Let's define a function F(i) to be the weight of the maximum-weight subarray
* ending just before position i in the array. This means, for example, that
* F(0) would be 0, since the weight of the maximum-weight subarray ending just
* before the first character is the weight of the empty subarray, which is
* zero.
*
* Now, let's think about the relationship between F(i) and F(i + 1). That is,
* if we were to take the maximum-weight subarray ending just before character
* i, could we use information about it to determine the size of the maximum-
* weight subarray ending just before element i + 1? Well, let's think about
* what the possible maximum subarrays ending just before element i + 1 might
* look like. We can take any number of elements from the suffix of the first
* i elements of the array, of which the one that has the maximum value will be
* given by F(i), the weight of the maximum-weight subarray ending at position
* i. Moreover, we know that F(i) >= 0, since in the worst case the largest
* subarray ending at position i could just be the empty subarray. Thus if we
* want to consider the subarray formed by extending the maximum-weight
* subarray ending just before position i, we would do so by adding in the
* array element at position i. This means that one possible subarray we could
* pick has value F(i) + A[i]. The other option is to take no elements at all,
* which would happen if, for example, the value of A[i] is so enormously
* negative that it would dwarf the result. This means that we have the nice
* recurrence that
*
* F(0) = 0
* F(i + 1) = max { F(i) + A[i], 0 }
*
* This can be computed trivially by a forward scan over the array. Once we
* have all of the values of this function, the maximum one we encounter must
* be the maximum-weight subarray for the overall array. We can implement this
* naively by actually storing all the values of F, but since all we care about
* is the maximum value attained by F, we can do so in O(1) space by just
* storing the maximum value encountered so far. The result is an O(n)-time,
* O(1)-space algorithm for finding the maximum-weight subarray of the array.
* Moreover, the algorithm works perfectly fine on a stream of elements, since
* we need just one pass over the data.
*/
#ifndef Kadane_Included
#define Kadane_Included
#include <iterator> // For std::iterator_traits
#include <algorithm> // For std::max
/**
* Function: MaximumSubarrayWeight(InputIterator begin, InputIterator end);
* Usage: cout << MaximumSubarrayWeight(v.begin(), v.end());
* ----------------------------------------------------------------------------
* Given a range of elements [begin, end), returns the weight of the maximum-
* weight subarray in the range [begin, end).
*/
template <typename InputIterator>
typename std::iterator_traits<InputIterator>::value_type
MaximumWeightSubarray(InputIterator begin, InputIterator end) {
/* For sanity's sake, give the underlying type being iterated over a nicer
* name.
*/
typedef typename std::iterator_traits<InputIterator>::value_type ElemType;
/* Initially, assume that the maximum value found so far is zero, since in
* the worst-case we can just take nothing.
*/
ElemType result(0);
/* The value of the maximum-weight subarray ending just before the current
* iterator, which corresponds to F(0) initially (with value zero).
*/
ElemType endingValue(0);
/* Scan across the elements, computing the maximum-weight subarray ending at
* each point. At every point, update our resulting maximum value based on
* what we've found so far.
*/
for (; begin != end; ++begin) {
/* Update the value of the subarray ending at this element according to the
* above recurrence relation.
*/
endingValue = std::max(ElemType(0), endingValue + *begin);
/* Update the global maximum value based on this candidate answer. */
result = std::max(result, endingValue);
}
return result;
}
#endif