You are on page 1of 17

Chapter 4

Divide and conquer

Three steps discussed earlier

(1) Divide
(2) Conquer
(3) Combine

When the subproblem is large enough to solve recursively it is called the recursive case.

Once the subproblems become small enough that we no longer recurse, we say that the recursion
“bottoms out” and we have gotten down to the base case.

Some times there are additional subproblems that are not just smaller instances of the original
problem. Solving these subproblems are considered to be a part of the combine step.

Recurrences

Recurrences give a natural way to characterize the run time of divide and conquer algorithms.

A recurrence is an equation or inequality that describes a function in terms of its value on smaller
inputs

Example: T (n) is the worst-case running time of MERGE_SORT

Whose solution was found using a recursive tree to be Θ(n lg n)

Three methods to solve recurrences are discussed –

(1) Substitution method – we guess a bound and use mathematical induction to prove it is
correct
(2) Recursion tree method – converts the recurrence into a tree where each node represents
the cost incurred at various levels of the recursion.
(3) Master method – provides bounds for recurrences of the form T ( n )=aT ( n/b ) + f (n),
where a ≥ 1 ,b ≥ 1

A recurrence of the form of the equation above characterises a divide and conquer algorithm that
creates a number of subproblems, of 1/b the size of the original problem.

Sometimes recurrences are given as inequalities, in such cases we find the solution using Ο –
notation or Ω – notation, depending on the inequality sign.

Technicalities in recurrences

Certain technical details are neglected when recurrences are solved.

Ex: if MERGE_SORT is called for n elements where n is odd, the size of the subproblems are ceil( n /2)
and floor(n /2). Neither size is n /2 since it is not an integer when n is odd.
So, the real recurrence is

T ( n )=Θ(1) for sufficiently small n


For convenience, statements on the boundary conditions of recurrence are omitted and the value of
T (n) is assumed to be constant for small n
The recurrence for MERGE_SORT is mostly stated as

T ( n )=2 T ( n/2 ) +Θ(n)


Without explicitly giving value for small n

This is because although changing T (1) changes the exact solution, it does not affect the order of
growth.

So, in solving recurrences floors, ceiling and boundary conditions are mostly ignored.

Whether this is okay is determined later.

The maximum subarray problem

Problem

You have an opportunity to invest in Volatile Chemical Corporation. You can only buy one unit of
stock at one time and sell it at a later date. Buying and selling can take place after the end of trading
for that day. The stock prices for the entire timeline from first to last day is known.

Goal: maximize profits.

Incorrect strategies

1: buy at lowest possible price sell at highest possible price – not always possible as can be seen in
above example. Date of highest price before date of lowest price.

2: find the lowest possible price, then work through the right to find the highest later price. Find the
highest price, work through the left to find lowest prior price. Compare profits for both cases.
Not always accurate. Counter example below:

Brute force solution

Try every pair of buy and sell dates in which buy date lies before sell date.

For n days there are (n2 ) such pairs of dates. (n2 ) is Θ(n )
2

Best case if we can evaluate all pairs of dates in constant time so,

This approach would take Ω(n2)

A transformation – look at the problem in a different way.

We need to find the sequence of days where the net change in stock price between first and last day
is max.

So, instead of looking at daily prices, look at change in prices. Such that,

change on day i= price ( i )− price(i−1)


Change in price on day i, for each day can be taken as an array.

We now need to a non-empty, contiguous subarray of A whose values have largest sum.

This is the maximum subarray problem.

However, we still need to check (n−1


2 )
2
=Θ(n ) subarrays for a period on n days.

Though, computing the cost of one subarray ∝ length of subarray,


Computation can be arranged such that each subarray takes Ο(1) time.

Ex: computing all the subarrays starting at one index, then next and so on.

For any one index, first itself, then itself + next, then further add next and so on till end.

Solution using divide and conquer

Divide and conquer suggests that the array be divided into two subarrays as equal as possible.

