You are on page 1of 9

COMP2119B Introduction to Data Structures and Algorithms

Assignment 1 — Recursion, Mathematical Induction, and Algorithm


Analysis
Due Date: Sept 27, 2022 5:00pm

Part A
Please only submit give your responses to the questions in this part.

Question 1 Recurrence Equations [25%]


Solve the Θ bound for each recurrence of the following recurrence formulae.

1. T (n) = T (n − 2) + n; T (0) = T (1) = 0


√ k
2. T (n) = T ( n) + 2; T (1) = T (2) = 0 (You may assume that n = 22 where k is a power
of 2.)

3. T (n) = 5T (n/5) + n/5; T (1) = 0 (You may assume that n is a power of 5.)

4. T (n) = T (n − 1) + log2 n; T (1) = 0

5. T (n) = T ( 2n 3n
5 ) + T ( 5 ) + n; T (n) = 0 if n ≤ 1

Solution: (5% each)

1. 2 points will be reduced if only one case is considered.


(1) n is even number and n >= 0:
T (n) = T (n − 2) + n
= T (n − 4) + (n − 2) + n
= T (n − 6) + (n − 4) + (n − 2) + n
= 0 + 2 + ... + (n − 4) + (n − 2) + n
n(n + 2)
= → Θ(n2 )
4
(2) n is odd number and n >= 0:
T (n) = T (n − 2) + n
= T (n − 4) + (n − 2) + n
= T (n − 6) + (n − 4) + (n − 2) + n
= 0 + 3 + ... + (n − 4) + (n − 2) + n
(n + 1)2
= − 1 → Θ(n2 )
4
Therefore, the Θ bound is Θ(n2 ).

1

2. T (n) = T ( n) + 2
1
= T (n 2 ) + 2
1
= T (n 22 ) + 2 ∗ 2
1
= T (n 23 ) + 2 ∗ 3
1 k
= T (n 2k ) + 2 ∗ k (Assume that n = 22 )
1
= T (n 2log2 log2 n ) + 2 ∗ (log2 log2 n)
= T (2) + 2 ∗ (log2 log2 n)
= 0 + 2 ∗ (log2 log2 n) → Θ(log log n)
n n
3. T (n) = 5T ( ) +
5 5
n n n
= 5[5T ( 2 ) + 2 ] +
5 5 5
2 n n
= 5 T( 2) + ∗ 2
5 5
2 n n n
= 5 [5T ( 3 ) + 3 ] + ∗ 2
5 5 5
3 n n
= 5 T( 3) + ∗ 3
5 5
n n
= 5 T ( k ) + ∗ k (Assume that n = 5k )
k
5 5
log5 n n n
=5 T ( log n ) + ∗ log5 n
5 5 5
log5 n n
=5 T (1) + ∗ log5 n
5
n
= ∗ log5 n → Θ(n log n)
5
4. T (n) = T (n − 1) + log2 n
= [T (n − 2) + log2 (n − 1)] + log2 n
= [T (n − 3) + log2 (n − 2)] + log2 (n − 1) + log2 n
= T (n − 3) + log2 (n − 2) + log2 (n − 1) + log2 n
= log2 1 + log2 2 + ... + log2 (n − 2) + log2 (n − 1) + log2 n
= log2 n! → Θ(n log n)

Proof of log2 n! → Θ(n log n): Since it is obvious that nn >= n!. We can see that n! = 1∗2∗
..∗(n/2)∗(n/2+1)∗...∗n >= (n/2)∗(n/2+1)∗...∗n >= (n/2)∗(n/2)∗...∗(n/2) = (n/2)n/2 ).
So log nn >= log n! >= log((n/2)n/2 ), we have n log n >= log n! >= (n/2) log(n/2).
2n 3n
5. T (n) = T ( ) + T ( ) + n ( level 1 in Figure 1)
5 5
2 2 6n 6n 3 2
= T (n ∗ ( ) ) + T ( ) + T ( ) + T (n ∗ ( ) ) + n ∗ 2
5 25 25 5
n n n n
= T( 2) + T( 5 5 ) + T( 5 5 ) + T( 5 2) + n ∗ 2 (level 2 in Figure 1)
5
(2) ( 2 ) ∗ ( 3 ) ( 3 ) ∗ ( 2 ) (3)
= ...
We can expand the recurrence equation as Figure 1. More details of the recursion tree
can be found at chapter 2 and chapter 4 in “Introduction to Algorithms” by Leiserson,
Cormen, Rivest and Stein, MIT press.
By observation, each T (n) can split into two new T (n)s plus a single n according to the
recurrence equation. In the last level of the recursion tree where all T (n) = T (1) = 0, we

