LeetCode #153 Medium

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).

Constraints
  • 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.
binary-searcharray
Open on LeetCode ↗
02

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.

How to spot this pattern

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.

03

Approach

Try it first

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.

1

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.

2

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.

3

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.

4

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.

5

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.

6

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.

7

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.

04

Solution & live demo

▶1class Solution:
▶2 def findMin(self, nums):
▶3 lo, hi = 0, len(nums) - 1
▶4 while lo < hi:
▶5 mid = (lo + hi) // 2
▶6 if nums[mid] > nums[hi]:
▶7 lo = mid + 1
▶8 else:
▶9 hi = mid
▶10 return nums[lo]
05

Common pitfalls

Comparing against nums[lo]

✗ Wrong
if nums[mid] > nums[lo]:
✓ Right
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

✗ Wrong
else:
    hi = mid - 1
✓ Right
else:
    hi = mid

mid 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

✗ Wrong
while lo <= hi:
✓ Right
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.

06

Edge cases

Array not rotated at all, e.g. [1,2,3,4]

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.

Array of length 1

The loop never executes and the single element is returned.

Rotated by exactly n-1 positions

The minimum is at index 1 in a two-element view; the standard rule finds it without special handling.

Duplicate values

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.

07

Complexity

Time
O(log n)
Space
O(1)
One comparison per halving. Scanning for the drop is O(n).