Searching & Sorting · 22 of 36
Find pivot element in a sorted array
A sorted list was turned like a wheel; find the spot where it was turned, where the biggest number is followed by the smallest.
- Simple way
- time O(n)
room O(1) - Clever way
- time O(log n)
room O(1)
The problem, simply
Take a sorted array of different numbers, like [0, 1, 2, 4, 5, 6, 7]. Cut it somewhere and move the front part to the back: [4, 5, 6, 7, 0, 1, 2]. This is a rotated sorted array.
Find the turning point. It is the one place where a number is followed by a smaller one: the biggest number (the pivot) sits right before the smallest. Return the index of the smallest number. That index is also how many times the array was turned, and the pivot is the box just before it. If the array was not turned at all, return 0.
A story to remember it
Picture it
Two climbing runs: 4, 5, 6, 7 and then 0, 1, 2. The drop is between index 3 and index 4. The pivot (biggest) is 7, and the smallest is 0 at index 4.
- done
- answer
- path
Examples
A normal case
- In
[4, 5, 6, 7, 0, 1, 2]- Out
4
The smallest, 0, is at index 4. The pivot 7 is at index 3.
Turned near the end
- In
[3, 4, 5, 1, 2]- Out
3
The drop is from 5 to 1.
Not turned
- In
[1, 2, 3, 4, 5]- Out
0
No drop at all. The smallest is the first box.
Two boxes
- In
[2, 1]- Out
1
The drop is right in the middle.
One box
- In
[9]- Out
0
One box is its own smallest.
Way 1: the simple way
Walk from left to right and look for the drop: the first i where arr[i] < arr[i - 1]. If there is no drop, the array was not turned.
class Solution {
public int findMinIndex(int[] arr) {
for (int i = 1; i < arr.length; i++) {
if (arr[i] < arr[i - 1]) return i; // the drop: smallest is here
}
return 0; // never turned
}
}How long it takes: up to one look per box, O(n). Extra room: O(1).
Way 2: the clever way
Compare the middle box with the last box of the current range. The last box arr[hi] acts like a judge.
lo = 0,hi = n - 1.- While
lo < hi, look atmid. - If
arr[mid] > arr[hi], the numbers must drop somewhere aftermid. The smallest is to the right:lo = mid + 1. - Otherwise
arr[mid] <= arr[hi], so frommidtohithe numbers only climb. The smallest ismidor to its left:hi = mid. Keepmidin the range, it might be the answer. - When
lo == hi, that is the index of the smallest.
Compare the middle with the last box to find the drop
01 / 07
The first box (4) is bigger than the last box (2), so the array was turned. The smallest number is somewhere in between. lo = 0, hi = 6.
- checking
- seen
- done
- answer
- rejected
- ignored
class Solution {
public int findMinIndex(int[] arr) {
int lo = 0, hi = arr.length - 1;
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
if (arr[mid] > arr[hi]) lo = mid + 1; // the drop is to the right of mid
else hi = mid; // mid..hi climbs, smallest is mid or left
}
return lo; // index of the smallest
}
public int findPivotIndex(int[] arr) { // index of the biggest
int m = findMinIndex(arr);
return (m - 1 + arr.length) % arr.length;
}
}How long it takes: the range halves each time, O(log n). Extra room: O(1).
Watch out for
- Writing
hi = mid - 1in the "otherwise" case.miditself might be the smallest, so keep it. - Using
while (lo <= hi)withhi = mid. Whenlo == hithe range never shrinks and the loop runs forever. - Repeated numbers break the rule. With
[3, 3, 1, 3],arr[mid] == arr[hi]tells you nothing. Then shrink withhi--, which isO(n)in the worst case. - Know which answer is asked: the smallest's index (the rotation count) or the biggest's index (the pivot). They are next to each other.
What interviewers ask next
- How many times was the array rotated? It is the smallest's index.
- Search for a target in a rotated array. Find the smallest's index
m, then binary search in[0, m - 1]or[m, n - 1], whichever can hold the target. Or do it in one pass by checking which half is sorted. - With duplicates allowed (LeetCode 154)? When
arr[mid] == arr[hi], dohi--. Worst caseO(n), and no algorithm can do better in the worst case. - Find the peak in a mountain array (goes up, then down)? A similar idea: compare
arr[mid]witharr[mid + 1]and walk toward the higher side.
Remember this
Grown-up words: the turned array is a rotated sorted array, the jump is the rotation point, the biggest number is the pivot, and the smallest's index is the rotation count.