2
Figure 1: Recursion Tree

can see the equation is only related to the n part. It is easy to find that, at each level, the
term that only contain n is n*(the current level). Assume k is the total number of levels
of the recursion tree, then Θ bound of T (n) is Θ(nk)
n k
At the k-th level, the left-most T ( k) has the biggest denominator ( 25 ) than any other
( 52 )
term relates to T (n). So it will be reach to T (1) earlier than other terms. Similarity, the
right-most T is T ( 5n k ) has smallest denominator and will be the last one to reach T (1).
(3)
k k
The middle T s have denominators between ( 35 ) and ( 52 ) .
n
So the final level k will be larger than the level when the left-most T ( k) = T (1).
( 52 )
n
Similarly, k will be smaller than or equals to the level when the right-most T( 5 k) = T (1).
(3)
Then, we obtain ⌊log 5 n⌋ ≤ k ≤ ⌈log 5 n⌉. The lower Θ bound is Θ(n ∗ log 5 n) when
2 3 2
k = ⌊log 5 n⌋, and upper Θ bound is Θ(n ∗ log 5 n) when k = ⌈log 5 n⌉.
2 3 3

Therefore, the Θ bound is Θ(n log n).

Question 2 Recursive Algorithms [30%]

1. You are given c identical mooncakes and p identical plates. Fill in the details in the
following pseudo-code of a function S (indicated by the dotted line). The function S(c,
p) computes the number of possible ways of distributing c mooncakes among p plates.

S(c, p):
if p == 1 or c == 0:
return 1
if p > c :
return S(c, c);
return ______________________

3
2. Take a look at these two Python functions, funcA and funcB. The parameters for the
function funcA are e, a list of strings, and lst, a list of lists of strings. A list of lists of
strings lst is the only parameter required by the other function, funcB.

1 def funcA(e: list, lst: list) -> list:


2 if lst == []:
3 return []
4 else:
5 return [e + lst[0]] + funcA(e, lst[1:])
6

7 def funcB(lst: list) -> list:


8 if len(lst) < 2:
9 return []
10 else:
11 return funcB(lst[1:]) + funcA(lst[0], lst[1:])

(a) What is the output of print(funcA([‘x’], [[‘b’], [‘c’], [‘d’, ‘e’]]))?


(b) What is the output of print(funcB([[‘a’], [‘b’], [‘c’], [‘d’, ‘e’]]))?
(c) Explain what functions funcA and funcB do.
(d) Let n be the length of lst in funcA and T (n) be the number of “+” (list concatena-
tion) operations executed in line 5. Give the recurrence equation for T (n) and solve
the recurrence.
(e) Let n be the length of lst in funcB and S(n) be the number of “+” (list concatena-
tion) operations executed in line 11. Give the recurrence equation for S(n) in terms
of S and T . Solve the recurrence.

Solution:

1. (5%) return S(c, p-1)+S(c-p , p)

2. (a) (3%) [[‘x’, ‘b’], [‘x’, ‘c’], [‘x’, ‘d’, ‘e’]]


(b) (3%) [[‘c’, ‘d’, ‘e’], [‘b’, ‘c’], [‘b’, ‘d’, ‘e’], [‘a’, ‘b’], [‘a’, ‘c’], [‘a’, ‘d’, ‘e’]]
(c) (5%) funcA concatenates list e to the front of all the list elements in lst; funcB
returns all combinations of each two lists from the list lst.
(d) (7%) T (n) = T (n − 1) + 2; T (0) = 0
Solving the recurrence, we get T (n) = 2n.
(e) (7%) We can formulate the recurrence equation:
S(n) = S(n − 1) + T (n − 1) + 1; S(0) = S(1) = 0.
According to (c), we obtain S(n) = S(n − 1) + 2(n − 1) + 1; S(0) = S(1) = 0.
The S(n − 1) term corresponds to calling the statement funcB(lst[:-1]), and the
term T (n − 1) corresponds to funcA(lst[:-1]).
S(n) = S(n − 1) + T (n − 1) + 1
= S(n − 1) + 2(n − 1) + 1
= (S(n − 2) + 2(n − 2) + 1) + 2(n − 1) + 1
= S(n − 2) + 2((n − 2) + (n − 1)) + 1 ∗ 2
= (S(n − 3) + 2(n − 3) + 1) + 2((n − 2) + (n − 1)) + 1 ∗ 2
= S(n − 3) + 2((n − 3) + (n − 2) + (n − 1)) + 1 ∗ 3
= n2 − 1

