Largest Contiguous Sum
CSC 172
SPRING 2002
LECTURE 2
Today’s Agenda
Largest
Sum Problem & Analysis
Linked
Lists
Workshop
Sign up
LAB ASSINGMENTS
Labs
are due at the beginning of the first lab of the
following week
Lab hand ins (hardcopy) will be a “report”
Hand
in to lab TA
Neat, Stapled, Broken into sections
Cover page describing the lab
Listing of required files, properly modified
Example
One
dimensional pattern recognition
Input: a vector x of n floating point numbers
Output: the maximum sum found in any
contiguous subvector of the input.
31 -41 59 26 -53 58 97 -93 -23 84
X[2..6]
or 187
How would you solve this?
Obvious solution
Check all pairs
int sum; int maxsofar = 0;
for (int i = 0; i<x.length;i++)
for (int j = i; j<x.length;j++){
sum = 0;
for (int k = i;k<=j;k++) sum += x[k];
maxsofar = max(sum,maxsofar);
}
How long does the obvious solution
take?
We
could “measure” it – benchmarking
What
is a “good size” of input to measure?
How long does the obvious solution
take?
We
could “analyse” it
Multiply
the “cost” (time required) to do
something by the number of times you have to
do it.
If n is the length of the array
Outer loop runs exactly n times
Inner loop runs at most n times
Inner most loop runs no more than n times
Let’s say the “+=“ and “max” take unit time
How long does the obvious solution
take?
We
call this an “n3” solution
Can you think of a better (faster) way?
Can you do an analysis that will prove it
better?
That
is what we do in CSC 172
For
some very common tasks
A better solution
We
“notice” that the sum x[i..j] is intimately
related to the sum x[i..(j-1)]
Use this fact to prevent taking redundant sums
A better solution
Check all pairs
int sum; int maxsofar = 0;
for (int i = 0; i<x.length;i++)
sum = 0;
for (int j = i; j<x.length;j++){
sum += x[k]; // the sum of x[i..j]
maxsofar = max(sum,maxsofar);
}
How long for the better solution?
Outer
loop runs exactly n times
Inner loop runs at most n times
Let’s say the “+=“ and “max” take unit time
How long for the better solution?
Innerloop
cost = n * 1
Outerloop cost = n * (Innerloop cost)
Outerloop cost = n * ( n * 1)
Outerloop cost = n2 +n
How much better is the “better”
algorithm than the “obvious”?
We
are comparing an n2 to an n3 algorithm
Does
If
efficiency matter?
we wait 18 months, the speed of computers will
double, right?
Time to solve a problem
(400MHz Pent II) Bently, 2000
Size
Obvious 1.3n3 ns
Better 10n2 ns
103
1.3 sec
10 msec
104
22 min
1 sec
105
15 days
1.7 min
106
41 years
2.8 hrs
107
41 millennia
1.7 wks
Max size problem solved
Obvious 1.3n3 ns
Better 10n2 ns
Sec
920
10,000
Min
3600
77,000
Hr
14,000
6.0*105
Day
41,000
2.9*106
Divide & Conquer
To
solve a problem of size n, recursively solve two
sub-problems of size of size n/2, and combine their
solutions to yield a solution to the complete
problem.
D&C for LCS
x
a
b
ma
mb
ma , mb or:
mc
Recursive D&D LCS
public double LCS(double[] x){
return LCS(x,0,x.length-1);
}
Recursive D&C LCS
(proto structure)
public double LCS(double[] x, int lower, int upper){
if (lower>upper) return 0;
if (lower == upper) return max(0,x[lower]);
middle = (upper + lower) /2;
return max(LCS(x,lower,middle),
LCS(x,middle+1,upper));
}// still need to do “mc”
How to find mc?
Note
that mc consists of two parts
The
part starting at the boundary and reaching up
The part ending at the boundary and reaching down
The
sum of these is mc
mc
mclower mcup
Recursive D&D LCS
public double LCS(double[] x, int lower, int upper){
if (lower>upper) return 0;
if (lower == upper) return max(0,x[lower]);
middle = (upper + lower) /2;
double umax = findUmax(x,middle+1,upper);
double lmax = findLmax(x,lower,middle);
return max(LCS(x,lower,middle),
LCS(middle+1,upper),
lmax + umax);
}
findLmax
public double findLmax(double[] x,
int lower,int middle){
double lmax = 0, sum = 0;
for (int j = middle;j>=lower;j--){
sum+=x[j];
lmax = max(lmax,sum);
}
return lmax;
} // Run Time? In terms of middle-lower?
findUmax
public double findLmax(double[] x,
int middle1,int upper){
double umax = 0, sum = 0;
for (int j = middle;j<=upper;j++){
sum+=x[j];
umax = max(lmax,sum);
}
return umax;
} // Run Time? In terms of upper-middle1?
Recursive D&D LCS
public double LCS(double[] x, int lower, int upper){
if (lower>upper) return 0;
if (lower == upper) return max(0,x[lower]);
middle = (upper + lower) /2;
double umax = findUmax(x,middle+1,upper);
double lmax = findLmax(x,lower,middle);
return max(LCS(x,lower,middle),
LCS(x,middle+1,upper),
lmax + umax);
} //Run time of the two calls?
Run Time of D&C LCS
Every
call on a range of n takes
n
to find umax & lmax
2 (recursive) calls of size n/2 each
Formally
TLCS(n) = 2TLCS(n/2)+n
As we will see (later in the course) this solves to
O(n log n)
Time to Solve (Bently)
1.3n3
10n2
47nlog2n
103
1.3 sec
10msec
.4msec
104
22 min
1 sec
6 msec
105
15 days
1.7 min
78 msec
106
41 years
2.8 hours
.94 sec
107
41 millennia
1.7 weeks
11 sec
Max size (Bently)
1.3n3
10n2
47nlog2n
Sec
920
10,000
1.0*106
min
3600
77,000
4.9*107
hr
14,000
6.0*105
2.4*109
day
41,000
2.9*106
5.0*1010
LCS Scanning
A scanning
algorithm starts at the left end x[0] and
proceedes to theright x[n-1] keeping track of the
current result
The key to a scanning algorithm is
Given
that the problem is solved for the x[0..j-1] range
Do some processing at step j that will extend the partial
solution to the x[0..j] range
LCS Scanning
Keep
a record of the “best” and the “current”
If the “current” is better than the “best” then
replace
How do I extend the maxendinghere?
x
maxsofar
0
maxendinghere
j
Extending maxendinghere
We
have up until x[j-1]
Should we include x[j]?
We should if adding x[j] keeps the sum positive
Consider:
if the max ending at x[j] is negative then the
contribution from x[j] and before cannot be of “benefit”
to what comes after
Otherwise,
The
we should reset maxendinghere to zero
empty vector
LCS Scanning
public double LCS(double[] x){
double maxsofar = 0, maxendinghere = 0;
for (int j = 0;j<x.length;j++){
maxendinghere =
max(maxendinghere+x[j],0);
maxsofar = max(maxsofar,maxendinghere);
}
return maxsofar;
} // Run Time?
Time to solve (Bently)
1.3n3
10n2
47nlog2n
48n
103
1.3 sec
10msec
.4msec
0.5 msec
104
22 min
1 sec
6 msec
.5 msec
105
15 days
1.7 min
78 msec
5 msec
106
41 years
2.8 hours
.94 sec
48 msec
107
41 millennia 1.7 weeks
11 sec
.48 sec
Max Problem (Bently)
1.3n3
10n2
47nlog2n
Sec
920
10,000
1.0*106
2.1*107
min
3600
77,000
4.9*107
1.3*109
hr
14,000
6.0*105
2.4*109
7.6*1010
day
41,000
2.9*106
5.0*1010
1.8*1012
48n
Machine Power?
10
Alpha 21164A,
TRS-80, “BASIC”,
“C”, “obvious ald” Linear alg
0.6 microsec
200 millisecs
100
0.6 millisecs
2.0 sec
1000
0.6 sec
20 sec
10,000
10 min
3.2 min
100,000
7 days
32 min
19 years
5.4 hrs
n
1,000,000
Design Principles
Save
state to avoid recomputation
Preprocess into data structures
Divide and conquer
Scanning algorithms
Cumulatives when dealing with ranges
Open problem
Extend
LCS to 2D
Given an nxn array of reals, find the maximum
sum contained in any rectangular sub-array
What is the time complexity?
Further reading
Programming
Pearls by Jon Bently 2nd ed. 2000
© Copyright 2026 Paperzz