Search in Rotated Sorted Array takes the comfortable world of binary search and tilts it. The array is still sorted — it has just been rotated at some unknown point. The trick is realizing that half of it is always still sorted, and binary search can live in that half.
Problem. A sorted array was rotated at some unknown pivot (for example [0,1,2,4,5,6,7] became
[4,5,6,7,0,1,2]). Given the rotated array nums (no duplicates) and a target, return the index
of target, or -1 if it is not present. Do it in O(log n) time.
Example: nums = [4, 5, 6, 7, 0, 1, 2], target = 0 → answer 4 (because nums[4] = 0).
The slow way first
You could scan every element and compare it to the target. That finds the answer, but it is O(n) — it ignores all the sortedness we were handed. The problem explicitly asks for O(log n), which is a giant hint: use binary search.
The catch: plain binary search needs a fully sorted array. After rotation, comparing the target to nums[mid] no longer tells us which way to go, because the array dips down at the pivot.
The idea: one half is always sorted
Here is the key observation. Pick any mid. The pivot can only be on one side of it, which means the other side is perfectly sorted. So at every step:
- Compute
mid. Ifnums[mid] == target, done. - Figure out which half is sorted by comparing
nums[lo]withnums[mid]. - In that sorted half, a normal range check tells us whether the target lives there.
- Keep the half that could contain the target; throw away the other.
Because we still halve the search space every step, the whole thing stays O(log n).
Walk through it
Step through the animation with nums = [4,5,6,7,0,1,2], target = 0. First mid = 3 (value 7): the left half [4,5,6,7] is sorted, but 0 is not inside [4,7], so we move lo past mid. Next mid = 5 (value 1): the left half [0,1] is sorted and 0 is inside [0,1], so we move hi left. Finally mid = 4 (value 0) matches — we return index 4. Three probes, not seven.
Pseudocode
lo, hi = 0, last index
while lo <= hi:
mid = (lo + hi) // 2
if nums[mid] == target: return mid
if the left half (lo..mid) is sorted: # nums[lo] <= nums[mid]
if target is in [nums[lo], nums[mid]): hi = mid - 1
else: lo = mid + 1
else: # right half (mid..hi) is sorted
if target is in (nums[mid], nums[hi]]: lo = mid + 1
else: hi = mid - 1
return -1The Python solution
def search(nums, target):
lo, hi = 0, len(nums) - 1
while lo <= hi:
mid = (lo + hi) // 2
if nums[mid] == target:
return mid
if nums[lo] <= nums[mid]: # left half sorted
if nums[lo] <= target < nums[mid]:
hi = mid - 1
else:
lo = mid + 1
else: # right half sorted
if nums[mid] < target <= nums[hi]:
lo = mid + 1
else:
hi = mid - 1
return -1nums[lo] <= nums[mid]is the heart of it: if true, the left half is sorted; otherwise the right half is.- Once we know which half is sorted, we use an ordinary range check on its endpoints to decide if the target is inside it.
- The boundaries are exclusive on the
midside (target < nums[mid],nums[mid] < target) becausenums[mid]was already tested for equality above. - Each branch discards half the array, so we loop at most about
log2(n)times.
Complexity
| Case | Time | Notes |
|---|---|---|
| Linear scan | O(n) (moderate) | ignores the sortedness |
| Modified binary search | O(log n) (fast) | halve the range each step |
O(1) (fast)We do constant extra work and use no extra memory — just three indices that close in on the answer.
When this pattern shows up
Whenever an array is sorted "but with a twist" (rotated, or you must find a pivot / minimum / a peak),
think binary search with an extra decision at mid. The move is always: identify the half that obeys a
clean ordering, range-check the target there, and discard the other half.
Get the range bounds right. Because nums[mid] is already checked for equality, the sorted-half range
must be half-open (nums[lo] <= target < nums[mid]). Using <= on the mid side can send you into the
wrong half and miss the answer.
Practice
nums = [4,5,6,7,0,1,2], target = 0. After the first probe at mid = 3 (value 7), which half is sorted and which way does lo or hi move?
1. Why can we still use binary search on a rotated sorted array?
2. How do we tell which half is the sorted one?
3. Why is the range check on the mid side exclusive (target < nums[mid])?
4. What is the time complexity of this solution?