Facebook Pixel

153. Find Minimum in Rotated Sorted Array

Problem Description

You are given an array that was originally sorted in ascending order, but has been rotated between 1 and n times (where n is the length of the array).

A rotation means taking the last element and moving it to the front. For example:

  • Original array: [0,1,2,4,5,6,7]
  • After 1 rotation: [7,0,1,2,4,5,6]
  • After 4 rotations: [4,5,6,7,0,1,2]
  • After 7 rotations: [0,1,2,4,5,6,7] (back to original)

Your task is to find and return the minimum element in this rotated sorted array.

Key requirements:

  • All elements in the array are unique (no duplicates)
  • Your algorithm must run in O(log n) time complexity

The solution uses binary search to efficiently find the minimum element. The key insight is that in a rotated sorted array, the minimum element is at the "pivot point" where the rotation occurred. The algorithm compares elements with nums[0] to determine which half of the array contains the pivot point:

  • If nums[0] <= nums[-1], the array is not rotated (or rotated n times), so the minimum is nums[0]
  • Otherwise, use binary search to find where the rotation break occurs by checking if nums[mid] is greater than or equal to nums[0] to decide which half to search next
Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

When we look at a rotated sorted array, we can observe a key pattern: the array can be divided into two sorted portions. For example, in [4,5,6,7,0,1,2], we have [4,5,6,7] and [0,1,2] - both sorted, but there's a "break" between them where the values drop from 7 to 0.

The minimum element will always be at this break point - specifically, it's the first element of the second sorted portion.

Since we need O(log n) time complexity, we can't scan through the entire array. This constraint immediately suggests binary search.

The challenge is: how do we know which half to search? Here's the key insight - we can use the first element nums[0] as a reference point:

  1. If the array hasn't been rotated (or rotated exactly n times), then nums[0] <= nums[-1], and nums[0] is already the minimum.

  2. If the array is rotated, then nums[0] belongs to the "upper" sorted portion (the larger values). Any element in this upper portion will be >= nums[0], while elements in the "lower" sorted portion will be < nums[0].

  3. During binary search, when we look at nums[mid]:

    • If nums[mid] >= nums[0], then mid is in the upper portion, so the minimum must be to the right (set left = mid + 1)
    • If nums[mid] < nums[0], then mid is in the lower portion where the minimum exists, but mid itself could be the minimum (set right = mid)

This way, we progressively narrow down to the exact point where the rotation break occurs, which is where our minimum element resides.

Solution Approach

Let's walk through the implementation step by step:

Step 1: Check if the array is rotated

if nums[0] <= nums[-1]:
    return nums[0]

First, we check if the first element is less than or equal to the last element. If true, the array hasn't been rotated (or has been rotated exactly n times back to its original position), so the minimum is simply nums[0].

Step 2: Initialize binary search pointers

left, right = 0, len(nums) - 1

We set up two pointers for binary search - left starting at index 0 and right at the last index.

Step 3: Binary search loop

while left < right:
    mid = (left + right) >> 1

We continue searching while left < right. The middle index is calculated using bit shift operation >> 1 (equivalent to dividing by 2), which is slightly more efficient than (left + right) // 2.

Step 4: Determine which half contains the minimum

if nums[0] <= nums[mid]:
    left = mid + 1
else:
    right = mid

This is the core logic:

  • If nums[0] <= nums[mid], it means mid is in the upper sorted portion (before the rotation break). The minimum must be in the right half, so we move left to mid + 1.
  • If nums[0] > nums[mid], it means mid is in the lower sorted portion (after the rotation break). The minimum could be at mid itself or to its left, so we set right = mid (not mid - 1 to preserve the potential minimum).

Step 5: Return the result

return nums[left]

When the loop exits (left == right), both pointers converge at the minimum element's position.

Time Complexity: O(log n) - We eliminate half of the search space in each iteration. Space Complexity: O(1) - We only use a constant amount of extra space for the pointers.

