Problem 1

1.1

Consider the following function of nn:

n2i=0n5in31n3n2+2n(Πi=19i)(i=0log2(n)2i)+17ln(n)ln(1n)ln(2n)10nlog2(n7)n4nn5n\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}

Group the above functions that have identical growth rate and order these groups on increasing growth. Hence:

  • If you place functions f1(n)f_1(n) and f2(n)f_2(n) in the same group, then we must have f1(n)=Θ(f2(n))f_1(n) = \Theta{(f_2(n))};

  • If you place function f1(n)f_1(n) in a group ordered before the group in which you place function f2(n)f_2(n), then we must have f1(n)=O(f2(n))f1(n)Ω(f2(n))f_1(n) = \mathcal{O}{(f_2(n))} \land f_1(n) \neq \Omega{(f_2(n))}.

Solution:

Theorem 3.25 states the following:

limnf(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}

The following are the rules of thumb to determine the order of growth of functions:

cf(n)=Θ(f(n))loga(n)=Θ(logb(n))limnncnc+d=limn1nd=0nc=O(nc+d)log2(n)c=O(nd) c>0,d>0nc=O(dn) c>0,d>1dnu=O(cnv) cd1,uv1i=1mcindi=O(ndi)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}

Let’s start with analysing the functions that have the same growth rate:

  • n2n^2: polynomial growth, n2=Θ(n2)n^2 = \Theta(n^2) based on rule 3.

  • i=0n5i\sum_{i=0}^{n}5\cdot{i}: polynomial growth, i=0n5i=5n(n+1)2=52n2+52n\sum_{i=0}^{n}5\cdot{i} = 5 \cdot \frac{n(n+1)}{2} = \frac{5}{2}n^2 + \frac{5}{2}n, which is Θ(n2)\Theta(n^2) based on rule 77.

  • n31n3n^3 \cdot \sqrt{\frac{1}{n^3}}: polynomial growth, =n31n32Θ(n32)= n^3 \cdot \frac{1}{n^{\frac{3}{2}}} \rightarrow \Theta(n^{\frac{3}{2}}) based on rule 9,39, 3

  • n2+2nn^2 + 2^n: exponential growth, =Θ(2n)=\Theta(2^n) based on rule 77

  • (Πi=19i)(\Pi_{i=1}^{9}i): constant, =129=1 \cdot 2 \dots 9 based on rule 9

  • i=0log2(n)2i+1\sum_{i=0}^{\log_2{(n)}}{2^i} + 1: linear, since the term is a geometrics series, such that i=0log2(n)2i+1=1(2log2(n)+11)21+1=22log2(n)=2n\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. Therefore based on rule 11 we have Θ(n)\Theta(n)

  • 7ln(n)7^{\ln(n)}: polynomial, since 7ln(n)=nln(7)7^{\ln(n)} = n^{\ln(7)}. Apply rule 33 we have 7ln(n)=Θ(nln7)O(n2)7^{\ln(n)} = \Theta(n^{\ln 7}) \rightarrow \mathcal{O}(n^2)

  • ln(1n)-\ln(\frac{1}{n}): logarithmic, since ln(1n)=ln(n)-\ln (\frac{1}{n}) = \ln(n). Apply rule 11 yield Θ(lnn)\Theta{(\ln{n})}.

  • ln(2n)\ln (2^n): linear, since ln(2n)=nln2\ln(2^n) = n \cdot \ln_{2} and rule 11 yield Θ(n)\Theta{(n)}

  • 1010: constant

  • nlog2(n7)n\log_2(n^7): polynomial, since nlog2(n7)=n7log2(n)=7nlog2(n)n\log_{2}(n^7) = n \cdot 7\log_{2}{(n)} = 7n\log_{2}(n). Based on rule 99 and 11 yield O(n2)\mathcal{O}(n^2)

  • n4\sqrt{n^4}: polynomial growth, =n2=n^2 based on rule 3.

  • nnn^n: super-exponential.

  • 5n5n: linear based on rule 1, gives Θ(n)\Theta(n)

