Solution

ID: past-exam-of-the-year-1-of-the-computer-science-course-of-the-university-of-oxford/2016/functional-programming-design-and-analysis-of-algorithms/5/d/solution

Maintain an inclusive interval with these recursion invariants: if , then ; if , then . The original full interval satisfies both conditions vacuously.
LocalMaximum(A):
    require length(A) >= 1
    return Peak(0, length(A)-1)

Peak(lo, hi):
    m = floor((lo+hi)/2)
    if m > lo and A[m-1] > A[m]:
        return Peak(lo, m-1)
    if m < hi and A[m+1] > A[m]:
        return Peak(m+1, hi)
    return m
In the left-recursion branch, the new right endpoint satisfies and the old left boundary is retained. The right-recursion branch is symmetric. Thus both recursion invariants persist.
If neither branch is taken, exceeds its neighbours within the current interval because all entries are distinct. If is an endpoint of that interval and there is a neighbour outside, the boundary recursion invariant supplies the missing strict inequality. Hence the returned index is an array local maximum with respect to the original array, not just the restricted interval. Every branch shortens the interval, so termination is guaranteed; this also establishes existence, including the singleton case.
Each call performs at most two comparisons, and a recursive interval has at most half as many elements, up to rounding. Thus and
The conventional bound is for , with constant work for a singleton. Distinctness is essential to this proof of a strict local maximum.

New to topics? Read the docs here!