Ready to land your dream job?

Unlock your dream job with a 3-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's trace through the algorithm with the array [4,5,6,7,0,1,2].

Initial Check:

  • nums[0] = 4 and nums[-1] = 2
  • Since 4 > 2, the array is rotated, so we proceed with binary search

Binary Search Process:

Iteration 1:

  • left = 0, right = 6
  • mid = (0 + 6) >> 1 = 3
  • nums[mid] = nums[3] = 7
  • Compare: nums[0] = 4 <= nums[3] = 7
  • This means index 3 is in the upper sorted portion [4,5,6,7]
  • The minimum must be to the right of mid
  • Update: left = mid + 1 = 4

Iteration 2:

  • left = 4, right = 6
  • mid = (4 + 6) >> 1 = 5
  • nums[mid] = nums[5] = 1
  • Compare: nums[0] = 4 <= nums[5] = 1
  • This means index 5 is in the lower sorted portion [0,1,2]
  • The minimum could be at mid or to its left
  • Update: right = mid = 5

Iteration 3:

  • left = 4, right = 5
  • mid = (4 + 5) >> 1 = 4
  • nums[mid] = nums[4] = 0
  • Compare: nums[0] = 4 <= nums[4] = 0
  • Index 4 is in the lower sorted portion
  • The minimum could be at mid itself
  • Update: right = mid = 4

Termination:

  • left = 4, right = 4 (converged)
  • Return nums[4] = 0

The algorithm correctly identifies that the minimum element 0 is at index 4, which is exactly where the rotation break occurs (between 7 and 0).

Solution Implementation

1class Solution:
2    def findMin(self, nums: List[int]) -> int:
3        # If array is not rotated or has only one element, first element is minimum
4        if nums[0] <= nums[-1]:
5            return nums[0]
6      
7        # Initialize binary search boundaries
8        left, right = 0, len(nums) - 1
9      
10        # Binary search to find the rotation point (minimum element)
11        while left < right:
12            # Calculate middle index using bit shift (equivalent to // 2)
13            mid = (left + right) >> 1
14          
15            # If mid element is greater than or equal to first element,
16            # the minimum must be in the right half (after rotation point)
17            if nums[0] <= nums[mid]:
18                left = mid + 1
19            # Otherwise, the minimum is in the left half (including mid)
20            else:
21                right = mid
22      
23        # When left == right, we've found the minimum element
24        return nums[left]
25
1class Solution {
2    /**
3     * Finds the minimum element in a rotated sorted array.
4     * Uses binary search to find the pivot point where the rotation occurs.
5     * 
6     * @param nums - rotated sorted array (may not be rotated)
7     * @return the minimum element in the array
8     */
9    public int findMin(int[] nums) {
10        int n = nums.length;
11      
12        // If array is not rotated (first element <= last element), 
13        // the minimum is the first element
14        if (nums[0] <= nums[n - 1]) {
15            return nums[0];
16        }
17      
18        // Binary search to find the rotation point
19        int left = 0;
20        int right = n - 1;
21      
22        while (left < right) {
23            // Calculate middle index using bit shift (equivalent to (left + right) / 2)
24            int mid = (left + right) >> 1;
25          
26            // If middle element is greater than or equal to first element,
27            // the minimum must be in the right half
28            if (nums[0] <= nums[mid]) {
29                left = mid + 1;
30            } else {
31                // Otherwise, the minimum is in the left half (including mid)
32                right = mid;
33            }
34        }
35      
36        // When left == right, we've found the minimum element
37        return nums[left];
38    }
39}
40
1class Solution {
2public:
3    int findMin(vector<int>& nums) {
4        int n = nums.size();
5      
6        // If array is not rotated (first element <= last element), minimum is at index 0
7        if (nums[0] <= nums[n - 1]) {
8            return nums[0];
9        }
10      
11        // Binary search to find the rotation point (minimum element)
12        int left = 0;
13        int right = n - 1;
14      
15        while (left < right) {
16            // Calculate middle index using bit shift (equivalent to dividing by 2)
17            int mid = (left + right) >> 1;
18          
19            // If mid element is in the left sorted portion (greater than or equal to first element),
20            // the minimum must be in the right half
21            if (nums[0] <= nums[mid]) {
22                left = mid + 1;
23            }
24            // Otherwise, the minimum is in the left half (including mid itself)
25            else {
26                right = mid;
27            }
28        }
29      
30        // After the loop, left points to the minimum element
31        return nums[left];
32    }
33};
34
1/**
2 * Finds the minimum element in a rotated sorted array
3 * Uses binary search to achieve O(log n) time complexity
4 * @param nums - The rotated sorted array
5 * @returns The minimum element in the array
6 */
7function findMin(nums: number[]): number {
8    // Initialize left pointer to the start of array
9    let left: number = 0;
10  
11    // Initialize right pointer to the end of array
12    let right: number = nums.length - 1;
13  
14    // Continue searching while the search space has more than one element
15    while (left < right) {
16        // Calculate middle index using unsigned right shift to avoid overflow
17        // Equivalent to Math.floor((left + right) / 2)
18        const mid: number = (left + right) >>> 1;
19      
20        // If middle element is greater than rightmost element,
21        // the minimum must be in the right half (after mid)
22        if (nums[mid] > nums[right]) {
23            left = mid + 1;
24        } else {
25            // Otherwise, the minimum is in the left half (including mid)
26            // or mid itself could be the minimum
27            right = mid;
28        }
29    }
30  
31    // When left equals right, we've found the minimum element
32    return nums[left];
33}
34

