4
Divide and Conquer (continued) Example: Integer Multiplication (Karatsuba algorithm) The problem: Let and be two -digit numbers. Compute β‹…. A straightforward algorithm (like what a human does) would require ( 2 ) time to multiply each digit of with each digit of . Let’s try to do divide-and-conquer. Let = 2 . Let =2 β‹… 1 + 2 and =2 β‹… 1 + 2 . Then β‹…=2 2 β‹… 1 1 +2 β‹… ( 1 2 + 2 1 )+ 2 2 So, we have () = 4 β‹… ( 2 ) + (). By Master’s theorem, =4, =2, and =1. So, () = 2 . Disappointing… The trick is to reduce . Notice that ( 1 + 2 )( 1 + 2 )= 1 1 + ( 1 2 + 2 1 )+ 2 2 . Therefore, after computing 1 1 and 2 2 , the value 1 2 + 2 1 can be computed in the following way, 1 2 + 2 1 = ( 1 + 2 )( 1 + 2 )βˆ’ 1 1 βˆ’ 2 2 Thus, only three multiplications are needed. Therefore, () = 3 β‹… ( 2 ) + () Thus, by Master’s theorem, =3, =2, and =1. So, () = log 2 3 < 1.59 . Practical concerns: 1. is odd? 2. What base to use? 3. For small overhead is too high. Better use ( 2 ) method. For > 1000, this method is better. 4. There is an ( log 2 Θ(log βˆ— ) ) method that is asymptotically better but requires very large to be beneficial. Here log βˆ— is the number of times the logarithm function must be iteratively applied before the result is less than or equal to 1.

Divide and Conquer (continued) - cs.uwaterloo.cabinma/cs341/04-05-divide-and-conquer-1.pdfΒ Β· Divide and Conquer (continued) Example: Integer Multiplication (Karatsuba algorithm)

  • Upload
    dongoc

  • View
    219

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Divide and Conquer (continued) - cs.uwaterloo.cabinma/cs341/04-05-divide-and-conquer-1.pdfΒ Β· Divide and Conquer (continued) Example: Integer Multiplication (Karatsuba algorithm)

Divide and Conquer (continued) Example: Integer Multiplication (Karatsuba algorithm) The problem: Let π‘₯ and 𝑦 be two 𝑛-digit numbers. Compute π‘₯ β‹… 𝑦.

A straightforward algorithm (like what a human does) would require 𝑂(𝑛2) time to multiply each digit of

π‘₯ with each digit of 𝑦. Let’s try to do divide-and-conquer.

Let π‘š =𝑛

2. Let π‘₯ = 2π‘š β‹… π‘₯1 + π‘₯2 and 𝑦 = 2π‘š β‹… 𝑦1 + 𝑦2. Then

π‘₯ β‹… 𝑦 = 22π‘š β‹… π‘₯1𝑦1 + 2π‘š β‹… (π‘₯1𝑦2 + π‘₯2𝑦1) + π‘₯2𝑦2

So, we have 𝑇(𝑛) = 4 β‹… 𝑇 (𝑛

2) + 𝑂(𝑛). By Master’s theorem, π‘Ž = 4, 𝑏 = 2, and 𝑐 = 1. So, 𝑇(𝑛) = 𝑛2.

Disappointing…

The trick is to reduce π‘Ž. Notice that (π‘₯1 + π‘₯2)(𝑦1 + 𝑦2) = π‘₯1𝑦1 + (π‘₯1𝑦2 + π‘₯2𝑦1) + π‘₯2𝑦2. Therefore,

after computing π‘₯1𝑦1 and π‘₯2𝑦2, the value π‘₯1𝑦2 + π‘₯2𝑦1 can be computed in the following way,

π‘₯1𝑦2 + π‘₯2𝑦1 = (π‘₯1 + π‘₯2)(𝑦1 + 𝑦2) βˆ’ π‘₯1𝑦1 βˆ’ π‘₯2𝑦2

Thus, only three multiplications are needed. Therefore,

𝑇(𝑛) = 3 β‹… 𝑇 (𝑛

2) + 𝑂(𝑛)

