CPSC 331
30. January 2013
University of Calgary
Homework Assignment # 1
Due: 8. January 2013, 9:50 am in the drop box on the 2nd floor in Math Sciences.
Proposed Solutions
Question 1
[10 marks]
Consider the following algorithm:
Algorithm 1: Duplicates(n, A1 , A2 )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Output: k
/* Precondition: A1 and A2 are arrays of length n. All entries in A1 are distinct
integers, and all entries in A2 are distinct integers.
*/
/* Postcondition: k is the number of integers x such that x appears in array A1
and in array A2 .
*/
k=0
i=0
while i < n do
/* outer loop
*/
i=i+1
`=0
j=0
while j < n do
/* inner loop
*/
j =j+1
if A1 [i] = A2 [j] then
`=1
end
end
k =k+`
end
Example: If A1 contains the values 3, 5, 7, 9 and A2 contains the values 3, 4, 5, 6, then hen the
algorithm terminates with k = 2. There are exactly two integers, namely 3 and 5, which are stored
in both arrays.
Note that if either A1 or A2 contains the same integer twice, then the precondition is not satisfied!
(a) Prove the following loop invariant for the inner loop, assuming the precondition that i ∈
{1, . . . , n}, ` = 0, and j = 0:
(L1) It is j ∈ {0, . . . , n} and ` ∈ {0, 1}, and it holds ` = 1 if and only if the value of
A1 [i] appears in A2 [1 . . . j].1
1
If j = 0, then A2 [1 . . . j] is a sub-array with 0 elements which does not contain A1 [i].
(b) State a loop invariant for the outer loop and prove it. For your proof you can assume that (L1)
is a loop invariant for the inner loop. Use your loop invariant for the outer loop to show that
the algorithm is partially correct.
(c) Prove that your algorithm terminates. For that state loop variants for each of the loops and
prove that each loop terminates.
(d) Give a function T : N → R≥0 such that the worst-case running time of the algorithm is Θ(T ).
Use the loop variants from Part (c) to prove that the worst-case running time is O(T ).
Proposed Solution:
(a) Consider one iteration of the outer loop for some value of i ∈ {1, . . . , n}. When the execution
reaches line 7, obviously ` = 0 and j = 0. (This is also guaranteed by the precondition.) Since
A2 [1 . . . j] is the sub-array that contains no elements and thus does not contain A1 [i], (L1) is
true.
Now suppose the loop invariant is true at the beginning of an iteration of the inner loop and the
loop gate is true, i.e., 0 ≤ jbefore < n. Since j gets increased by exactly one during the iteration
it holds jafter = jbefore + 1 ∈ {0, . . . , n} at the end of the iteration. The value of ` can only
change in line 10 and it can only change to 1. Since `before ∈ {0, 1} it follows that `after ∈ {0, 1}.
First consider the case that `before = 1, and thus `after = 1. In this case, since the loop invariant
was true at the beginning of the iteration we have that A1 [i] appears in A2 [1 . . . jbefore ] and since
jafter = jbefore + 1 it also appears in A2 [1 . . . jafter ]. Thus, (L1) is true at the end of the iteration.
Now suppose `before = 0. If A1 [i] = A2 [jafter ] = A2 [jbefore + 1], then ` is set to 1 during
the iteration, i.e., `after = 1. In this case A1 [i] appears in A2 [1 . . . jafter ] and (L1) is true at
the end of the iteration. If A1 [i] 6= A2 [jafter ], then ` is not set to 1 during the iteration, i.e.,
`after = `before = 0. Since the loop invariant was true at the beginning of the iteration and
`before = 0, it holds that A2 [1 . . . jbefore ] does not contain A1 [i]. Hence, A2 [1 . . . jafter ] does not
contain A1 [i], either, so from `after = 0 the loop invariant (L1) follows.
(b) Let S be the set of integers that appear in A2 [1 . . . n]. We prove that the following is a loop
variant for the outer loop:
(L2) It is i ∈ {0, . . . , n} and k is the number of integers that appear in both,
A1 [1 . . . i] and in A2 [1 . . . n].
At the beginning of the first iteration of the loop we have i = 0 and k = 0. Since A1 [1 . . . i] is
the empty sub-array, there is no integer that appears in it, so (L2) is true.
For the ease of notation, let S be the set of integers that appear in A2 [1 . . . n]. Now consider an
iteration of the loop and suppose at the beginning of the loop (L2) is true and the loop gate is
true, too. Then ibefore < n and thus by (L2) ibefore ∈ {0, . . . , n − 1}. Since i gets increased by 1,
we have iafter = ibefore + 1 and thus iafter ∈ {1, . . . , n}.
By (L2), kbefore is the number of integers in A1 [1 . . . ibefore ] that are in S. When the inner loop
terminates, j = n (this follows from the loop gate and the loop invariant that implies j ≤ n).
By (L1), at the end of the inner loop ` = 1 if A1 [iafter ] appears in S, and otherwise iafter = 0.
Clearly, kafter = kbefore + `. Hence, if A1 [iafter ] is in S, then kafter = kbefore + 1 and otherwise
kafter = kbefore . Note that by the precondition of the algorithm, A1 [iafter ] does not occur in
A1 [1 . . . iafter − 1] = A1 [1 . . . ibefore ]. Hence, if A1 [iafter ] is in S, then there is one more integer in
A1 [1 . . . iafter ] that appears in S than in A1 [1 . . . ibefore ]. In this case, also kafter = kbefore + 1, so
(L2) follows.
(c) Let f (i) = n − i and g(j) = n − j.
Then f is a loop variant for the outer loop: In each iteration of the outer loop i increases by
one, so f (i) decreases by one, and when f (i) ≤ 0 then i ≥ n so the outer loop terminates.
Similarly, g is a loop variant for the inner loop: In each iteration of the inner loop j increases
by one, so g(j) decreases by one, and when g(j) ≤ 0 then j ≥ n so the inner loop terminates.
It follow that the inner loop terminates for every iteration of the outer loop. Hence, every
iteration of the outer loop terminates, and since f is a loop variant of that loop, the outer loop
terminates as well.
(d) T = n2 , i.e., the worst-case running time is Θ(n2 ).
We prove that the worst-case running time is O(n2 ). Before the outer loop starts, i = 0 so
f (i) = n. From that it follows that the outer loop gets iterated at most n times. Before the
inner loop starts during one iteration of the outer loop, j = 0, so g(j) = n. From that it follows
that the inner loop gets iterated at most n times for each iteration of the outer loop. Since there
is only a constant number of other operations per iteration of the outer and the inner loop, it
follows that the worst-case running time is O(n2 ).
Question 2
[5 marks]
Consider the following algorithm:
1
2
3
4
5
Input: x
/* Precondition: x ∈ N
y := x2
while y > 0 do
x := x − 1
y := y − 2x − 1
end
*/
(a) Prove that the following statement is a loop invariant: y = x2 .
(b) State a loop variant and prove that the algorithm terminates if the precondition is satisfied.
You can assume that y = x2 is a loop invariant.
(c) Show that the worst-case running time of the algorithm is O(x), using an appropriate loop
variant. (You can again assume that y = x2 is a loop invariant.) You may or may not require a
loop variant that is different from the one used for part (b).
Proposed Solution:
(a) Clearly, y = x2 at the beginning of the first iteration. Now suppose this is true at the beginning
of some iteration at which y > 0, i.e., when the loop gate is true. I.e., ybefore = x2before . Then
xafter = xbefore − 1 and
yafter = ybefore −2xafter −1 = x2before −2(xbefore −1)−1 = x2before −2xbefore +1 = (xbefore −1)2 = x2after .
(b) Define f (x) = x. Clearly, the value of x decreases with each iteration, so it suffices to show that
the loop terminates once f (x) = x ≤ 0. Since the value of x decreases by one in each iteration it
will reach the value 0 in some iteration. By the loop invariant, y = x2 = 0 when that happens,
and at that point the loop terminates.
(c) The loop variant immediately implies that only x iterations of the loop are executed as initially
f (x) = x. Since each loop comprises only a constant number of operations, the worst-case
running time of the algorithm is O(x).
Question 3.
[5 marks]
For n ∈ R>1 let f (n) = n3/2 and g(n) =
n2
. Prove that f = o(g).
log n
Proposed Solution:
n3/2
log n
ln n/ ln 2
f (n)
= lim 2
= lim 1/2 = lim
n→∞ n / log n
n→∞ n
n→∞
n→∞ g(n)
n1/2
2
1
1/n
1
L’Hop.
= lim
=0
= lim
·
·
n→∞ ln 2 n1/2
n→∞ ln 2 (1/2)n−1/2
lim
Question 4
[4 marks]
For each of the following statements, decide whether it is true or false. Justify your answer with a
proof or a counterexample.
n!
= o(nn/2 ).
(dn/3e)!
(b) If g(n) = Ω f (n) then 2f (n) = O 2g(n) .
(c) If f (n) = O g(n) then log f (n) = O(log g(n) .
(a)
Proposed Solution:
(a) This is not true. Let f (n) = nn/2 and g(n) = o
n!
dn/3e!
We show that f = o(g), and thus
g = ω(f ).
First, we consider g separately:
g(n) =
n!
n · (n − 1) . . . (dn/3e + 1) · dn/3e · (dn/3e − 1) . . . 1
=
= n·(n−1) . . . (dn/3e+1).
dn/3e!
dn/3e · (dn/3e − 1) . . . 1
This is a product of n − dn/3e ≥ n − (n/3 + 1) = (2/3)n − 1 terms. Replacing each term with
n/3, we obtain a lower bound on g(n):
g(n) ≥ (n/3) . . . (n/3) = (n/3)2n/3−1 .
|
{z
}
(2/3)n − 1 terms
Next, we transform the base: Since (n/3) = 2log(n/3) , we have
(2/3)n−1
g(n) ≥ 2log(n/3)
= 2log(n/3)(2n/3−1)
Similarly, we can transform the base in the expression of f (n):
f (n) = nn/2 = 2log(n)·n/2
Thus,
f (n)
2log(n)·n/2
≤ log(n/3)(2n/3−1) = 2log(n)·n/2−log(n/3)(2n/3−1)
g(n)
2
(1)
We just analyse the exponent:
n
n
2n
2n
lim log(n) · − log(n/3)
−1
= lim log(n) · − log(n/3)
+ log(n/3)
n→∞
n→∞
2
3
2
3
2n
2n
n
+ log(3)
+ log(n/3)
= lim log(n) · − log(n)
n→∞
2
3
3
1 2 (2/3) log(3) + log(n/3)
= lim n · log(n)
− +
n→∞
2 3
n log n
1 2
= lim n · log(n)
−
n→∞
2 3
1
= lim n · log(n) −
= −∞.
n→∞
6
Hence, the expression in (1) converges to 0.
© Copyright 2026 Paperzz