Chapter 4 Divide and Conquer
Chapter 4 Divide and Conquer
Chapter 4 Divide and Conquer
(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
(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
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
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.
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.
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:
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,
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,
We now need to a non-empty, contiguous subarray of A whose values have largest sum.
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.
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
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.
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:
high−low +1=n
So, Θ(n)
So T ( 1 )=Θ (1)
Start at the left end progress to the right, while keeping track of the maximum subarray seen so far.
Pseudocode:
Normal method
if C= A ⋅ B
then,
k=n
c ij =∑ aik b kj
k=1
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
Each of these equations specify 2 matrix multiplications of the n /2 ×n /2 matrices and 2 additions.
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.
Running time:
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,
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.
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.
The steps
The RHS just shows what the products are equal too. Only the middle operations are performed
recursively
(1)
(3)
(4)
https://brilliant.org/wiki/the-substitution-method-for-solving-recurrences/
Example:
prove T ( n )=Ο(n lg 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
T ( 1 )=1
c ( 1 ) lg 1=0<T (1)
So not true for T ( 1 )
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
Example: pg. 87
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:
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
To make it less messy, we can use an infinite decreasing geometric series as upper bound
( sloppy)
So instead we have
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.
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:
On adding values at every level of the recursion tree we get c n for every level
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)
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.