Exponential & Interpolation Search
Imagine you're looking for a house on a street, but you don't know how long the street is. You start by taking 1 step, then 2 steps, then 4, then 8 — doubling your step size each time — until you overshoot your destination. Now you know the house is somewhere in the last stretch you crossed. You go back to where you started that stretch and do a careful room-by-room search.
That's exponential search. Phase one: double until you overshoot. Phase two: binary search the range you've narrowed down.
Why not just use binary search?
Binary search is perfect when you know the array's size. But sometimes you don't — imagine a stream of sorted data coming in, or an API that lets you access any index but won't tell you how many elements there are. You can't set hi = n - 1 if you don't know n.
Exponential search solves this: it discovers the range by doubling, then searches it. Even better — if your target happens to be near the beginning (say, at position p), you find it in \(O(\log p)\) time, regardless of how enormous the full array is. Binary search would need \(O(\log n)\) where n >> p.
The two phases
Phase 1 — Bounding: Start at index 1. If arr[1] < target, jump to index 2, then 4, then 8, doubling each time. Stop when you find arr[i] >= target or you fall off the end of the array. The target must be in the range [i/2, i].
Phase 2 — Binary search: Run standard binary search on [i/2, min(i, n-1)]. Since this range has size at most i/2 which is at most the target's position, the binary search costs \(O(\log p)\).
Total cost: \(O(\log p)\) for bounding + \(O(\log p)\) for binary search = \(O(\log p)\). For a random target, p ≈ n/2 on average, so this is \(O(\log n)\).