public int findMin(int[] nums) { int l = 0; int r = nums.length - 1; while (l < r) { // the min is always in [l, r] int m = l + (r - l) / 2; if (nums[m] > nums[r]) { l = m + 1; // the drop is right of m } else { r = m; // m..r rises; m may be the min } } return nums[l];}
- l
- —
- r
- —
- m
- —
- nums[m]
- —
- nums[r]
- —
Why it works
- A linear scan finds the min in O(n), or finds the one place where a value is smaller than the one before it. Neither uses the fact that both pieces are sorted.
- Compare the middle with the right end. If
nums[m] > nums[r], the values must drop somewhere afterm, and the min is that drop: it lies in[m+1, r]. Otherwisem..rrises steadily, so nothing right ofmbeatsnums[m]: keep[l, m]. Invariant: the min is always inside[l, r]. - O(log n) time, O(1) space. Each comparison throws away about half of
[l, r]; the loop stops when one cell remains, and that cell is the min. - Pitfall:
r = m, notm - 1. In the rising casenums[m]may be the min itself, so it must stay. That is also why the loop runs whilel < r: withl <= randr = mit never ends. Comparing withnums[l]instead fails on an array that is not rotated. - Related: Search in Rotated Sorted Array (33) uses the same "one side is sorted" test to find a target. With duplicates (154),
nums[m] == nums[r]tells you nothing, so droprby one; the worst case becomes O(n).