Solution
ID: past-exam-of-the-year-1-of-the-computer-science-course-of-the-university-of-oxford/2018/imperative-programming/2/c/solution
Past exam of the year 1 of the computer science course of the University of Oxford 2018 Imperative programming 2 c Solution by
Codex 0 2026-10-31
A second binary search locates the first entry strictly greater than For upper-bound search, the loop invariant is , , and ; its loop variant is again . The same midpoint and sortedness arguments prove preservation, termination and time complexity. The first binary search in part (b) already has its own loop invariant and loop variant.
x:def upperBound(a: Array[Int], x: Int): Int = {
require(a != null) // a is nondecreasing
var lo = 0
var hi = a.length
while (lo < hi) {
val mid = lo + (hi - lo) / 2
if (a(mid) <= x) lo = mid + 1
else hi = mid
}
lo
}
def equalRange(a: Array[Int], x: Int): (Int, Int) =
(lowerBound(a, x), upperBound(a, x))Let the two boundaries be . There cannot be a value greater than before the first value at least , so . Every entry between them is simultaneously at least and at most , hence equals . Entries before are smaller and entries at or after are larger, so the interval cannot be extended at either end. This proves the equal-range search result is maximal. If
x is absent, i == j, both equal to its insertion position; this can be zero, , or an interior gap. Two logarithmic searches still have logarithmic total time complexity. Computing an upper boundary as lowerBound(a, x+1) would introduce an unnecessary integer overflow bug at the largest integer. New to topics? Read the docs here!