A[low .. high ] is divided into two subarrays A[low .. mid ] and A[mid +1 ..high]
Any contiguous subarray A[i.. j] of A[low .. high] will lie

1. Entirely in subarray A[low .. mid ]; low ≤ i≤ j ≤ mid


2. Entirely in subarray A[mid +1 ..high]; mid <i≤ j ≤ high
3. Crossing the midpoint; low ≤ i≤ mid < j ≤ high
Thus, max subarray of A[low .. high] lies in one of these three places

So, the max subarray of A[low .. high] is the subarray lying in region 1,2 or 3 with the greatest sum.

Maximum subarrays of A[low .. mid ] and A[mid +1. . high] are found recursively.

Finding the maximum subarray crossing the midpoint is not a smaller instance of original problem. It
is a different problem as there is the added restriction that it must cross the midpoint.

This subarray of region 3 is itself made up of two subarrays

A [ i.. mid ] ∧A [mid +1.. j]; low ≤ i≤ mid < j< high
so, we need to find the 2 maximum subarrays of the above form and combine them to get max
subarray of region 3.

The maximum of the maximum subarrays found in 1,2 and 3 is the solution.

Complexity:

Each iteration of the for loop


take Θ(1)

iterations in first loop:


mid−low +1

iterations in second loop:


high−mid
Total iterations:

high−low +1=n
So, Θ(n)

Line 1: base case – subarray with just one element

Analysing divide and conquer algorithm

Assumption: n is the power of 2

Base case: n=1

Line 1 and 2: constant time

So T ( 1 )=Θ (1)

Recursive case: n>1

Line 1 and 3: constant

Line 4 and 5: T (n/2) each

Line 6: already seen that it is Θ(n)

Line 7 – 11: Θ(1)

T ( n )=Θ (1 )+2 T ( n / 2 )+Θ ( n ) +Θ(1)


¿ 2 T ( n/2 ) +Θ(n)
Combining base case and recursive case

Kadane’s algorithm for maximum contiguous subarray

Start at the left end progress to the right, while keeping track of the maximum subarray seen so far.

Maximum subarray of A[1. . j+ 1] is either the maximum subarray of A[1. . j] or maximum


subarray of A [ 1.. j ] + A [ j+1]

Pseudocode:

Strassen’s method for matrix multiplication

Normal method

let A=(a ij ) and B=(bij ) be two n × n matrices

if C= A ⋅ B

then,
k=n
c ij =∑ aik b kj
k=1

We need to compute n2 matrix entries each of which is the sum of n elements


Complexity

Each of the for loops run n times

Statement 7 takes Θ(1) time

So, the procedure takes Θ(n3 ) time

Simple divide and conquer algorithm

Assumption: n is to the power of 2 in each of the n × nmatrix

The matrices A and B will be divided into 4 n /2 ×n /2 matrices.

Suppose A , B and C are partitioned into four n /2 ×n /2

A 11 A 12 B11 B 12 C11 C 12
A=
( A 21 A 22 )
, B=
( B21 B 22 )
, (
C=
C21 C 22 ) …( 4.9)

C= A ⋅ B can be written as
C 11 C12 A A 12 B 11 B12
( C 21 C22 )(
= 11 ⋅
)(
A 21 A 22 B21 B22 )
Which corresponds to 4 equations

C 11= A11 ⋅ B11 + A 12 ⋅ B21

C 12=A 11 ⋅B 12+ A12 ⋅B22

C 21=A 21 ⋅ B11 + A22 ⋅B 21

C 11= A 21 ⋅B 12+ A22 ⋅B 22

Each of these equations specify 2 matrix multiplications of the n /2 ×n /2 matrices and 2 additions.

The multiplications can be solved recursively in divide and conquer.


How to partition A , B and C ? In line 5

If we create 12 new n /2 ×n /2 matrices, Θ(n 2) time would be spent copying values

Partitioning can be done without copying entries. We can use index calculations.

The submatrix is identified by a range of row and column indices of the original matrix. Then line 5
only take Θ(1) time.

This representation is slightly different, but it is glossed over for simplicity.