Time and Space Complexity

Time Complexity: O(log n), where n is the length of the input array nums.

The algorithm uses binary search to find the minimum element in a rotated sorted array. In each iteration of the while loop, the search space is reduced by half. The number of iterations is logarithmic with respect to the array size, as we divide the search range by 2 in each step until left >= right. The initial check if nums[0] <= nums[-1] takes O(1) time, and all operations inside the loop (comparison and index calculations) are O(1). Therefore, the overall time complexity is O(log n).

Space Complexity: O(1)

The algorithm uses only a constant amount of extra space. It maintains three integer variables (left, right, and mid) regardless of the input size. No additional data structures are created, and the algorithm operates directly on the input array without recursion (which would use stack space). Thus, the space complexity is constant.

Common Pitfalls

1. Incorrect Boundary Update When Moving Right Pointer

The Pitfall: A common mistake is setting right = mid - 1 instead of right = mid when nums[0] > nums[mid]:

# INCORRECT
if nums[0] <= nums[mid]:
    left = mid + 1
else:
    right = mid - 1  # Wrong! Could skip the minimum

Why This Fails: When nums[0] > nums[mid], the element at mid could actually be the minimum itself. By setting right = mid - 1, we might exclude the minimum from our search range.

Example: For array [4,5,1,2,3]:

  • mid = 2, nums[mid] = 1
  • Since nums[0] = 4 > nums[mid] = 1, we know minimum is in left half
  • But nums[mid] = 1 IS the minimum! Setting right = mid - 1 would skip it

Solution: Always use right = mid to preserve the potential minimum:

if nums[0] <= nums[mid]:
    left = mid + 1
else:
    right = mid  # Correct: keeps mid in search range

2. Comparing with Wrong Reference Point

The Pitfall: Using nums[left] instead of nums[0] as the reference for comparison:

# INCORRECT
if nums[left] <= nums[mid]:  # Wrong reference point!
    left = mid + 1
else:
    right = mid

Why This Fails: As left changes during the search, nums[left] no longer represents the start of the rotated array. This breaks the logic for determining which half contains the rotation point.