Thus, by Master’s theorem, π‘Ž = 3, 𝑏 = 2, and 𝑐 = 1. So, 𝑇(𝑛) = 𝑛log2 3 < 𝑛1.59.

Practical concerns:

1. 𝑛 is odd?

2. What base to use?

3. For small 𝑛 overhead is too high. Better use 𝑂(𝑛2) method. For 𝑛 > 1000, this method is

better.

4. There is an 𝑂(𝑛 log 𝑛 2Θ(logβˆ— 𝑛)) method that is asymptotically better but requires very large 𝑛

to be beneficial. Here logβˆ— 𝑛 is the number of times the logarithm function must be iteratively

applied before the result is less than or equal to 1.

Page 2: Divide and Conquer (continued) - cs.uwaterloo.cabinma/cs341/04-05-divide-and-conquer-1.pdfΒ Β· Divide and Conquer (continued) Example: Integer Multiplication (Karatsuba algorithm)

Example: Matrix Multiplication (Strassen Algorithm) Let 𝐴 and 𝐡 be two matrices, 𝐢 = 𝐴 Γ— 𝐡, then 𝑐𝑖,𝑗 = βˆ‘ π‘Žπ‘–,π‘˜π‘π‘˜,𝑗

π‘›π‘˜=1 . For brevity we assume each matrix is

𝑛 Γ— 𝑛 matrix. A straightforward algorithm would take 𝑂(𝑛3) time.

Remark: Note that in this case the input size is 𝑛2 but not 𝑛. The time complexity is a parameter related

to the input size.

We can divide each matrix into four blocks as follows:

Each block is a 𝑛

2Γ—

𝑛

2 matrix. Then

But using these straightforwardly will not make things run faster. Instead, Strassen computed seven

other matrices:

Then it can be verified that

Page 3: Divide and Conquer (continued) - cs.uwaterloo.cabinma/cs341/04-05-divide-and-conquer-1.pdfΒ Β· Divide and Conquer (continued) Example: Integer Multiplication (Karatsuba algorithm)

Matrix additions take only 𝑂(𝑛2) time. So, 𝑇(𝑛) = 7𝑇 (𝑛

2) + 𝑂(𝑛2). By using Master’s theorem, the

time complexity is 𝑇(𝑛) = 𝑂(𝑛log2 7) β‰ˆ 𝑂(𝑛2.807).

Nobody knows how Strassen figured out the seven intermediate matrices 𝑀1 to 𝑀7. With the

knowledge of Karatsuba algorithm for integer multiplication, a clever person would think one may be

able to apply the same trick to matrices. The remaining is a strong belief in it and the persistence of

trying out different ways. Be prepared to fail many times before you find the right answer.

Example: Polynomial Multiplication

Given two polynomials 𝑝(π‘₯) = π‘Ž0 + π‘Ž1π‘₯ + π‘Ž2π‘₯2 + β‹― + π‘Žπ‘›π‘₯𝑛 andπ‘ž(π‘₯) = π‘Ž0 + π‘Ž1π‘₯ + π‘Ž2π‘₯2 + β‹― +

π‘Žπ‘›π‘₯𝑛, compute 𝑝(π‘₯) β‹… π‘ž(π‘₯). The divide-and-conquer idea is very similar to the integer multiplication.

Work it out as an exercise.

Example: Counting inversions If you rank 𝑛 movies with order 1, 2, … , 𝑛, and your friend ranks the same movies with order 𝑖1, … , 𝑖𝑛.

The number of pairs of movies that you and your friend rank with different orders is called the

inversions in the permutation 𝑖1, … , 𝑖𝑛. This can be used as a measure of how similar (dissimilar) you and

your friend are. More formally, the number of inversions is |{(𝑖𝑗, π‘–π‘˜): 𝑗 < π‘˜ and 𝑖𝑗 > π‘–π‘˜}|.

Algorithm 1: For every pair of 𝑗 < π‘˜, check if 𝑖𝑗 > π‘–π‘˜ and count. 𝑂(𝑛2).

Algorithm 2: Divide and Conquer.

Divide the array 𝐴[1. . 𝑛] into two halves. Then the number of inversions is equal to the sum of the

