Find Minimum in Rotated Sorted Array
A sorted array of distinct values has been rotated some unknown number of times. Return its minimum element in O(log n).
- n == nums.length
- 1 <= n <= 5000
- -5000 <= nums[i] <= 5000
- All the integers of nums are unique.
- nums is sorted and rotated between 1 and n times.
Intuition
Find minimum in rotated sorted array locates the smallest value in a sorted array that has been rotated an unknown number of times. Values are distinct, and the required O(log n) rules out a linear scan.
Rotation leaves a specific structure: the array is two sorted runs, with the minimum at the start of the second. That element is also the single point where an element is smaller than its predecessor — the rotation point.
Ordinary binary search compares against a target, but there is no target here. The comparison that works instead is between mid and the right end:
- If nums[mid] > nums[right], the rotation point lies to the right of mid; otherwise mid could itself be the minimum.
The reasoning is direct. A middle element larger than the rightmost means mid sits in the first, higher run, so the minimum must be further right — move left = mid + 1, safely excluding mid. Otherwise mid is in the second run and might be the minimum itself, so move right = mid, keeping it as a candidate.
Comparing against nums[left] instead is the classic error. It cannot distinguish a rotated array from an unrotated one, because in both cases the middle can exceed the left element.
The loop runs while left < right, converging when the two meet. No separate check for an unrotated array is needed: if the array was never rotated, every comparison sends the search left and it lands on index 0 correctly.
With duplicates allowed the comparison breaks down, and the worst case degrades to O(n) — that is Find Minimum in Rotated Sorted Array II.
Compare nums[mid] to nums[hi], never to nums[lo]. If the midpoint exceeds the right end, the rotation point lies strictly to the right; otherwise the minimum is at or left of mid. Anchoring on the right end is what makes the two cases unambiguous.
Approach
Before reading on: price up what the direct approach costs here, then ask what property lets you throw away half the range after one comparison. Aim for O(log n) time and O(1) space.
Identify the structure
A rotated array is two sorted runs, and the minimum is the first element of the second run — the one point where an element is smaller than its predecessor.
Compare against the right end
There is no target to search for, so compare nums[mid] with nums[right]. This comparison is what distinguishes the two runs.
Move right when mid is larger
nums[mid] > nums[right] puts mid in the first, higher run, so the minimum lies further right. Set left = mid + 1, safely excluding mid.
Keep mid when it is smaller
Otherwise mid sits in the second run and could itself be the minimum, so set right = mid rather than mid - 1 — excluding it would discard the answer.
Avoid comparing with the left end
Comparing against nums[left] is the classic error. It cannot separate a rotated array from an unrotated one, since the middle exceeds the left element in both.
Converge without a special case
Loop while left < right. An unrotated array sends every comparison left and lands on index 0, so no separate check for zero rotation is needed.
Cost of the search
The range halves each step, giving O(log n) time and O(1) space. Duplicates break the comparison and degrade the worst case to O(n) — that is the follow-up problem.
Solution & live demo
Common pitfalls
Comparing against nums[lo]
if nums[mid] > nums[lo]:
if nums[mid] > nums[hi]:
On an unrotated array nums[mid] > nums[lo] holds while the minimum is at lo, sending the search the wrong way. The right-end comparison is unambiguous in both the rotated and unrotated cases.
Excluding mid when searching left
else:
hi = mid - 1else:
hi = midmid itself can be the minimum — on [3, 4, 5, 1, 2] the search lands on index 3 exactly. Dropping it loses the answer and returns a neighbouring value.
Using lo <= hi as the loop condition
while lo <= hi:
while lo < hi:
With hi = mid the range never empties, so lo <= hi spins forever once they converge. The lo < hi form terminates exactly when the two meet on the answer.
Edge cases
Every comparison takes the nums[mid] <= nums[hi] branch and hi walks down to 0, returning the first element. This is precisely why the comparison anchors on hi.
The loop never executes and the single element is returned.
The minimum is at index 1 in a two-element view; the standard rule finds it without special handling.
This variant (LC 154) breaks the guarantee: when nums[mid] == nums[hi] neither side can be ruled out. The fix is to decrement hi by one, degrading the worst case to O(n). The distinct-values version here has no such problem.