Example: For array [4,5,6,7,0,1,2]:

  • Initially: left = 0, mid = 3, nums[left] = 4 <= nums[mid] = 7
  • After update: left = 4, mid = 5, nums[left] = 0 <= nums[mid] = 1
  • This would incorrectly move left to 6, missing the minimum at index 4

Solution: Always compare with the fixed reference nums[0]:

if nums[0] <= nums[mid]:  # Correct: fixed reference point
    left = mid + 1
else:
    right = mid

3. Forgetting Edge Cases

The Pitfall: Not handling arrays with single element or unrotated arrays:

# INCORRECT - jumps straight to binary search
def findMin(self, nums: List[int]) -> int:
    left, right = 0, len(nums) - 1
    while left < right:
        # ... binary search logic

Why This Fails:

  • Single element arrays would work but are inefficient
  • Unrotated arrays would unnecessarily go through binary search when the answer is simply nums[0]

Solution: Add the initial check:

if nums[0] <= nums[-1]:
    return nums[0]

This handles both unrotated arrays and single-element arrays efficiently in O(1) time.

Discover Your Strengths and Weaknesses: Take Our 3-Minute Quiz to Tailor Your Study Plan:

What's the output of running the following function using input [30, 20, 10, 100, 33, 12]?

1def fun(arr: List[int]) -> List[int]:
2    import heapq
3    heapq.heapify(arr)
4    res = []
5    for i in range(3):
6        res.append(heapq.heappop(arr))
7    return res
8
1public static int[] fun(int[] arr) {
2    int[] res = new int[3];
3    PriorityQueue<Integer> heap = new PriorityQueue<>();
4    for (int i = 0; i < arr.length; i++) {
5        heap.add(arr[i]);
6    }
7    for (int i = 0; i < 3; i++) {
8        res[i] = heap.poll();
9    }
10    return res;
11}
12
1class HeapItem {
2    constructor(item, priority = item) {
3        this.item = item;
4        this.priority = priority;
5    }
6}
7
8class MinHeap {
9    constructor() {
10        this.heap = [];
11    }
12
13    push(node) {
14        // insert the new node at the end of the heap array
15        this.heap.push(node);
16        // find the correct position for the new node
17        this.bubble_up();
18    }
19
20    bubble_up() {
21        let index = this.heap.length - 1;
22
23        while (index > 0) {
24            const element = this.heap[index];
25            const parentIndex = Math.floor((index - 1) / 2);
26            const parent = this.heap[parentIndex];
27
28            if (parent.priority <= element.priority) break;
29            // if the parent is bigger than the child then swap the parent and child
30            this.heap[index] = parent;
31            this.heap[parentIndex] = element;
32            index = parentIndex;
33        }
34    }
35
36    pop() {
37        const min = this.heap[0];
38        this.heap[0] = this.heap[this.size() - 1];
39        this.heap.pop();
40        this.bubble_down();
41        return min;
42    }
43
44    bubble_down() {
45        let index = 0;
46        let min = index;
47        const n = this.heap.length;
48
49        while (index < n) {
50            const left = 2 * index + 1;
51            const right = left + 1;
52
53            if (left < n && this.heap[left].priority < this.heap[min].priority) {
54                min = left;
55            }
56            if (right < n && this.heap[right].priority < this.heap[min].priority) {
57                min = right;
58            }
59            if (min === index) break;
60            [this.heap[min], this.heap[index]] = [this.heap[index], this.heap[min]];
61            index = min;
62        }
63    }
64
65    peek() {
66        return this.heap[0];
67    }
68
69    size() {
70        return this.heap.length;
71    }
72}
73
74function fun(arr) {
75    const heap = new MinHeap();
76    for (const x of arr) {
77        heap.push(new HeapItem(x));
78    }
79    const res = [];
80    for (let i = 0; i < 3; i++) {
81        res.push(heap.pop().item);
82    }
83    return res;
84}
85

Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More