number of inversion in the first and second halves, as well as the inversions 𝐴[𝑖] > 𝐴[𝑗] for 𝑖 and 𝑗 in the

first and second halves, respectively. One can check that a straightforward counting of the inversion

across the two halves take 𝑛2

4 comparisons. By Master theorem, this divide-and-conquer ends up with an

𝑂(𝑛2) algorithm. To improve, we have to reduce the time complexity to count the inversions across the

two halves.

An often used technique when dealing with arrays is to check if things become easier if the arrays are

sorted. Consider the situation when 𝐴[1. . 𝑛/2] and 𝐴[𝑛/2 + 1. . 𝑛] are sorted, respectively. If 𝐴[𝑖] >

𝐴[𝑗] for 1 ≀ 𝑖 ≀ 𝑛/2 and 𝑛

2< 𝑗 ≀ 𝑛, then we know that 𝐴[𝑖′] > 𝐴[𝑗] for every 𝑖′ β‰₯ 𝑖. If we count in a

proper way, all these inversions may be counted together in one operation. This saves time.

Let 𝐴 and 𝐡 be two sorted array with sizes π‘š and 𝑛, respectively. We put 𝐴 before 𝐡 and count the

inversions between them. The idea is that we loop through every 𝐡[𝑗] in the second array, and find the

first 𝑖 such that 𝐴[𝑖] > 𝐡[𝑗]. Then we know that 𝐡[𝑗] is involved in precisely π‘š βˆ’ 𝑖 + 1 inversions. We

sum up all the inversions of every 𝐡[𝑗].

CountPairSorted

Page 4: Divide and Conquer (continued) - cs.uwaterloo.cabinma/cs341/04-05-divide-and-conquer-1.pdfΒ Β· Divide and Conquer (continued) Example: Integer Multiplication (Karatsuba algorithm)

Input: Two sorted arrays 𝐴 and B with length π‘š and 𝑛, respectively

Output: the number of inversions when 𝐴 is put before 𝐡.

1. 𝑖 ← 1; π‘˜ ← 0;

2. For 𝑗 from 1 to 𝑛

3. while 𝑖 ≀ π‘š and 𝐴[𝑖] ≀ 𝐡[𝑗]

4. 𝑖++

5. π‘˜ ← π‘˜ + π‘š βˆ’ 𝑖 + 1 6. Return π‘˜

The correctness follows the discussion above the pseudocode.

Time complexity: Note that the condition in line 3 can only be true for at most π‘š times during the whole

algorithm execution. Also, for each 𝑗, the condition in line 3 can be false only once. Therefore, lines 3

and 4 take 𝑂(π‘š + 𝑛) times in total. Line 5 takes 𝑂(1) time for each 𝑗. Therefore, the total time

complexity is 𝑂(π‘š + 𝑛).

Now we can use CountPairSorted as a subroutine for the divide and conquer algorithm.

SortAndCount:

Input: A is a list of 𝑛 elements.

Output: (S, k), where S is sorted, and k is the number of inversions.

1. If 𝑛 ≀ 3 sort and count with a trivial algorithm and return.

2. (𝑆1, π‘˜1) ← SortAndCount (A[1..n/2])

3. (𝑆2, π‘˜2) ← SortAndCount (A[n/2+1..n])

4. π‘˜3 ← CountPairSorted(𝑆1,𝑆2).

5. 𝑆 ← Merge(𝑆1, 𝑆2)

6. Return (𝑆, π‘˜1 + π‘˜2 + π‘˜3).

Proof of correctness. By induction. Base case is straightforward and omitted. Inversions in 𝐴 includes

inversions in the first half, second half, and across the two halves. This is indeed what line 4 of

SortAndCount computes.

Time complexity: 𝑇(𝑛) = 2𝑇 (𝑛

2) + 𝑂(𝑛). Therefore, 𝑇(𝑛) = 𝑂(𝑛 log 𝑛).

Remark: It is possible to combine lines 4 and 5 together into a single MergeAndCount subroutine. This is

perhaps what you will do when you write the program. But since it does not affect the big O complexity,

separating them is easier for our proofs.