4
Question 3 Mathematical Induction [20%]
Prove the following equations with mathematical induction.

1. 1 ∗ 11 + 3 ∗ 17 + 5 ∗ 23 + ... + (2n − 1)(6n + 5) = 4n3 + 8n2 − n for all positive integers n


2∗2−1 3∗3−2 4∗4−3 (n+1)∗(n+1)−n 1
2. 1∗2 + 2∗3 + 3∗4 + ... + n(n+1) =n+1− n+1 for all positive integers n

Solution: (10% each)

1. [Base Case] When n = 1, l.h.s. = 1 ∗ 11 = 4 ∗ 13 + 8 ∗ 12 − 1 = r.h.s.


[Inductive Step] Suppose n = k holds, i.e. 1 ∗ 11 + 3 ∗ 17 + 5 ∗ 23 + ... + (2k − 1)(6k + 5) =
4k 3 + 8k 2 − k; then when n = k + 1,
l.h.s. = 1 ∗ 11 + 3 ∗ 17 + 5 ∗ 23 + ... + (2k − 1)(6k + 5) + (2(k + 1) − 1)(6(k + 1) + 5)
= 4k 3 + 8k 2 − k + (2k + 1)(6k + 11)
= 4k 3 + 20k 2 + 27k + 11
= 4(k + 1)3 + 8(k + 1)2 − (k + 1)
= r.h.s.
By mathematical induction, we showed that 1 ∗ 11 + 3 ∗ 17 + 5 ∗ 23 + ... + (2n − 1)(6n + 5) =
4n3 + 8n2 − n for all positive integers n.
2∗2−1 3 1
2. [Base Case] When n = 1, l.h.s. = 1∗2 = 2 =1+1− 1+1 = r.h.s.
2∗2−1 3∗3−2 4∗4−3 (k+1)∗(k+1)−k
[Inductive Step] Suppose n = k holds, i.e. 1∗2 + 2∗3 + 3∗4 + ... + k(k+1) =
1
k + 1 − k+1 ; then when n = k + 1,

2∗2−1 3∗3−2 4∗4−3 (k + 1) ∗ (k + 1) − k (k + 2) ∗ (k + 2) − (k + 1)


l.h.s. = + + + ... + +
1∗2 2∗3 3∗4 k(k + 1) (k + 1)(k + 2)
1 (k + 2) ∗ (k + 2) − (k + 1)
=k+1− +
k+1 (k + 1)(k + 2)
1
=k+2−
k+2
= r.h.s.

Question 4 Big-Theta Notation [10%]


Prove or disprove the following statement using the definition of Θ:

f (n) = ( n2 + 2 n + log2 n)2 is Θ(n2 )
√ 2
Solution: Since ∀n ≥ 64 : 0 ≤ log2 n ≤ 2 n ≤ n4 , we have ∀n ≥ 64 : n4 = ( n2 + 0 +
0)2 ≤ f (n) ≤ ( n2 + n4 + n4 )2 = n2 . Therefore, we pick n0 = 64, c1 = 41 , c2 = 1 such that
∀n ≥ n0 : c1 · n2 ≤ f (n) ≤ c2 · n2 . Hence f (n) is Θ(n2 ).

Question 5 Algorithm Design [15%]


Consider a 2D space in which an object is initially located at the origin O(0, 0) and is moving
towards a destination location D. The object moves in steps with the following rules.

1. In each step, the object can either move 1 or 2 units along either axis.

2. The object cannot make two consecutive moves each by 2 units.

3. The object cannot move backward. That is, it must make progress either along the x-axis
or the y-axis towards the destination D in each step and it cannot regress towards O.

