Menu

Earn Premium with Referrals

Invite your friends and earn Premium rewards through our referral program.

See how it works and start inviting friends.

Binary Search in Rotated Array
DSA

Binary Search in Rotated Array

Learn how binary search can be adapted to efficiently search rotated sorted arrays.

A rotated sorted array was originally sorted but shifted at some pivot:

[1, 2, 3, 4, 5, 6]
          ↓ rotate
[4, 5, 6, 1, 2, 3]

The key observation:

At least one half of the array is always sorted.

Focus on recognizing:

Rotated → find the sorted half → decide which half can contain the target


Pattern 1: Search in Rotated Sorted Array

Search in Rotated Sorted Array

Search a rotated sorted array in O(log n). At each mid, one half is guaranteed sorted — check which side the target falls in.

Array: [4,5,6,7,0,1,2], target=0. Left half [4,5,6,7] is sorted. 0 < 4 → search right half.

ARRAY VISUALIZER
Steps
4
0
5
1
6
2
7
3
0
4
1
5
2
6
Press ▶ to animate, or step through manually.
Variables
keys: ← → space F
Pseudocode

                        1
                        lo = 0, hi = n - 1
                      
                        2
                        while lo <= hi:
                      
                        3
                          mid = (lo + hi) / 2
                      
                        4
                          if nums[mid] == target: return mid
                      
                        5
                          left sorted? if yes: check if target in left range
                      
                        6
                          else: right sorted — check if target in right range
                      
public int search(int[] nums, int target) {
    int lo = 0;
    int hi = nums.length - 1;

    while (lo <= hi) {
        int mid = lo + (hi - lo) / 2;

        if (nums[mid] == target) {
            return mid;
        }

        if (nums[lo] <= nums[mid]) {
            // left half is sorted
            if (target >= nums[lo] && target < nums[mid]) {
                hi = mid - 1;
            } else {
                lo = mid + 1;
            }
        } else {
            // right half is sorted
            if (target > nums[mid] && target <= nums[hi]) {
                lo = mid + 1;
            } else {
                hi = mid - 1;
            }
        }
    }

    return -1;
}
def search(nums, target):
    lo, hi = 0, len(nums) - 1

    while lo <= hi:
        mid = lo + (hi - lo) // 2

        if nums[mid] == target:
            return mid

        if nums[lo] <= nums[mid]:
            # left half is sorted
            if nums[lo] <= target < nums[mid]:
                hi = mid - 1
            else:
                lo = mid + 1
        else:
            # right half is sorted
            if nums[mid] < target <= nums[hi]:
                lo = mid + 1
            else:
                hi = mid - 1

    return -1
int search(vector<int>& nums, int target) {
    int lo = 0, hi = (int)nums.size() - 1;

    while (lo <= hi) {
        int mid = lo + (hi - lo) / 2;

        if (nums[mid] == target) return mid;

        if (nums[lo] <= nums[mid]) {
            // left half is sorted
            if (target >= nums[lo] && target < nums[mid])
                hi = mid - 1;
            else
                lo = mid + 1;
        } else {
            // right half is sorted
            if (target > nums[mid] && target <= nums[hi])
                lo = mid + 1;
            else
                hi = mid - 1;
        }
    }

    return -1;
}
function search(nums, target) {
  let lo = 0,
    hi = nums.length - 1;

  while (lo <= hi) {
    const mid = lo + ((hi - lo) >> 1);

    if (nums[mid] === target) return mid;

    if (nums[lo] <= nums[mid]) {
      // left half is sorted
      if (target >= nums[lo] && target < nums[mid]) hi = mid - 1;
      else lo = mid + 1;
    } else {
      // right half is sorted
      if (target > nums[mid] && target <= nums[hi]) lo = mid + 1;
      else hi = mid - 1;
    }
  }

  return -1;
}

Two questions per step: which half is sorted? (nums[lo] <= nums[mid] → left), then is the target inside it?

Pattern 2: Find Minimum

Watch [4,5,6,1,2,3] shrink to its minimum in three probes — every step keeps the minimum inside [lo..hi]. Press to animate.

Minimum in a Rotated Sorted Array

Find the smallest element in a rotated sorted array in O(log n) using binary search. The key insight: the pivot (minimum) is always in the unsorted half of the current range.

Array [4,5,6,1,2,3] was sorted then rotated. Compare mid (6) with the right end (3): if mid > right, the minimum is to the RIGHT of mid (a rotation happened there), so lo = mid+1; otherwise it's to the left or at mid, so hi = mid. The L/R pointers track the live range and we land on the minimum 1.

ARRAY VISUALIZER
Steps
4
0
5
1
6
2
1
3
2
4
3
5
Press ▶ to animate, or step through manually.
Variables
keys: ← → space F
Pseudocode

                        1
                        lo = 0, hi = n - 1
                      
                        2
                        while lo < hi:
                      
                        3
                          mid = (lo + hi) / 2
                      
                        4
                          if nums[mid] > nums[hi]:   // break is RIGHT of mid
                      
                        5
                            lo = mid + 1
                      
                        6
                          else:                      // right half sorted →
                      
                        7
                            hi = mid                 // min is at mid or left of it
                      
                        8
                        return nums[lo]
                      

The minimum sits exactly where the rotation begins:

public int findMin(int[] nums) {
    int lo = 0;
    int hi = nums.length - 1;

    while (lo < hi) {
        int mid = lo + (hi - lo) / 2;

        if (nums[mid] > nums[hi]) {
            lo = mid + 1;      // drop is right of mid
        } else {
            hi = mid;          // min at mid or left of it
        }
    }

    return nums[lo];
}
def find_min(nums):
    lo, hi = 0, len(nums) - 1

    while lo < hi:
        mid = lo + (hi - lo) // 2

        if nums[mid] > nums[hi]:
            lo = mid + 1       # drop is right of mid
        else:
            hi = mid           # min at mid or left of it

    return nums[lo]
int findMin(vector<int>& nums) {
    int lo = 0, hi = (int)nums.size() - 1;

    while (lo < hi) {
        int mid = lo + (hi - lo) / 2;

        if (nums[mid] > nums[hi])
            lo = mid + 1;      // drop is right of mid
        else
            hi = mid;          // min at mid or left of it
    }

    return nums[lo];
}
function findMin(nums) {
  let lo = 0,
    hi = nums.length - 1;

  while (lo < hi) {
    const mid = lo + ((hi - lo) >> 1);

    if (nums[mid] > nums[hi]) lo = mid + 1;
    // drop is right of mid
    else hi = mid; // min at mid or left of it
  }

  return nums[lo];
}

Find Min = compare mid with hi. nums[mid] > nums[hi] means the drop — and the minimum — live strictly right.


Variant: Duplicates

When nums[lo] == nums[mid] == nums[hi], neither half is provably sorted. Shrink both ends:

lo++; hi--;

Worst case degrades to O(n) — unavoidable with heavy duplication.


Common Mistakes

Skipping the sorted-half check.

Deciding where the target lives before knowing which half is sorted is guessing.


Wrong target-range comparisons.

Sorted left: target >= nums[lo] && target < nums[mid]. Sorted right: target > nums[mid] && target <= nums[hi]. Note the asymmetric bounds.


Using lo <= hi for find-min.

The minimum template converges with while (lo < hi) and answers at lo == hi.


Complexity

OperationTime
SearchO(log n)
Find minO(log n)
With duplicatesO(n) worst

My Private Notes

Notes are auto-saved locally to this device.