Description
Question 1: Setting Up and Solving Recurrences
Consider the python-like pseudocode below
def div_and_conquer_fun(a):
# a is an array of size n
n = length(a)
if n == 0:
return 0
if n == 1:
return a[1]
# 1. Divide into 3 parts
a1 = a[1 ... n//3]
a2 = a[n//3+1 ... 2*n//3]
a3 = a[2*n//3+1 ... n]
# note // denotes integer division a//b := floor(a/b)
(b1, b2) = coalesce_arrays_into_two(a1, a2, a3)
# note b1, b2 are arrays of size n//4 each.
c1 = div_and_conquer_fun(b1)
c2 = div_and_conquer_fun(b2)
return c1 + c2 // Theta (1) time
- The algorithm first divides an array of size n into 3 roughly equal parts.
- Next, it uses the functionΒ
coalesce_arrays_into_two(a1, a2, a3)Β that runs inΒ Ξ(n)Ξ(n)Β time, returning two arraysΒb1Β andΒb2Β of sizeΒ n4n4Β each. - The function is then recursively called onΒ
b1Β andΒb2. - Finally, the result is summed up and returned.
Write down a recurrence relation for the running time of the divide and conquer function above. Use master method to solve the recurrence: write down which case of the master method and the result.
YOUR ANSWER HERE
Question 2(a): Counting Dominances
Suppose you are given two sorted arraysΒ aaΒ andΒ bbΒ of the sizesΒ mmΒ andΒ nn, respectively. A “dominance” ofΒ aaΒ overΒ bbΒ is a pair of indicesΒ (i,j)(i,j)Β such thatΒ a[i]>b[j]a[i]>b[j]. Note thatΒ iiΒ is an index of arrayΒ aaΒ andΒ jjΒ must be an index of arrayΒ bb.
Write aΒ brute forceΒ algorithm that counts the number of dominances ofΒ aaΒ overΒ bbΒ that runs inΒ Ξ(n2)Ξ(n2)Β time.
#Answer 2(a):
def count_dominances_brute_force(a, b):
# YOUR CODE HERE
raise NotImplementedError()
Question 2(b): Counting Dominances
However, the brute force algorithm is suboptimal. Design aΒ Ξ(n)Ξ(n)Β algorithm to count the number of dominances. Do this by modifying the merge algorithm we studied as part of merge sort. Instead of merging the two sorted arrays, count the number of dominances.
#Answer 2(b):
def count_dominances(a, b):
# YOUR CODE HERE
raise NotImplementedError()
Question 2(c): Counting Dominances
Explain the logic behind your solution to Question 2(b) briefly (5 lines).
YOUR ANSWER HERE
Question 3(a): Finding a Fixed Point.
A fixed point of an arrayΒ AA, if it exists, is an indexΒ iiΒ such thatΒ A[i]=iA[i]=i. Given aΒ sortedΒ arrayΒ AAΒ ofΒ distinctΒ integers, return the index of the fixed point if one exists, or otherwise, returnΒ -1Β to signal that no fixed point exists. Your algorithm must be as efficient as possible.
#Answer 3(a)
def find_fixed_point(a):
# YOUR CODE HERE
raise NotImplementedError()
Question 3(b):
Explain your solution to the problem briefly and derive its running time complexity.
YOUR ANSWER HERE
Question 3(c): Finding a Fixed Point Again.
Given aΒ sortedΒ arrayΒ AAΒ ofΒ distinctΒ natural numbers, return the index of the fixed point if one exists, or otherwise, returnΒ -1Β to signal that no fixed point exists. Your algorithm must be as efficient as possible.
#Answer 3(c)
def find_fixed_point_natural(a):
# YOUR CODE HERE
raise NotImplementedError()
Question 3(d)
Explain your solution to the problem briefly and derive its running time complexity. (Hint: Your algorithm should be quicker than your algorithm for part (a).)
YOUR ANSWER HERE
Testing your solutions — Do not edit code beyond this point
# This code runs 5 test cases on your two algorithms
def test_count_dominances(func):
a1 = [ 5, 7, 10]
b1 = [ 1, 2, 3]
n1 = 9
a2 = [ 6, 10, 15, 21]
b2 = [ 4, 19, 25, 32]
n2 = 5
a3 = [ 6, 10, 15, 21]
b3 = []
n3 = 0
a4 = [ 1, 3, 5, 7, 9, 11, 13]
b4 = [ 2, 4, 6, 8, 10]
n4 = 20
a5 = [1, 3, 5, 6, 7, 9, 11, 13]
b5 = [2, 4, 6, 6, 6, 8, 10]
n5 = 30
problems = [(a1, b1, n1), (a2, b2, n2), (a3, b3, n3), (a4, b4, n4), (a5, b5, n5)]
num_passed = 0
for (a, b, n) in problems:
res = func(a, b)
if res == n:
num_passed = num_passed + 1
else:
print('FAILED: a = ', a, 'b = ', b, ' expected = ', n, 'your code = ', res)
print('--- Done ---')
print ('Num tests = ', len(problems))
print ('Num passed = ', num_passed)
print('Testing brute force:')
test_count_dominances(count_dominances_brute_force)
print('Testing modified merge algorithm:')
test_count_dominances(count_dominances)
from random import sample
def compare_brute_force_vs_fast():
a = sorted( sample (range(60), 20) )
b = sorted( sample (range(60), 20) )
n1 = count_dominances_brute_force(a, b)
n2 = count_dominances(a, b)
if n1 != n2:
print('Disparity observed between two algorithms:', a, b, n1, n2)
return False
return True
print('Comparing the two implementations.')
num_passed = 0
total = 100
for i in range(total):
if compare_brute_force_vs_fast():
num_passed = num_passed + 1
print(' -- all tests done -- ')
print(' passed = ', num_passed, ' out of ', total)
print(find_fixed_point([-10, -5, -2, 2, 3, 5, 7, 10, 15, 25, 35, 78, 129]))
def find_fixed_point_very_naive(a):
n = len(a)
for i in range(0, n):
if a[i] == i:
return i
return -1
def test_find_fixed_point_code(n_tests, test_size):
n_passed = 0
for i in range(0, n_tests):
a = sorted( sample( range(-10 * n_tests, 10 * n_tests ), test_size))
j = find_fixed_point(a)
if j >= 0 and a[j] != j:
print(' Code failed for input: ', a, 'returned : ', j, 'expected:', find_fixed_point_very_naive(a))
elif j < 0:
assert j == -1, 'Your code returns an illegal negative number: have you implemented it yet?'
k = find_fixed_point_very_naive(a)
if k >= 0:
print('Code failed for input', a)
print('Your code failed to find a fixed point')
print('However, for j = ', k, 'a[j] =', a[k])
else:
n_passed = n_passed + 1
else:
n_passed = n_passed + 1
return n_passed
n_tests = 10000
n_passed = test_find_fixed_point_code(10000, 10)
print(' num tests = ', n_tests)
print(' num passed = ', n_passed)
print('Test: expected answer = 5, your answer = ', find_fixed_point([-10, -5, -2, 2, 3, 5, 7, 10, 15, 25, 35, 78, 129]))
def test_find_fixed_point_natural_code(n_tests, test_size):
n_passed = 0
for i in range(0, n_tests):
a = sorted( sample( range(0, 10 * n_tests ), test_size))
j = find_fixed_point_natural(a)
if j >= 0 and a[j] != j:
print(' Code failed for input: ', a, 'returned : ', j, 'expected:', find_fixed_point_very_naive(a))
elif j < 0:
assert j == -1, 'Your code returns an illegal negative number: have you implemented it yet?'
k = find_fixed_point_very_naive(a)
if k >= 0:
print('Code failed for input', a)
print('Your code failed to find a fixed point')
print('However, for j = ', k, 'a[j] =', a[k])
else:
n_passed = n_passed + 1
else:
n_passed = n_passed + 1
return n_passed
n_tests = 10000
n_passed = test_find_fixed_point_natural_code(10000, 10)
print(' num tests = ', n_tests)
print(' num passed = ', n_passed)
print('Test: expected answer = 0, your answer = ', find_fixed_point_natural([0,1, 2, 3, 5, 7, 10, 15, 25, 35, 78, 129]))