5
Design a recursive algorithm calculate route that takes the destination coordinates D(x, y)
(x, y are non-negative integers and O ̸= D) as input and outputs the number of distinct routes
from O to D. For example, if the input coordinates are D(2, 2), your algorithm should
return 12 because there are 12 possible routes from O to D:
(0, 0) → (0, 1) → (0, 2) → (2, 2)
(0, 0) → (0, 1) → (0, 2) → (1, 2) → (2, 2)
(0, 0) → (0, 1) → (1, 1) → (1, 2) → (2, 2)
(0, 0) → (0, 1) → (1, 1) → (2, 1) → (2, 2)
(0, 0) → (0, 1) → (2, 1) → (2, 2)
(0, 0) → (1, 0) → (2, 0) → (2, 2)
(0, 0) → (1, 0) → (2, 0) → (2, 1) → (2, 2)
(0, 0) → (1, 0) → (1, 1) → (2, 1) → (2, 2)
(0, 0) → (1, 0) → (1, 1) → (1, 2) → (2, 2)
(0, 0) → (1, 0) → (1, 2) → (2, 2)
(0, 0) → (0, 2) → (1, 2) → (2, 2)
(0, 0) → (0, 2) → (2, 2) (Exclude due to violation of Rule 2)
(0, 0) → (2, 0) → (2, 1) → (2, 2)
(0, 0) → (2, 0) → (2, 2) (Exclude due to violation of Rule 2)

Give the pseudocode for calculate route(x, y, z), where z can be utilized to indicate
whether a 2-unit move is carried out in a previous step.
You should verbally explain your idea and make your algorithm clear and understandable.
Solution: See Algorithm 1.

Algorithm 1 calculate route(x,y,z)


if x == 0 and y == 0 then ▷ Base case
return 1
else if x < 0 or y < 0 then ▷ Impermissble move
return 0
else
if z == 0 then
return calculate route(x-1,y,0) + calculate route(x-2,y,1) +
calculate route(x,y-1,0) + calculate route(x,y-2,1)
else
return calculate route(x-1,y,0) + calculate route(x,y-1,0)
end if
end if

Part B
For your practice only. Do NOT submit your answer to this part.

1. Solve the following recurrence formulae and give a Θ bound for each of the recurrences.

(a) T (n) = 4T (n/4) + 1; T (1) = 0


(b) T (n) = 4T (n/2) + 1; T (1) = 0

2. Show that, if a is a positive real number, then g(n) = 1 + a + a2 + ... + an is:

(a) Θ(1) if a < 1

6
(b) Θ(n) if a = 1
(c) Θ(an ) if a > 1

3. What is the output of the following Python code?

def test(i,j):
if i==0: return j
else: return test(i-1,i+j)

print (test(4,7))

4. The following pseudocode calculates the greatest common divisor of two positive integers
a and b. Use M.I. to prove the correctness the gcd function.

gcd(a, b):
if b == 0:
return a
else:
return gcd(b, a mod b)

5. Is there a faster way to compute the n-th Fibonacci number than by the iterative algorithm
(Chapter 2, slide p.91)? One idea involves matrices. We start by writing the equations
F1 = F1 and F2 = F0 + F1 in matrix notation:
    
F1 0 1 F0
=
F2 1 1 F1

Similarly,
      2  
F2 0 1 F1 0 1 F0
= =
F3 1 1 F2 1 1 F1

In general,    n  
Fn 0 1 F0
=
Fn+1 1 1 F1
So, in order to compute Fn , it suffices to raise this 2 × 2 matrix, call it X, to the n-th
power.

(a) Show that two 2 × 2 matrices can be multiplied using 4 additions and 8 multiplica-
tions.

But how many matrix multiplications does it take to compute X n ?

(b) Show that O(log n) matrix multiplications suffice for computing X n . (Hint: Think
about computing X 8 .)

Thus the number of arithmetic operations needed by our matrix-based algorithm, is just
O(log n), as compared to O(n) for the iterative method. Have we broken another barrier?

(c) Briefly explain why or why not the new algorithm will be faster than the iterative
algorithm.

7
Solution:

1. (a) T (n) = 4T (n/4) + 1


