Find in Mountain Array takes the plain binary-search trick and bends it over a hill. The array is not sorted top to bottom — it climbs to a single peak, then strictly falls. The win is realizing that each side is sorted on its own, so you can binary-search the array three times instead of scanning it.
Problem. A mountain array strictly increases to one peak index, then strictly decreases. Given
such an array arr and a target, return the smallest index whose value equals target, or -1
if it is absent.
Example: arr = [1, 5, 8, 6, 4, 2], target = 6 → answer 3 (the peak is 8 at index 2, and the 6
on the falling side sits at index 3).
The slow way first
The obvious idea is a linear scan: walk every element and compare to the target. That is O(n), and it ignores all the structure the mountain hands us. With a sorted array we would never settle for O(n) — we would binary-search. A mountain is not one sorted array, but it is two of them glued at the peak, so we should still get to O(log n).
The question to ask: can I find the peak quickly, and then binary-search each slope?
The idea: peak, then two halves
Do three binary searches. First, find the peak with a slope search: at mid, compare arr[mid] to arr[mid+1]. If the value is still rising, the peak is to the right; if it is falling, the peak is at mid or to its left. That converges on the summit in O(log n).
Then binary-search the rising side [0..peak] the normal way. If the target is not there, binary-search the falling side [peak+1..n-1] — but with the comparison reversed, because that half decreases.
The key insight: a mountain is two sorted runs. Binary search only needs monotonicity, and each slope has it — you just flip the inequality on the way down.
Walk through it
Step through the animation. Phase 1 slides lo/hi until they meet on the peak at index 2. Phase 2 binary-searches the rising side and fails (8 != 6). Phase 3 searches the falling side with flipped comparisons and lands on index 3, where arr[3] = 6.
Pseudocode
peak = slope-binary-search: at mid, if arr[mid] < arr[mid+1] go right else go left
left = binary-search [0..peak] # ascending: if arr[mid] < target go right
if arr[left] == target: return left
right = binary-search [peak+1..n-1] # descending: if arr[mid] > target go right
if arr[right] == target: return right
return -1The Python solution
def find_in_mountain(arr, target):
n = len(arr)
lo, hi = 0, n - 1
while lo < hi:
mid = (lo + hi) // 2
if arr[mid] < arr[mid + 1]:
lo = mid + 1
else:
hi = mid
peak = lo
lo, hi = 0, peak
while lo < hi:
mid = (lo + hi) // 2
if arr[mid] < target:
lo = mid + 1
else:
hi = mid
if arr[lo] == target:
return lo
lo, hi = peak + 1, n - 1
while lo < hi:
mid = (lo + hi) // 2
if arr[mid] > target:
lo = mid + 1
else:
hi = mid
return lo if arr[lo] == target else -1- The first loop is the slope search:
arr[mid] < arr[mid+1]means we are climbing, so the peak is to the right (lo = mid + 1); otherwise the peak is atmidor left (hi = mid). Whenlo == hi, that index is the peak. - The second loop is an ordinary ascending binary search over
[0..peak]. Ifarr[mid] < target, the answer is to the right. - After it,
arr[lo] == targettells us whether the rising side held the value; if so we return immediately, which also gives the smallest index since the left side comes first. - The third loop is a descending binary search. The comparison flips:
arr[mid] > targetnow means we must go right, because larger values sit on the left of a falling run. - A peak search that touches
mid + 1is safe because the loop maintainslo < hi, somidis never the last index.
Complexity
| Case | Time | Notes |
|---|---|---|
| Linear scan | O(n) (moderate) | ignores the structure |
| Three binary searches | O(log n) (fast) | peak + two halves, each O(log n) |
O(1) (fast)Each phase halves its range, so the total is three logarithms, which is still O(log n). We use only a handful of index variables, so the extra space is O(1).
When this pattern shows up
Binary search is not just for fully sorted arrays — it works on any monotonic condition. Rotated arrays, mountain arrays, and "find the boundary where a predicate flips" problems all reduce to: find the pivot, then binary-search the monotonic pieces.
On the falling side you must reverse the comparison. If you copy the ascending search verbatim, it walks the wrong direction and misses the target. Decide which way values grow on each slope before you write the inequality.
Practice
The peak of [1, 5, 8, 6, 4, 2] is index 2. After the ascending search on [0..2] fails to find 6, which range does phase 3 search, and which way does its comparison point?
1. How does the slope search decide which way to move?
2. Why does the search on the falling side flip its comparison?
3. What is the overall time complexity?
4. Why search the ascending (left) side before the descending side?