Survey
Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts
no text concepts found
Transcript
```COM S 311 SPRING 2022
HOMEWORK 2
SAMPLE SOLUTIONS
(1) Solve the following recurrence equations: Assume that T (n) is constant for sufficiently small
n.
(a) T (n) = 5T (n/4) + log n
Answer. Apply the Master Theorem. We have
a = 5, b = 4, and f (n) = log n.
Thus, nlogb a = nlog4 5 ≈ n1.161 and f (n) = log n = O(nlog4 5− ) for any < log4 5.
Hence, Case 1 of the Master Theorem applies, and T (n) = Θ(nlog4 5 ).
(b) T (n) = 16T (n/2) + n4 .
Answer. Apply the Master Theorem. We have
a = 16, b = 2, and f (n) = n4 .
Thus, nlogb a = nlog2 16 = n4 and f (n) = Θ(n4 ). Hence, Case 2 of the Master Theorem
applies, and T (n) = Θ(n4 log n).
(c) T (n) = 9T (n/3) + n2 log n
Answer. We first try to apply the Master Theorem. We have
a = 9, b = 3, and f (n) = n2 log n.
Thus, nlogb a = nlog3 9 = n2 . Now,
• n2 log n is not O(n2− ), so Case 1 does not apply,
• n2 log n is not Θ(n2 ), so Case 2 does not apply, and
• n2 log n is not Ω(n2+ ), so Case 3 does not apply.
Thus, instead of the Master Theorem, we use the recursion tree method to bound T (n).
The recursion tree is shown below.
n 2 log n
n2
n
log
(3)
9
9
2
2
log3 n
n2
n
log
(3)
9
n
n
n
n
⋯
log
log
(3)
(9)
81
81
9
⋯
9
⋯
⋯
9
n2
n
n
n
log
⋯
log
(3)
81
(3)
81
2
⋯
9
n 2 log n
9
⋯
9
n2
n
log
(3)
9
n2
n
log
(9) ⋯
81
⋯
≤ n 2 log n
9
n2
n
log
(9)
81
9
⋯
≤ n 2 log n
9
⋮
1
1
1
⋯
1
9
log3 n
=n
log3 9
= n leaves
2
1
1
1
n2
Total ≤ (n 2 log n) ⋅ log3 n + n 2
From the recursion tree, we see that
log3 n−1
T (n) =
X
i=0
log3 n−1
=
X
9i
n 2
3i
n2 log
i=0
2
log
n
3i
n
3i
+ 9log3 n
+ nlog3 9
≤ (n log n) · log n + n2
= O(n(log n)2 ).
Note that it is possible to show that this bound is tight — i.e., T (n) = Θ(n2 (log n)2 ).
Students are not required to prove this.
In the next problems, assume that array indices start at 1.
(2) The algorithm below can be proved to correctly (although inefficiently) sort and array A.
You do not need to prove that this algorithm is correct.
1
2
3
4
5
6
7
8
9
10
SillySort(A, i, j)
Input: An array A of n integers, and two indices, i and j, such that 1 ≤ i ≤ j ≤ n.
Result: Subarray A[i . . j] is sorted in nondecreasing order .
n=j−i+1
// The size of the subarray we are sorting
if n == 2 then
if A[i] > A[j] then
Swap A[i] and A[j]
else if n > 2 then
m = bn/3c
SillySort(A, i, j − m)
// Sort the first part
SillySort(A, i + m, j)
// Sort the last part
SillySort(A, i, j − m)
// Sort the first part again
(a) Write a recurrence equation for the running time T (n) of SillySort.
Answer. The recurrence is
(
Θ(1)
if n ≤ 2
T (n) =
3T (2n/3) + c if n > 2.
Note that we assume that only a reference to the subarrays of A is passed to the
recursive calls. If the subarrays have to be copied, the c in the recurrence becomes cn.
(b) What is the solution to the recurrence of part (a)?
Answer. Apply the Master Theorem. We have
a = 3, b = 3/2, and f (n) = c.
Thus, nlogb a = nlog3/2 3 ≈ n2.71 and f (n) = O(nlog3/2 3− ), for any ≤ log3/2 3. Hence,
Case 1 of the Master Theorem applies, and T (n) = O(n2.71 ).
Note that the solution for T (n) remains the same if c is replaced by cn in the recurrence
of part (a).
(c) Write the recurrence equation for the running time T (n) of SillySort assuming that
we replace Line 7 with m = bn/4c.
2
Answer. The recurrence is
(
Θ(1)
if n ≤ 2
T (n) =
3T (3n/4) + c if n > 2.
Note that we assume that only a reference to the subarrays of A is passed to the
recursive calls. If the subarrays have to be copied, the c in the recurrence becomes cn.
(d) What is the solution to the recurrence of part (c)?
Answer. Apply the Master Theorem. We have
a = 3, b = 4/3, and f (n) = c.
Thus, nlogb a = nlog4/3 3 ≈ n3.82 and f (n) = O(nlog4/3 3− ), for any ≤ log4/3 3. Hence,
Case 1 of the Master Theorem applies, and T (n) = O(n3.82 ).
Note that the solution for T (n) remains the same if c is replaced by cn in the recurrence
of
(3) Design a divide-and-conquer algorithm for the following problem. The input is an array A
consisting of n distinct integers, which can be positive, negative, or zero. Assume that A
is sorted from low to high. The algorithm should determine if there is an index i such that
A[i] = i. Make your algorithm as fast as you can possibly make it. For full credit, you must
• give pseudocode for your algorithm,
• briefly justify the correctness of your algorithm, and
• analyze the running time of your algorithm.
Answer. The pseudocode for our algorithm is shown below.
1
2
3
4
5
6
7
8
9
10
FindIndex(A, left, right)
Input: An array A of n distinct integers in increasing order, and two indices left and
right into A. The elements of A may be positive or nonpositive
Output: true if there is an index i ∈ {left, left + 1, . . . , right} such that A[i] == i;
false if no such i exists.
if left > right then
return false
mid = b(left + right)/2c
if mid == A[mid] then
return true
if mid < A[mid] then
return FindIndex(A, left, mid − 1)
else
return FindIndex(A, mid + 1, right)
Note that if left > right, it must be the case that there is no i ∈ {left, left +
1, . . . , right}, so the algorithm correctly returns false.
Correctness follows directly from the following property, which we shall argue holds at
each call to FindIndex:
Property. If there exists an index i ∈ {left, left + 1, . . . , right} such that
A[i] = i, then, either
1. i = mid and line 6 returns the correct result,
2. i < A[mid], and i ∈ {left, left + 1, . . . , mid − 1}, or
3. i > A[mid] and i ∈ {mid + 1, mid + 2, . . . , right}.
3
Proof.
1. If mid = A[mid], then we clearly have i = mid.
2. If mid < A[mid], then, since the elements A are strictly increasing, j < A[j]
for all j ∈ {mid + 1, mid + 2, . . . , right}, so if there exists an index i ∈
{left, left + 1, . . . , right} such that A[i] = i, it must be the case that
i ∈ {left, left + 1, . . . , mid − 1}.
3. If mid > A[mid], then, since the elements A are strictly increasing, j > A[j]
for all j ∈ {left, left + 1, . . . , mid − 1}, so so if there exists an index
i ∈ {left, left + 1, . . . , right} such that A[i] = i, it must be the case that
i ∈ {mid + 1, mid + 2, . . . , right}.
The running time T (n) of a call to FindIndex(A, 1, n) satisfies the same recurrence as
binary search. That is,
(
Θ(1)
if n = 1
T (n) =
T (n/2) + c if n > 1.
Thus, T (n) = Θ(log n).
(4) Suppose you have an n-element array A of intervals (xi , yi ), where xi , yi are integers such
that xi ≤ yi . The interval (xi , yi ) represents the set of integers between xi and yi . For
example, the interval (3, 6) represents the set {3, 4, 5, 6}. Define the overlap of two intervals
I, I 0 to be the number of integers that are members of both intervals. For example, the
overlap of intervals I = (3, 6) and I 0 = (5, 8) is 2, since there are only two integers, namely
5 and 6, that are in both I and I 0 .
The goal of this problem is to design a divide-and-conquer algorithm that takes as input
an n-element array A of intervals and returns the highest overlap among all pairs of intervals
in A. Assume that A is sorted by the xi -values of its intervals.
(a) A naı̈ve approach is to compute the overlap between every pair of intervals. What is
the exact number of comparisons that this approach needs? What is the running time
of this approach?
Answer. The number is n2 = n(n − 1)/2, leading to a Θ(n2 )-time algorithm.
(b) Consider the following potential divide-and-conquer algorithm for the problem. First,
divide A into two parts L and R of length n/2, such that all the xi -values of intervals
in L are smaller than the xi -values of intervals in R. Next, recursively determine
the maximum overlap pL in L and the maximum overlap pR in R. Finally, return
max{pL , pR }. Why is this not enough to give the correct answer?
Answer. This approach fails to take into account overlaps between an interval in L
and an interval in R.
(c) Taking advantage of the fact that the array A is sorted, design a divide-and-conquer
algorithm that is faster than the naı̈ve approach. For full credit, you must
• give pseudocode for your algorithm and
• briefly justify the correctness of your algorithm.
Answer. For an interval I, we write I.x to denote the left endpoint of I and I.y
to denote the right endpoint of I. Thus, I = (I.x, I.y). We assume that we have a
function Overlap such that, for any two intervals I and I 0 , Overlap(I, I 0 ) returns the
overlap of I and I 0 in Θ(1) time.
4
Algorithm MaxOverlap, shown below follows the divide-and-conquer idea outlined in
part (b), recursively computing pL and pR for the two sublists L and R, but additionally
invokes a procedure CrossOverlap that counts the number, pRL of overlaps between
an interval in L and an interval in R.
1
2
3
4
5
6
7
8
9
MaxOverlap(A)
Input: An array A of n intervals sorted by nondecreasing left endpoint.
Output: The maximum overlap between any pair of intervals in A.
if n == 1 then
return 0
L = [A[1], . . . , A[bn/2c]]
R = [A[bn/2c + 1], . . . , A[n]]
pL = MaxOverlap(L)
pR = MaxOverlap(R)
pLR = CrossOverlap(L, R)
return max{pL , pR , pLR }
Assuming CrossOverlap, described next, is correct, MaxOverlap is also correct. We
argue this inductively.
Base case: When n = 1, there are no overlaps, and MaxOverlap(A) correctly
returns 0.
Induction hypothesis: MaxOverlap returns the correct answer for any arrays
with up to n − 1 intervals.
Induction step: Suppose A is an array of n intervals. Then, every overlap in A
is either (1) between two intervals un L, (2) between two intervals in R, or (3)
between an interval in L and an interval in R. Since L and R have at most n − 1
intervals, MaxOverlap correctly computes the maximum overlaps pL and pR for
each subarray. Thus, assuming CrossOverlap is correct, MaxOverlap correctly
returns the maximum overlap in A.
Algorithm CrossOverlap is shown below.
1
2
3
4
5
6
7
8
9
10
11
12
CrossOverlap(L, R)
Input: Arrays L and R of nL and nR intervals, respectively. L and R are sorted by
nondecreasing left endpoints, and L[nL ].x ≤ R[1].x.
Output: The maximum overlap between an interval in L and an interval in R.
rightmost = 1
for i = 2 to nL do
if L[i].y > L[rightmost].y then
rightmost = i
if L[rightmost].y < R[1].x then
return 0
curMax = 0
for i = 1 to nR do
if Overlap(L[rightmost], R[i]) > curMax then
curMax = Overlap(L[rightmost], R[i])
return curMax
Lines 2–5 search for the interval L[rightmost] in L whose right endpoint is maximum.
If L[rightmost].y < R[1].x, then every interval in L is to the left of any interval in
R, so CrossOverlap correctly returns 0 in Line 7. Otherwise, the maximum overlap
between an interval in L and an interval in R must be between L[rightmost] and some
5
interval in R. Thus, Lines 9–11 successively examine each interval in R to find the one
that has the maximum overlap with L[rightmost]. The maximum overlap found is
returned in Line 12.
(d) What is the recurrence for the running time of your divide-and-conquer algorithm in
part (c)?
Answer. The base case takes constant time. Otherwise, there are two recursive calls
on inputs of size n/2 and the combination (merge) work in CrossOverlap is linear.
This leads to the following recurrence:
(
Θ(1)
if n = 1
T (n) =
2T (n/2) + cn if n > 1.
(e) What is the running time of the algorithm in part (c)?
Answer. The recurrence of part (d) is the same as that for merge sort. Its solution,
therefore, is T (n) = Θ(n log n)
6
```
Related documents