DSA Advanced Capstone โ the Mock Gauntlet
The capstone is one program that solves four hard problems under interview conditions. A printed self-scoring rubric closes the program and the series.
Problem one, the partition search
The kth value across two sorted lists sits at a split of both lists. Binary search moves the split until every left value is at most every right value.
def kth_smallest(a, b, k):
if len(a) > len(b):
a, b = b, a
lo = max(0, k - len(b))
hi = min(k, len(a))
while lo <= hi:
i = (lo + hi) // 2
j = k - i
left_a = a[i - 1] if i > 0 else float("-inf")
right_a = a[i] if i < len(a) else float("inf")
left_b = b[j - 1] if j > 0 else float("-inf")
right_b = b[j] if j < len(b) else float("inf")
if left_a <= right_b and left_b <= right_a:
return max(left_a, left_b)
if left_a > right_b:
hi = i - 1
else:
lo = i + 1
return None
print("4th smallest of [1, 4, 9] and [2, 3, 8]:", kth_smallest([1, 4, 9], [2, 3, 8], 4))Problem two, merges over ranges
Merging neighbouring piles costs the total weight of the piles merged. Short ranges are priced first, and longer ranges reuse their answers.
def min_merge(piles):
n = len(piles)
prefix = [0]
for p in piles:
prefix.append(prefix[-1] + p)
dp = [[0] * n for _ in range(n)]
for length in range(2, n + 1):
for i in range(n - length + 1):
j = i + length - 1
cost = prefix[j + 1] - prefix[i]
dp[i][j] = min(dp[i][m] + dp[m + 1][j] for m in range(i, j)) + cost
return dp[0][n - 1]
print("cheapest merge of [4, 2, 3]:", min_merge([4, 2, 3]))Problem three, one free road
Each town appears twice, once with the coupon unused and once with it spent. Dijkstra over those doubled states finds the cheapest route from A to D.
import heapq
def cheapest_with_coupon(roads, start, goal):
dist = {(start, False): 0}
heap = [(0, start, False)]
while heap:
cost, node, used = heapq.heappop(heap)
if cost > dist.get((node, used), float("inf")):
continue
if node == goal:
return cost
for nxt, w in roads[node]:
if cost + w < dist.get((nxt, used), float("inf")):
dist[(nxt, used)] = cost + w
heapq.heappush(heap, (cost + w, nxt, used))
if not used and cost < dist.get((nxt, True), float("inf")):
dist[(nxt, True)] = cost
heapq.heappush(heap, (cost, nxt, True))
return None
roads = {
"A": [("B", 9), ("C", 2)],
"B": [("D", 2)],
"C": [("B", 3), ("D", 7)],
"D": [],
}
print("cheapest A to D with one free road:", cheapest_with_coupon(roads, "A", "D"))Problem four, a recent event counter
The design holds event times in a queue ordered by arrival. A count first drops every time outside the window, then reads the queue length.
from collections import deque
class RecentCounter:
def __init__(self, window):
self.window = window
self.times = deque()
def add(self, t):
self.times.append(t)
def count(self, t):
while self.times and self.times[0] <= t - self.window:
self.times.popleft()
return len(self.times)
counter = RecentCounter(10)
counter.add(1)
counter.add(5)
print("count at 9:", counter.count(9))
counter.add(12)
print("count at 12:", counter.count(12))
print("count at 30:", counter.count(30))Example
import heapq
from collections import deque
def kth_smallest(a, b, k):
if len(a) > len(b):
a, b = b, a
lo = max(0, k - len(b))
hi = min(k, len(a))
while lo <= hi:
i = (lo + hi) // 2
j = k - i
left_a = a[i - 1] if i > 0 else float("-inf")
right_a = a[i] if i < len(a) else float("inf")
left_b = b[j - 1] if j > 0 else float("-inf")
right_b = b[j] if j < len(b) else float("inf")
if left_a <= right_b and left_b <= right_a:
return max(left_a, left_b)
if left_a > right_b:
hi = i - 1
else:
lo = i + 1
return None
def min_merge(piles):
n = len(piles)
prefix = [0]
for p in piles:
prefix.append(prefix[-1] + p)
dp = [[0] * n for _ in range(n)]
for length in range(2, n + 1):
for i in range(n - length + 1):
j = i + length - 1
cost = prefix[j + 1] - prefix[i]
dp[i][j] = min(dp[i][m] + dp[m + 1][j] for m in range(i, j)) + cost
return dp[0][n - 1]
def cheapest_with_coupon(roads, start, goal):
dist = {(start, False): 0}
heap = [(0, start, False)]
while heap:
cost, node, used = heapq.heappop(heap)
if cost > dist.get((node, used), float("inf")):
continue
if node == goal:
return cost
for nxt, w in roads[node]:
if cost + w < dist.get((nxt, used), float("inf")):
dist[(nxt, used)] = cost + w
heapq.heappush(heap, (cost + w, nxt, used))
if not used and cost < dist.get((nxt, True), float("inf")):
dist[(nxt, True)] = cost
heapq.heappush(heap, (cost, nxt, True))
return None
class RecentCounter:
def __init__(self, window):
self.window = window
self.times = deque()
def add(self, t):
self.times.append(t)
def count(self, t):
while self.times and self.times[0] <= t - self.window:
self.times.popleft()
return len(self.times)
passed = 0
total_cases = 0
def report(family, case, expected, got):
global passed, total_cases
total_cases += 1
ok = got == expected
if ok:
passed += 1
print(family, "case", case, "| expected", expected, "| got", got,
"|", "PASS" if ok else "FAIL")
for idx, (a, b, k, expected) in enumerate([
([1, 4, 9, 12], [2, 3, 8], 5, 8),
([5, 6, 7], [1, 2], 2, 2),
([], [4, 9], 2, 9)], start=1):
report("P1 kth across two sorted lists", idx, expected, kth_smallest(a, b, k))
for idx, (piles, expected) in enumerate([
([4, 2, 3], 14),
([1, 2, 3, 4], 19),
([5, 5], 10)], start=1):
report("P2 cheapest merge of piles", idx, expected, min_merge(piles))
roads_one = {
"A": [("B", 9), ("C", 2)],
"B": [("D", 2)],
"C": [("B", 3), ("D", 7)],
"D": [],
}
roads_two = {
"X": [("Y", 4), ("W", 3)],
"Y": [("Z", 6)],
"W": [("Z", 9)],
"Z": [],
}
report("P3 cheapest route, one free road", 1, 2,
cheapest_with_coupon(roads_one, "A", "D"))
report("P3 cheapest route, one free road", 2, 3,
cheapest_with_coupon(roads_two, "X", "Z"))
counter = RecentCounter(10)
counter.add(1)
counter.add(5)
results = [counter.count(9)]
counter.add(12)
results.append(counter.count(12))
results.append(counter.count(30))
report("P4 recent event counter", 1, [2, 2, 0], results)
print("SCORECARD:", passed, "of", total_cases, "cases passed")
print("RUBRIC binary search: a strong run states the partition invariant before coding.")
print("RUBRIC interval DP: a strong run fills ranges from short ranges to long ones.")
print("RUBRIC graph composition: a strong run names the doubled state before searching.")
print("RUBRIC design: a strong run states the cost of each operation before coding.")
print("HONESTY: every verdict above came from running this code, not from memory.")
print("COMPLEXITY: kth O(log n), merge O(n^3), coupon search O(E log V), counter O(1) amortised.")Key points
- One program solves four hard problems under interview conditions.
- The first problem finds the kth value across two sorted lists by binary search.
- Interval DP is dynamic programming whose state is a range of the input.
- The second problem prices pile merges over ranges with interval DP.
- A coupon is a token that makes one chosen road free.
- The third problem runs Dijkstra over towns paired with the coupon state.
- The fourth problem counts recent events with a queue that drops old timestamps.
- Every case prints its expected value, its got value, and its verdict.
In this example, the gauntlet runs all four problems as tested functions in one program. The stated budgets were ten minutes for the binary search problem. The interval DP problem had twelve minutes. The graph problem had twelve minutes. The design problem had eight minutes. Problem one found the kth value across two sorted lists three times. Its cases covered a middle value, a value in the shorter list, and an empty list. Problem two priced the cheapest merge for three rows of piles. Problem three ran Dijkstra over doubled states and spent the coupon on the best road each time. Problem four drove the recent event counter through one fixed script of adds and counts. The scorecard printed 9 of 9 cases passed. The rubric then printed one line per family, plus an honesty line and a complexity line. Every technique in this program was taught earlier in this course.
Note
All four problems use original wording and original fixed data.
Try it Yourself
Edit the code, then press Run.
Running is simulated ยท Python Playground
Exercise
In problem three, what extra fact does each search state carry besides the town?