= 4(4(T (n/42 ) + 1) + 1
= 42 T (n/42 ) + 41 + 40
= 42 (4(T (n/43 ) + 1)) + 41 + 40
= 43 T (n/43 ) + 42 + 41 + 40
= 4log4 n T (1) + 4log4 n−1 + 4log4 n−2 + ... + 41 + 40
1 − 4log4 n
=0+
1−4
n−1
= → Θ(n)
3
(b) T (n) = 4T (n/2) + 1
= 4(4(T (n/22 ) + 1) + 1
= 42 T (n/22 ) + 41 + 40
= 42 (4(T (n/23 ) + 1)) + 41 + 40
= 43 T (n/23 ) + 42 + 41 + 40
= 4log2 n T (1) + 4log2 n−1 + 4log2 n−2 + ... + 41 + 40
1 − 4log2 n
=0+
1−4
n2 − 1
= → Θ(n2 )
3
n n
2. (a) Since 0 < a < 1, we have g(n) = 1 + a(1−a )
1−a . Also,
a(1−a )
1−a
a
≤ 1−a . Therefore, we
a
pick n0 = 0, c1 = 1, c2 = 1 + (1−a) such that ∀n ≥ n0 : c1 · 1 ≤ g(n) ≤ c2 · 1. Hence
g(n) is Θ(1).
(b) Since a = 1, we have g(n) = n + 1. Therefore, we pick n0 = 1, c1 = 1, c2 = 2 such
that ∀n ≥ n0 : c1 · n ≤ g(n) = n + 1 ≤ c2 · n. Hence g(n) is Θ(n).
n
−1
(c) Since a > 1, we have g(n) = aa−1 +an . Therefore, we pick n0 = 1, c1 = 1, c2 = 1
a−1 +1
such that ∀n ≥ n0 : c1 · an ≤ g(n) ≤ c2 · an . Hence g(n) is Θ(an ).

3. 17
The recursive processes are as follows: test(4,7) → test(3,4+7) → test(2,3+11)
→ test(1,2+14) → test(0,1+16) → 17

4. [Base Case]
Case 1: When a = 1 and b = 1, gcd(1,1) = gcd(1,0) = 1. 1 is the greatest common divisor
of 1 and 1.
Case 2: When a = 1 and b > 1, gcd(1,b) = gcd(b,1) = gcd(1,0) = 1. 1 is the greatest
common divisor of 1 and b.
Case 3: When a > 1 and b = 1, gcd(a,1) = gcd(1,0) = 1. 1 is the greatest common divisor
of a and 1.
Case 4: When b = q ∗ a where q > 1 and q is an integer, gcd(a,q*a) = gcd(q*a,a) =
gcd(a,0) = a. a is the greatest common divisor of a and b = q ∗ a.
Case 5: When a = q ∗ b where q > 1 and q is an integer, gcd(q*b,b) = gcd(b,0) = b. b is
the greatest common divisor of a = q ∗ b and b.

8
[Inductive Step] Assume that when a ≤ k and b ≤ k, gcd(a,b) return the greatest common
divisor of a and b. Then we want to prove gcd(a,b) still holds when a ≤ k +1 and b ≤ k +1.
That means we need to prove the extra cases of new range which are gcd(k, k+1), gcd(k+1,
k) and gcd(k+1, k+1) can return the correct answer.
Case 1: We know gcd(a, b) = gcd(b, a mod b), so gcd(k+1, k) = gcd(k, (k+1) mod k).
k ≤ k and (k + 1) mod k ≤ k, so gcd(k+1, k) = gcd(k, (k+1) mod k) returns the greatest
common divisor of k+1 and k.
Case 2: Similarly, k ≤ k and (k + 1) mod k ≤ k, gcd(k, k+1) = gcd(k+1, k mod (k+1))
= gcd(k+1, k) = gcd(k, (k+1) mod k) return the greatest common divisor of k and k+1.
Case 3: gcd(k+1, k+1) = gcd(k+1, 0) = k+1 return the greatest common divisor of k+1
and k+1.
Therefore, we showed by mathematical induction that for any positive integer a and b,
gcd(a,b) return the greatest common divisor of a and b.

5. (a) Refer to slide Chapter 2, p.54.


⌊log n⌋
(b) (Step 1) To compute X n , we first obtain X 1 , X 2 , X 4 , X 8 , X 16 , ...X 2 2 . Obtaining
these matrices involves O(log n) matrix multiplications. (Step 2) To compute X n ,
we get the binary representation of n, and then multiply the corresponding matrices.
For example, we compute X 11 by multiplying X 8 , X 2 and X 1 . Since there are no
more than O(log n) matrices, there will be at most O(log n) matrix multiplications.
Summing up the number of matrix multiplications in Steps 1 and 2 gives O(log n).
(c) Our new algorithm involves multiplication, not just addition; and multiplications of
large numbers are slower than additions.

Submission
Please submit your assignment (one PDF file) to moodle by the deadline. Make sure the
content is readable. Feel free to post your questions on moodle forum, or contact TAs if you
encounter any difficulty in this assignment. We are happy to help.

You might also like