Thus the order from increasing rate:

  • 10(Πi=19i)10 \quad (\Pi_{i=1}^{9}i) (constant)

  • ln(1n)-\ln(\frac{1}{n}) (logarithmic)

  • ln(2n)5ni=0log2(n)2i+1\ln (2^n) \quad 5n \quad \sum_{i=0}^{\log_2{(n)}}{2^i} + 1 (linear)

  • n2i=0n5in31n3n4nlog2(n7)7ln(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)} (polynomial)

  • n2+2nn^2 + 2^n (exponential)

  • nnn^n (super-exponential)

1.2

Consider the following recurrence

T(n)={7if n1;3T(n2)if n>1.T(n) = \begin{cases} 7 & \text{if } n \leq 1;\\ 3T(n-2) & \text{if } n > 1. \end{cases}

Use induction to prove that T(n)=f(n)T(n) = f(n) with f(n)=73[n2]f(n) = 7 \cdot 3^{[\frac{n}{2}]}

Solution:

base case:

Given T(n)=f(n)=73[n2]T(n) = f(n) = 7 \cdot 3^{[\frac{n}{2}]} apply for n=0n=0 and n=1n=1:

  • n=1T(n)=73[12]=730=7n = 1 \rightarrow T(n) = 7 \cdot 3^{[\frac{1}{2}]} = 7 \cdot 3^0 = 7
  • n=0T(n)=73[02]=730=7n = 0 \rightarrow T(n) = 7 \cdot 3^{[\frac{0}{2}]} = 7 \cdot 3^0 = 7

Thus the base case holds.

induction hypothesis:

Assume T(n)=f(n)T(n) = f(n) holds for n>1n > 1. We will proves that f(n+2)=T(n+2)f(n+2) = T(n+2) also holds.

f(n)=T(n)T(n)=f(n)=3T(n2)=3f(n2)=373[n22]T(n+2)=3T(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}

Therefore:

T(n+2)=3373[n22]=73[n22+2]T(n+2)=73[n+22]=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}

Therefore the induction hypothesis holds.

conclusion:

T(n)=f(n)=73[n2]T(n) = f(n) = 7 \cdot 3^{[\frac{n}{2}]} is true for all n0n \geq 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:

0iL,c=j=0i1[L[j]=v]0 \leq i \leq |L|, c = \sum_{j=0}^{i-1} \lbrack L \lbrack j \rbrack = v \rbrack

2.2

Provide a bound function for the while loop at Line 2

Solution:

f(i)=Lif(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) with i=0i=0 is L[0,0)L \lbrack 0, 0)

  • L[0,0)L \lbrack 0,0) is empty, hence c=j=0i1[L[j]=v]=0c = \sum_{j=0}^{i-1} \lbrack L \lbrack j \rbrack = v \rbrack = 0

  • bound function f(i)=Lif(i) = |L| - i starts at L,L0|L|, |L| \geq 0

Line 2: while i neq |L| do

  • bound function f(i)f(i) stops at 00

  • invariant still holds, with iLi \neq |L|

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]=vL \lbrack i \rbrack = v hence vL[0,i]v \in L\lbrack 0,i \rbrack

  • invariant still holds, with iLi \neq |L| and L[v]=vL\lbrack v \rbrack = v

  • inew=i+1i_{\text{new}} = i + 1 hence 0<inewL0 < i_{\text{new}} \leq |L| implies 0inewL 0 \leq i*{\text{new}} \leq |L| and f(inew)=f(i)1f(i*{\text{new}}) = f(i) - 1

  • cnew=c+1=j=0i1[L[j]=v]+1=j=0inew[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

  • f(i)f(i) strictly decreases after each iteration, inew:=i+1i_{\text{new}} := i + 1

Therefore the invariant still holds within the if statement.

L7: end while

  • i=Li = |L| hence f(i)=0f(i) = 0, the loop stops
  • c=j=0i1[L[j]=v]=j=0L1[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

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 times,
  • L3-5 (if loop) implies 4 instructions L|L| times
  • L6 implies 2 instructions L|L| times

Therefore number of work is 5+8N5 + 8N, thus runtime complexity would be Θ(5+8N)\Theta(5+8N).

Memory complexity is Θ(1)\Theta(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(log2(L))\mathcal{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