Running time:

Base case: n=1

Line 4: just one scalar multiplication so T ( 1 )=Θ (1)

Recursive case: n>1

Line 5: Θ(1) time using index calculations, Θ(n 2) if copied onto new matrix

Line 6-9: 8 recursive calls. 8 T (n/2), also 4 matrix additions which takes Θ(n 2) time

So,

T ( n )=Θ (1 )+ 8T ( n/2 ) +Θ ( n2 )=8 T ( n/2 )+ Θ(n2 )


If we would have copied the matrix instead of index partitioning, the recurrence would stay the
same
The solution to the recurrence is T ( n )=Θ(n3 )

Strassen’s method

This method makes the recursive tree a little less bushy, so instead of 8 recursive multiplications of
n /2 ×n /2 matrices there are only 7.
Cost of removing 1 recursive multiplication results in several new additions of n /2 ×n /2 matrices.
But it will still be a constant number of additions and will be subsumed by the Θ notation,

Additions of n2 / 4 elements each took Θ(n 2 /4) time which was subsumed to Θ(n 2) time. The
notation subsumes the factor.

Steps: (this method is not obvious)

1. Divide the input matrices A , B and output matrix C into n /2 ×n /2 submatrices. This takes
constant time using index calculations.
2. Create 10 matrices S1 , S 2 , S 3 … S 10 each of which is n /2 ×n /2 submatrices, and should be
the sum or difference of 2 matrices created in step 1. This takes Θ(n 2) time.
3. Using the submatrices created in step 1 and step 2 recursively compute 7 matrix products
P1 , P2 , P 3 … P7. Each Pi is an n /2 ×n /2 matrix.
4. Compute desired submatrices C 11 ,C 12 , C 21 , C22 of the result matrix C by adding or
subtracting various combinations of the Pi matrices. We can compute all 4 in Θ(n 2) time.

Recurrence equation

Base case: T ( 1 )=Θ (1) as before. Only a scalar multiplication which take constant time.

Recursive case: step 1,2,4 takeΘ(n 2) time. Step 3 performs seven multiplications of n /2 ×n /2
matrices. So,

One matrix multiplication was traded off for a constant number of matrix additions.

This leads to a lower asymptotic running time.

The steps

The 10 submatrices created in step 2 are


Since we need to add or subtract 10 n /2 ×n /2matrices, this takes Θ(n 2) time

In step 3, we recursively multiply n /2 ×n /2 matrices 7 times to compute the following n /2 ×n /2


matrices

The RHS just shows what the products are equal too. Only the middle operations are performed
recursively

Step 4 constructs the results as follows

(1)

Expanding shows that it is right


(2)

(3)

(4)

The substitution method for solving recurrences

https://brilliant.org/wiki/the-substitution-method-for-solving-recurrences/

Substitution method comprises two steps –

1. Guess the form of the solution


2. Use mathematical induction to find the constants and prove that the solution works.
Substitution method can be used to establish an upper or lower bound on the recurrence

After guessing the form of the solution:

1. Assume that the hypothesis is true for m<n


2. Use this assumption to prove the hypothesis is true for n
3. Prove true for base case

Example:

for recurrence T ( n )=2 T ( [ n/2 ] ) +n

prove T ( n )=Ο(n lg n)

Hypothesis: for some n> n0, T ( n ) ≤ c nlg n , where c is a constant


Proof:

Assume that the hypothesis is true for m<n

For m=[n/2]

T ( [ n /2 ] ) ≤ c [ n /2 ] lg( [ n/2 ] )

⇒ 2 T ( [ n /2 ] ) +n ≤ 2 c [ n/2 ] lg ( [ n/2 ] ) +n

This is used to prove the hypothesis for n

T ( n )=2 T ( [ n/2 ] ) +n ≤ 2c [ n/2 ] lg ( [ n/2 ] ) +n

≤ c n lg ( n2 )+ n=c n lg n−c nlg 2+n


¿ c n lgn−c n+ n
c n lg n−c n+n<c n lgn , for c >1
Using this we get

