1 Asymptotics
(a) We have a function
findMax
that iterates through an unsorted
int
array once and returns the maximum element found in that array. Give the tightest lower (Ω(·
)) and upper bounds (
O
(
·
)) of findMax in terms of
N
, the length of the array. Is it possible to define a Θ(
·
) bound for
findMax
?
iuww520iuww520iuww520iuww520iuww520iuww520iuww520iuww520
Lower bound: Ω(
N
), Upper bound:
O
(
N
)
Because the array is unsorted, we don’t know where the max will be, so we have to iterate through the entire array to ensure that we find the true max. Therefore, we know that we can never go faster than linear time with respect to the length of the array. Since the function is both lower and upper bounded by N
, we can say that the function is theta-bounded by
N
as well (Θ(
N
)).
(b) Give the worst case and best case runtime in terms of
M
and
N
. Assume
ping
is in Θ(1) and returns an int
.
1
for
(
int
i = N; i > 0; i--) {
2
for
(
int
j = 0; j <= M; j++) {
3
if
(ping(i, j) > 64)
break
;
4 }
5 }
Worst: Θ(
MN
), Best: Θ(
N
)
We repeat the outer loop N times, no matter what. For the inner loop, we see the amount of times we repeat it depends on the result of ping
. In the best case, it returns true immediately, such that we’ll only ever look at the inner loop once and then break the inner loop. In the worst case, ping
is always false and we complete the inner loop M times for every value of N in the outer loop.
(c) Below we have a function that returns true if every int has a duplicate in the array, and false if there is any unique int in the array. Assume sort(array)
is in Θ(
N
log
N
) and returns
array
sorted.
1
public static boolean
noUniques(
int
[] array) {
2 array = sort(array);
3
int
N = array.length;
4
for
(
int
i = 0; i < N; i += 1) {
5
boolean
hasDuplicate =
false
;
6
for
(
int
j = 0; j < N; j += 1) {
7
if
(i != j && array[i] == array[j]) {
8 hasDuplicate = true
;
9 }
10 }
11
if
(!hasDuplicate)
return false
;
12 }
13
return true
;
14 }
2
Asymptotics and Trees
Give the worst case and best case runtime in Θ(
·
) notation, where
N
=
array.length
.
Notice that we call
sort
at the beginning of the function, which we are told runs in Θ(
N
log
N
).
First, we consider the best case. We notice that if
hasDuplicate
is false after the inner loop (i.e, !hasDuplicate has truth value
true
) we can exit the for loop early via the return statement on line 11. Thus, the best case is when we never set hasDuplicate
to be
true
during the first time we run the inner loop. In this case, we can return after only looping through the array once, giving us
Θ(
N
log
N
+
N
) = Θ(
N
log
N
).
For the worst case, we notice that if
hasDuplicate
is always set to
true
by the inner loop, we never return on line 11. Thus, we consider the worst case where hasDuplicate
is always set to
true
in every loop, forcing us to have to loop fully through both the inner and outer loop. One such input is an array of all the same integer! Since we have to fully loop through both loops, our worst-case runtime is Θ(N
log
N
+
N
2
) = Θ(
N
2
)