Time complexity and recurrence relations Problem 1
1.1
Consider the following function of n n n :
n 2 ∑ i = 0 n 5 ⋅ i n 3 ⋅ 1 n 3 n 2 + 2 n ( Π i = 1 9 i ) ( ∑ i = 0 log 2 ( n ) 2 i ) + 1 7 ln ( n ) − ln ( 1 n ) ln ( 2 n ) 10 n log 2 ( n 7 ) n 4 n n 5 n \begin{aligned}
&n^2 \quad \sum_{i=0}^{n}5\cdot{i} \quad n^3\cdot \sqrt{\frac{1}{n^3}} \quad n^2 + 2^n \quad (\Pi_{i=1}^{9}i) \quad (\sum_{i=0}^{\log_2(n)}2^i) + 1 \quad 7^{\ln{(n)}} \\
&-\ln{(\frac{1}{n})} \quad \ln{(2^n)} \quad 10 \quad n\log_2{(n^7)} \quad \sqrt{n^4} \quad n^n \quad 5n \\
\end{aligned} n 2 i = 0 ∑ n 5 ⋅ i n 3 ⋅ n 3 1 n 2 + 2 n ( Π i = 1 9 i ) ( i = 0 ∑ l o g 2 ( n ) 2 i ) + 1 7 l n ( n ) − ln ( n 1 ) ln ( 2 n ) 10 n log 2 ( n 7 ) n 4 n n 5 n
Group the above functions that have identical growth rate and order these groups on increasing
growth. Hence:
If you place functions f 1 ( n ) f_1(n) f 1 ( n ) and f 2 ( n ) f_2(n) f 2 ( n ) in the same group, then we must have f 1 ( n ) = Θ ( f 2 ( n ) ) f_1(n) = \Theta{(f_2(n))} f 1 ( n ) = Θ ( f 2 ( n )) ;
If you place function f 1 ( n ) f_1(n) f 1 ( n ) in a group ordered before the group in which you place function f 2 ( n ) f_2(n) f 2 ( n ) ,
then we must have f 1 ( n ) = O ( f 2 ( n ) ) ∧ f 1 ( n ) ≠ Ω ( f 2 ( n ) ) f_1(n) = \mathcal{O}{(f_2(n))} \land f_1(n) \neq \Omega{(f_2(n))} f 1 ( n ) = O ( f 2 ( n )) ∧ f 1 ( n ) = Ω ( f 2 ( n )) .
Solution:
Theorem 3.25 states the following:
lim n → ∞ f ( n ) g ( n ) is defined and is { ∞ then f ( n ) = Ω ( g ( n ) ) ; c , with c > 0 a constant then f ( n ) = Θ ( g ( n ) ) ; 0 then f ( n ) = O ( g ( n ) ) ; \lim_{n \to \infty} \frac{f(n)}{g(n)} \space \text{is defined and is} \space
\begin{cases}
\infty & \space \text{then} \space f(n) = \Omega(g(n)); \\
c \text{, with c > 0 a constant} & \space \text{then} \space f(n) = \Theta(g(n)); \\
0 & \space \text{then} \space f(n) = \mathcal{O}(g(n));
\end{cases} n → ∞ lim g ( n ) f ( n ) is defined and is ⎩ ⎨ ⎧ ∞ c , with c > 0 a constant 0 then f ( n ) = Ω ( g ( n )) ; then f ( n ) = Θ ( g ( n )) ; then f ( n ) = O ( g ( n )) ;
The following are the rules of thumb to determine the order of growth of functions:
c ⋅ f ( n ) = Θ ( f ( n ) ) log a ( n ) = Θ ( log b ( n ) ) lim n → ∞ n c n c + d = lim n → ∞ 1 n d = 0 → n c = O ( n c + d ) log 2 ( n ) c = O ( n d ) ∀ c > 0 , d > 0 n c = O ( d n ) ∀ c > 0 , d > 1 d n u = O ( c n v ) ∀ c ≥ d ≥ 1 , u ≥ v ≥ 1 ∑ i = 1 m c i ⋅ n d i = O ( n d i ) f ( n ) + g ( n ) = Θ ( g ( n ) ) h ( n ) ⋅ n ( n ) = O ( h ( n ) ⋅ g ( n ) ) \begin{align}
c \cdot f(n) &= \Theta(f(n)) \\
\log_{a}(n) &= \Theta(\log_{b}(n)) \\
\lim_{n \to \infty} \frac{n^c}{n^{c+d}} &= \lim_{n \to \infty} \frac{1}{n^d} = 0 \rightarrow n^c = \mathcal{O}(n^{c+d}) \\
\log_{2}(n)^c &= \mathcal{O}(n^d) \space \forall c > 0, d > 0 \\
n^c &= \mathcal{O}(d^{n}) \space \forall c > 0, d > 1 \\
d^{\frac{n}{u}} &= \mathcal{O}(c^{\frac{n}{v}}) \space \forall c \geq d \geq 1, u \geq v \geq 1 \\
\sum_{i=1}^{m}{c_{i} \cdot n^{d_i}} &= \mathcal{O}(n^{d_i}) \\
f(n) + g(n) &= \Theta(g(n)) \\
h(n) \cdot n(n) &= \mathcal{O}({h(n) \cdot g(n)})
\end{align} c ⋅ f ( n ) log a ( n ) n → ∞ lim n c + d n c log 2 ( n ) c n c d u n i = 1 ∑ m c i ⋅ n d i f ( n ) + g ( n ) h ( n ) ⋅ n ( n ) = Θ ( f ( n )) = Θ ( log b ( n )) = n → ∞ lim n d 1 = 0 → n c = O ( n c + d ) = O ( n d ) ∀ c > 0 , d > 0 = O ( d n ) ∀ c > 0 , d > 1 = O ( c v n ) ∀ c ≥ d ≥ 1 , u ≥ v ≥ 1 = O ( n d i ) = Θ ( g ( n )) = O ( h ( n ) ⋅ g ( n ) )
Let’s start with analysing the functions that have the same growth rate:
n 2 n^2 n 2 : polynomial growth, n 2 = Θ ( n 2 ) n^2 = \Theta(n^2) n 2 = Θ ( n 2 ) based on rule 3.
∑ i = 0 n 5 ⋅ i \sum_{i=0}^{n}5\cdot{i} ∑ i = 0 n 5 ⋅ i : polynomial growth, ∑ i = 0 n 5 ⋅ i = 5 ⋅ n ( n + 1 ) 2 = 5 2 n 2 + 5 2 n \sum_{i=0}^{n}5\cdot{i} = 5 \cdot \frac{n(n+1)}{2} = \frac{5}{2}n^2 + \frac{5}{2}n ∑ i = 0 n 5 ⋅ i = 5 ⋅ 2 n ( n + 1 ) = 2 5 n 2 + 2 5 n , which is Θ ( n 2 ) \Theta(n^2) Θ ( n 2 ) based on rule 7 7 7 .
n 3 ⋅ 1 n 3 n^3 \cdot \sqrt{\frac{1}{n^3}} n 3 ⋅ n 3 1 : polynomial growth, = n 3 ⋅ 1 n 3 2 → Θ ( n 3 2 ) = n^3 \cdot \frac{1}{n^{\frac{3}{2}}} \rightarrow \Theta(n^{\frac{3}{2}}) = n 3 ⋅ n 2 3 1 → Θ ( n 2 3 ) based on rule 9 , 3 9, 3 9 , 3
n 2 + 2 n n^2 + 2^n n 2 + 2 n : exponential growth, = Θ ( 2 n ) =\Theta(2^n) = Θ ( 2 n ) based on rule 7 7 7
( Π i = 1 9 i ) (\Pi_{i=1}^{9}i) ( Π i = 1 9 i ) : constant, = 1 ⋅ 2 … 9 =1 \cdot 2 \dots 9 = 1 ⋅ 2 … 9 based on rule 9
∑ i = 0 log 2 ( n ) 2 i + 1 \sum_{i=0}^{\log_2{(n)}}{2^i} + 1 ∑ i = 0 l o g 2 ( n ) 2 i + 1 : linear, since the term is a geometrics series, such that ∑ i = 0 log 2 ( n ) 2 i + 1 = 1 ⋅ ( 2 log 2 ( n ) + 1 − 1 ) 2 − 1 + 1 = 2 ⋅ 2 log 2 ( n ) = 2 n \sum_{i=0}^{\log_2{(n)}}{2^i} + 1 = \frac{1 \cdot (2^{\log_2(n)+1}-1)}{2-1} + 1 = 2 \cdot 2^{\log_2(n)} = 2n ∑ i = 0 l o g 2 ( n ) 2 i + 1 = 2 − 1 1 ⋅ ( 2 l o g 2 ( n ) + 1 − 1 ) + 1 = 2 ⋅ 2 l o g 2 ( n ) = 2 n . Therefore based on rule 1 1 1 we have Θ ( n ) \Theta(n) Θ ( n )
7 ln ( n ) 7^{\ln(n)} 7 l n ( n ) : polynomial, since 7 ln ( n ) = n ln ( 7 ) 7^{\ln(n)} = n^{\ln(7)} 7 l n ( n ) = n l n ( 7 ) . Apply rule 3 3 3 we have 7 ln ( n ) = Θ ( n ln 7 ) → O ( n 2 ) 7^{\ln(n)} = \Theta(n^{\ln 7}) \rightarrow \mathcal{O}(n^2) 7 l n ( n ) = Θ ( n l n 7 ) → O ( n 2 )
− ln ( 1 n ) -\ln(\frac{1}{n}) − ln ( n 1 ) : logarithmic, since − ln ( 1 n ) = ln ( n ) -\ln (\frac{1}{n}) = \ln(n) − ln ( n 1 ) = ln ( n ) . Apply rule 1 1 1 yield Θ ( ln n ) \Theta{(\ln{n})} Θ ( ln n ) .
ln ( 2 n ) \ln (2^n) ln ( 2 n ) : linear, since ln ( 2 n ) = n ⋅ ln 2 \ln(2^n) = n \cdot \ln_{2} ln ( 2 n ) = n ⋅ ln 2 and rule 1 1 1 yield Θ ( n ) \Theta{(n)} Θ ( n )
10 10 10 : constant
n log 2 ( n 7 ) n\log_2(n^7) n log 2 ( n 7 ) : polynomial, since n log 2 ( n 7 ) = n ⋅ 7 log 2 ( n ) = 7 n log 2 ( n ) n\log_{2}(n^7) = n \cdot 7\log_{2}{(n)} = 7n\log_{2}(n) n log 2 ( n 7 ) = n ⋅ 7 log 2 ( n ) = 7 n log 2 ( n ) . Based on rule 9 9 9 and 1 1 1 yield O ( n 2 ) \mathcal{O}(n^2) O ( n 2 )
n 4 \sqrt{n^4} n 4 : polynomial growth, = n 2 =n^2 = n 2 based on rule 3.
n n n^n n n : super-exponential.
5 n 5n 5 n : linear based on rule 1, gives Θ ( n ) \Theta(n) Θ ( n )
Thus the order from increasing rate:
10 ( Π i = 1 9 i ) 10 \quad (\Pi_{i=1}^{9}i) 10 ( Π i = 1 9 i ) (constant )
− ln ( 1 n ) -\ln(\frac{1}{n}) − ln ( n 1 ) (logarithmic )
ln ( 2 n ) 5 n ∑ i = 0 log 2 ( n ) 2 i + 1 \ln (2^n) \quad 5n \quad \sum_{i=0}^{\log_2{(n)}}{2^i} + 1 ln ( 2 n ) 5 n ∑ i = 0 l o g 2 ( n ) 2 i + 1 (linear )
n 2 ∑ i = 0 n 5 ⋅ i n 3 ⋅ 1 n 3 n 4 n log 2 ( n 7 ) 7 ln ( n ) n^2 \quad \sum_{i=0}^{n}5\cdot{i} \quad n^3 \cdot \sqrt{\frac{1}{n^3}} \quad \sqrt{n^4} \quad n\log_2(n^7) \quad 7^{\ln(n)} n 2 ∑ i = 0 n 5 ⋅ i n 3 ⋅ n 3 1 n 4 n log 2 ( n 7 ) 7 l n ( n ) (polynomial )
n 2 + 2 n n^2 + 2^n n 2 + 2 n (exponential )
n n n^n n n (super-exponential )
1.2
Consider the following recurrence
T ( n ) = { 7 if n ≤ 1 ; 3 T ( n − 2 ) if n > 1. T(n) = \begin{cases}
7 & \text{if } n \leq 1;\\
3T(n-2) & \text{if } n > 1.
\end{cases} T ( n ) = { 7 3 T ( n − 2 ) if n ≤ 1 ; if n > 1.
Use induction to prove that T ( n ) = f ( n ) T(n) = f(n) T ( n ) = f ( n ) with f ( n ) = 7 ⋅ 3 [ n 2 ] f(n) = 7 \cdot 3^{[\frac{n}{2}]} f ( n ) = 7 ⋅ 3 [ 2 n ]
Solution:
base case:
Given T ( n ) = f ( n ) = 7 ⋅ 3 [ n 2 ] T(n) = f(n) = 7 \cdot 3^{[\frac{n}{2}]} T ( n ) = f ( n ) = 7 ⋅ 3 [ 2 n ] apply for n = 0 n=0 n = 0 and n = 1 n=1 n = 1 :
n = 1 → T ( n ) = 7 ⋅ 3 [ 1 2 ] = 7 ⋅ 3 0 = 7 n = 1 \rightarrow T(n) = 7 \cdot 3^{[\frac{1}{2}]} = 7 \cdot 3^0 = 7 n = 1 → T ( n ) = 7 ⋅ 3 [ 2 1 ] = 7 ⋅ 3 0 = 7
n = 0 → T ( n ) = 7 ⋅ 3 [ 0 2 ] = 7 ⋅ 3 0 = 7 n = 0 \rightarrow T(n) = 7 \cdot 3^{[\frac{0}{2}]} = 7 \cdot 3^0 = 7 n = 0 → T ( n ) = 7 ⋅ 3 [ 2 0 ] = 7 ⋅ 3 0 = 7
Thus the base case holds.
induction hypothesis:
Assume T ( n ) = f ( n ) T(n) = f(n) T ( n ) = f ( n ) holds for n > 1 n > 1 n > 1 . We will proves that f ( n + 2 ) = T ( n + 2 ) f(n+2) = T(n+2) f ( n + 2 ) = T ( n + 2 ) also holds.
f ( n ) = T ( n ) T ( n ) = f ( n ) = 3 T ( n − 2 ) = 3 f ( n − 2 ) = 3 ⋅ 7 ⋅ 3 [ n − 2 2 ] T ( n + 2 ) = 3 T ( n ) \begin{align}
f(n) &= T(n) \\
T(n) = f(n) &= 3T(n-2) = 3f(n-2) = 3 \cdot 7 \cdot 3^{[\frac{n-2}{2}]} \\
T(n+2) &= 3T(n)
\end{align} f ( n ) T ( n ) = f ( n ) T ( n + 2 ) = T ( n ) = 3 T ( n − 2 ) = 3 f ( n − 2 ) = 3 ⋅ 7 ⋅ 3 [ 2 n − 2 ] = 3 T ( n )
Therefore:
T ( n + 2 ) = 3 ⋅ 3 ⋅ 7 ⋅ 3 [ n − 2 2 ] = 7 ⋅ 3 [ n − 2 2 + 2 ] T ( n + 2 ) = 7 ⋅ 3 [ n + 2 2 ] = f ( n + 2 ) \begin{align}
T(n+2) &= 3 \cdot 3 \cdot 7 \cdot 3^{[\frac{n-2}{2}]} = 7 \cdot 3^{[\frac{n-2}{2} + 2]} \\
T(n+2) &= 7 \cdot 3^{[\frac{n+2}{2}]} = f(n+2)
\end{align} T ( n + 2 ) T ( n + 2 ) = 3 ⋅ 3 ⋅ 7 ⋅ 3 [ 2 n − 2 ] = 7 ⋅ 3 [ 2 n − 2 + 2 ] = 7 ⋅ 3 [ 2 n + 2 ] = f ( n + 2 )
Therefore the induction hypothesis holds.
conclusion:
T ( n ) = f ( n ) = 7 ⋅ 3 [ n 2 ] T(n) = f(n) = 7 \cdot 3^{[\frac{n}{2}]} T ( n ) = f ( n ) = 7 ⋅ 3 [ 2 n ] is true for all n ≥ 0 n \geq 0 n ≥ 0 .
Problem 2
Consider the following Count
algorithm
Algorithm Count ( L , v ):
Pre : L is an array , v is a value
i , c := 0 , 0
while i neq | L | do
if L [ i ] = v then
c := c + 1
end if
i := i + 1
end while
return c.
Post : return the number of copies of v in L
2.1
Provide an invariant for the while loop at Line 2
Solution :
0 ≤ i ≤ ∣ L ∣ , c = ∑ j = 0 i − 1 [ L [ j ] = v ] 0 \leq i \leq |L|, c = \sum_{j=0}^{i-1} \lbrack L \lbrack j \rbrack = v \rbrack 0 ≤ i ≤ ∣ L ∣ , c = j = 0 ∑ i − 1 [ L [ j ] = v ]
2.2
Provide a bound function for the while loop at Line 2
Solution :
f ( i ) = ∣ L ∣ − i f(i) = |L| - i f ( i ) = ∣ L ∣ − i
2.3
Prove that Count
algorithm is correct.
Solution:
Line 1: i, c := 0, 0
L [ 0 , i ) L \lbrack 0, i) L [ 0 , i ) with i = 0 i=0 i = 0 is L [ 0 , 0 ) L \lbrack 0, 0) L [ 0 , 0 )
L [ 0 , 0 ) L \lbrack 0,0) L [ 0 , 0 ) is empty, hence c = ∑ j = 0 i − 1 [ L [ j ] = v ] = 0 c = \sum_{j=0}^{i-1} \lbrack L \lbrack j \rbrack = v \rbrack = 0 c = ∑ j = 0 i − 1 [ L [ j ] = v ] = 0
bound function f ( i ) = ∣ L ∣ − i f(i) = |L| - i f ( i ) = ∣ L ∣ − i starts at ∣ L ∣ , ∣ L ∣ ≥ 0 |L|, |L| \geq 0 ∣ L ∣ , ∣ L ∣ ≥ 0
Line 2: while i neq |L| do
Now prove invariant holds again til reach the end of the m-th
loop:
Line 3-5: if L[i] = v then
case:
L [ i ] = v L \lbrack i \rbrack = v L [ i ] = v hence v ∈ L [ 0 , i ] v \in L\lbrack 0,i \rbrack v ∈ L [ 0 , i ]
invariant still holds, with i ≠ ∣ L ∣ i \neq |L| i = ∣ L ∣ and L [ v ] = v L\lbrack v \rbrack = v L [ v ] = v
i new = i + 1 i_{\text{new}} = i + 1 i new = i + 1 hence 0 < i new ≤ ∣ L ∣ 0 < i_{\text{new}} \leq |L| 0 < i new ≤ ∣ L ∣ implies 0 ≤ i ∗ new ≤ ∣ L ∣ 0 \leq i*{\text{new}} \leq |L| 0 ≤ i ∗ new ≤ ∣ L ∣ and f ( i ∗ new ) = f ( i ) − 1 f(i*{\text{new}}) = f(i) - 1 f ( i ∗ new ) = f ( i ) − 1
c new = c + 1 = ∑ j = 0 i − 1 [ L [ j ] = v ] + 1 = ∑ j = 0 i new [ L [ j ] = v ] c_{\text{new}} = c + 1 = \sum_{j=0}^{i-1} \lbrack L \lbrack j \rbrack = v \rbrack + 1 = \sum_{j=0}^{i_{\text{new}}} \lbrack L \lbrack j \rbrack = v \rbrack c new = c + 1 = ∑ j = 0 i − 1 [ L [ j ] = v ] + 1 = ∑ j = 0 i new [ L [ j ] = v ]
f ( i ) f(i) f ( i ) strictly decreases after each iteration, i new : = i + 1 i_{\text{new}} := i + 1 i new := i + 1
Therefore the invariant still holds within the if statement.
L7: end while
i = ∣ L ∣ i = |L| i = ∣ L ∣ hence f ( i ) = 0 f(i) = 0 f ( i ) = 0 , the loop stops
c = ∑ j = 0 i − 1 [ L [ j ] = v ] = ∑ j = 0 ∣ L ∣ − 1 [ L [ j ] = v ] c = \sum_{j=0}^{i-1} \lbrack L \lbrack j \rbrack = v \rbrack = \sum_{j=0}^{|L|-1} \lbrack L \lbrack j \rbrack = v \rbrack c = ∑ j = 0 i − 1 [ L [ j ] = v ] = ∑ j = 0 ∣ L ∣ − 1 [ L [ j ] = v ]
Therefore the invariant still holds at the end of the loop.
2.4
What is the runtime and memory complexity of Count
algorithm?
Solution:
L1 implies 2 instructions
L2 implies 2 instructions ∣ L ∣ + 1 |L| + 1 ∣ L ∣ + 1 times,
L3-5 (if loop) implies 4 instructions ∣ L ∣ |L| ∣ L ∣ times
L6 implies 2 instructions ∣ L ∣ |L| ∣ L ∣ times
Therefore number of work is 5 + 8 N 5 + 8N 5 + 8 N , thus runtime complexity would be Θ ( 5 + 8 N ) \Theta(5+8N) Θ ( 5 + 8 N ) .
Memory complexity is Θ ( 1 ) \Theta(1) Θ ( 1 ) , since only 2 variables are used.
2.5
Provide an algorithm FastCount(L, v)
operates on ordered lists L
and computes the same results as Count(L, v)
but with a O ( log 2 ( ∣ L ∣ ) ) \mathcal{O}(\log_2(|L|)) O ( log 2 ( ∣ L ∣ ))
Solution:
Algorithm FastCount ( L , v ):
Pre : L is an ordered array , v is a value
function binarySearchFirst( L , v )
low , high := 0 , | L | - 1
results := - 1
while low <= high do
mid := ( low + high ) / 2
if L [ mid ] < v then
low := mid + 1
else if L [ mid ] > v then
high := mid - 1
else
results := mid
high := mid - 1
end while
return results
end function
function binarySearchLast( L , v )
low , high := 0 , | L | - 1
results := - 1
while low <= high do
mid := ( low + high ) / 2
if L [ mid ] < v then
low := mid + 1
else if L [ mid ] > v then
high := mid - 1
else
results := mid
low := mid + 1
end while
return result
end function
firstIndex := binarySearchFirst( L , v )
if firstIndex = - 1 then
return 0
end if
lastIndex := binarySearchLast( L , v )
return lastIndex - firstIndex + 1
Post : return the number of copies of v in L