T ( n ) ≤ c nlg n , for c>1


Hence the hypothesis is proved, as long as c >1

Now prove the base case:

T ( 1 )=1
c ( 1 ) lg 1=0<T (1)
So not true for T ( 1 )

T ( 2 ) =2 ( 1 ) +2=4< c ( 2 ) lg ( 2 )=2c , for c ≥ 2


So, it is proved that T ( n )=Ο(n lg n)

As T ( n ) ≥ c nlg n where c ≥2 and n0 >1 which is definition for O notation

Sometimes for a correct asymptotic bound, the math fails to work out.
Frequently this is because the inductive hypothesis is not strong enough

This can be overcome by changing the guess by subtracting a lower order term from it

Wrong proof for T ( n )=O(n) for the example above

Change variable to get an easier recurrence.

Example: pg. 87

The recursion tree method for solving recurrences

 In a recursion tree, each node represents the cost of a single subproblem somewhere in the
set of recursive function invocations.
 We sum the costs within each level of the tree to obtain a set of per-level costs,
 then we sum all the per-level costs to determine the total cost of all levels of the recursion.

A recursion tree is best used to generate a good guess, which you can then verify by the substitution
method.
It’s okay to be sloppy since we will verify our guess later.
 Like assuming n is the power of something
 Ignoring floors and ceilings

For example:

Try to find a good guess for the solution of recurrence –

Start by finding upper bound

Since floors and ceiling usually do not matter


Recursion tree can be created for T ( n )=3 T ( n /4 ) +c n2 instead example of sloppiness
We assume that n is an exact power of 4 example of sloppiness

Recursion tree is drawn below

Root – cost incurred at top level recursion

Children – cost of the subproblems of size n /4


Because subproblem sizes decrease by a factor of 4 each time we go down one level, we eventually
must reach a boundary condition.
At a depth i the sub problem size ¿ n /4i

The boundary is when the subproblem size hits 1, so i=log 4 n

The tree has log 4 n+1 levels

Next determine cost at every level

no . of nodes at depthi=3 i
2
cost of node at depth i=c ( n/ 4i )
cost at every level=no . of nodes at level × cost of each node at that level
2
¿ 3i c ( n/4 i ) =( 3/16 )i c n2
At the bottom level

no . of nodes=3log n =nlog 3
4 4

cost of each node=T (1)

cost of level=nlog 3 T ( 1 )=Θ(n log 3 )


4 4

Cost at every level is added up

To make it less messy, we can use an infinite decreasing geometric series as upper bound
( sloppy)
So instead we have

Thus, the guess T ( n )=Ο(n2 )

For the recurrence

If T ( n )=Ο(n2 ) is really the upper bound, then Ω( n2) is the lower bound
Why? Because the first recursive call contributes a cost of Θ ( n2 ) , so Ω(n2) must be a lower bound
for the recurrence.

This can be verified using substitution method

We want to show that T ( n ) ≤ d n2, for some constant d >0 using the same constant c >0 as before,

Hence proved

Example:

Again, the ceiling and the floor functions are omitted

As before, we let c represent the constant factor in the Ο(n) term

On adding values at every level of the recursion tree we get c n for every level

The longest simple path from the root to the leaf is

n →(2/3)n→ ( 2/3 )2 n→ … →1

( 2/3 )k n=1
⇒ k=log3 / 2 n

The cost is at most ¿ no . of levels ×the cost of each level=Ο ( c n log 3/ 2 n ) =Ο(n lg n)

Not every level in the tree contributes cn

Moreover, as we go down from the root, more and more internal nodes are absent.
Consequently, levels toward the bottom of the recursion tree contributes less than c n to the total
cost.
But we are just trying to come up with a guess to verify in the substitution method, so its okay.

Substitution method to verify that T ( n )=Ο(n lg n)

We show that T ( n )< d n lg n, where d is a suitable positive constant


The master theorem

Lots of examples in pg. 95 and 96 of book

You might also like