Data Structures, Algorithms, & Applications in C++
Chapter 19, Exercise 23
First let use try the divide-and-conquer method.
We use the term block to denote
a consecutive subset of the xis.
For example,
xj,
xj+1,
...,
xk,
denotes a block.
If n = 1, there is only
one block. This block is the block with maximum sum.
If n > 1, divide the elements into two
groups; one group has ceil(n/2) elements
and the other has the remaining elements. For each group, find the block
with maximum sum recursively.
The block with overall maximum sum is either one of these two blocks or
is a block that spans the two groups.
The maximum sum block that spans the two groups is comprised of two
parts: a max subblock that ends at the right end of the left group
and a max subblock that begins at the left of the right subgroup.
Suppose that the left group ends at xq.
The max subblock that ends at xq
can be found in linear time by computing
the sums s(i) = xi + xi+1 + ... + xq
for i = 0, 1, 2, ..., q, and then taking
the max of these
sums.
The max subblock that begins at xq+1
can be found similarly. The two max sublocks are combined to get the
max subblock that spans the two groups.
To make the analysis easy, assume that n is a power of
2.
Let t(n) denote the time complexity.
We see that t(n) =
2t(n/2)+cn when n >= 2.
This is the same equation as for merge sort.
Therefore,
t(n) = O(n log n).
Next consider a dynamic programming formulation. Let s(i)
be the maximum sum of any block of
xi,
xi+1,
...,
xn.
We see that
s(1) = max{sum(i,j)}.
First we make the following observations
-
s(n) = xn.
-
For
i < n, s(i)
is either the sum of a block that begins with xi
(i.e., s(i) = sum(i,j) for some j >= i),
or
it is the sum of a block that does not include xi (i.e., s(i) = s(i+1)).
These observations lead to
the following dynamic programming recurrence:
(1) s(n) = xn
(2) s(i) = max{maxSum(i), s(i+1)}
where maxSum(i) = max{sum(i,j) | j >= i}.
Equations (1) and (2) yield
(3) s(1) = max{maxSum(i)}
For maxSum(i) make the following observations:
-
maxSum(n) = xn
-
Let
i < n. maxSum(i) =
xi whenever maxSum(i+1) <= 0
and
maxSum(i) =
xi + maxSum(i+1) otherwise.
These observations result in the following dynamic programming recurrence
for maxSum:
(4) maxSum(n) = xn
(5) maxSum(i) = max{xi, xi + maxSum(i+1)}, i < n
We may determine the block with maximum sum as follows:
- Step 1
-
Set
maxSum(n) = xn.
This takes O(1) time.
- Step 2
-
Compute
maxSum(i) for
i = n-1, n-2, ..., 1, in that order,
using Equation (5).
This takes O(n) time.
- Step 3
-
Use Equation (3) to compute
s(1).
This takes O(n) time.
- Step 4
-
The block whose sum equals
s(1) is determined
in the following way. Let k be
such that
s(1) = maxSum(k). The block with
maximum sum begins at xk.
To find the block end, find the least j >= i
such that
sum(k,j)
= maxSum(k).
The time required for this is
O(n).
From the above description and analysis, we see that the overall complexity
is O(n).