HARD Lab · Binary Search · 09

33. Search in Rotated Sorted Array

A sorted array rotated at an unknown pivot always has one sorted half — identify it first, then check if the target lies within it to halve the search space, achieving O(log n) even without knowing where the rotation is.

MediumBinary SearchTypeScript

PROBLEM What we're solving

Given a sorted array of distinct integers rotated at some pivot (e.g. [4,5,6,7,0,1,2]), find the index of target in O(log n) time, or return -1 if it is not present. For example, nums=[4,5,6,7,0,1,2], target=0 4; target=3 -1.

KEY IDEA One half is always fully sorted

Insight → even after rotation, splitting at mid always leaves at least one half that is contiguously sorted. Compare nums[lo] with nums[mid]: if nums[lo] ≤ nums[mid], the left half is sorted; otherwise the right half is sorted. Once you know which half is sorted, a simple range check tells you whether target lives there — if yes, search that half; if no, search the other.

RECIPE Sorted-half binary search

  • 0 · Standard setup. lo=0, hi=n-1. Loop while lo ≤ hi.
  • 1 · Check mid. If nums[mid] === target return mid.
  • 2 · Identify the sorted half. nums[lo] ≤ nums[mid] → left half is sorted; otherwise right half is sorted.
  • 3 · Range-check target against the sorted half.If target is inside the sorted half's range, move the pointer to search that half; otherwise move the other pointer to search the unsorted half.
  • 4 · Exhausted? Return -1. Loop ends without a match.
Classic confusion → using < instead of when checking nums[lo] ≤ nums[mid]. When lo === mid (two-element window) you must treat the left half as sorted. The = is load-bearing.

COST Complexity & alternatives

Linear scan
O(n)
Ignore the structure; iterate every element.
Sorted-half binary search
O(log n)
O(1) space; exploits at-least-one-sorted-half invariant.

The rotation does not change the search space halving — we eliminate half the elements at every step just as in regular binary search. Space is O(1): only two pointers.

Pattern transfer →this "identify sorted half first" logic extends directly to Search in Rotated Sorted Array II (with duplicates — the tricky case when nums[lo] === nums[mid] forces a linear fallback) and Find Minimum in Rotated Sorted Array (find the pivot instead of a target).

RUN IT Find the sorted half first, then decide

step 0 / 5
STARTSearch for 0 in rotated array [4, 5, 6, 7, 0, 1, 2]. Set lo=0, hi=6.
nums40516273041526
State
0
lo
6
hi
0
target
lomidhifoundnot found
slowfast

TYPESCRIPT The solution, annotated

searchRotated.ts
function search(nums: number[], target: number): number {
  let lo = 0;
  let hi = nums.length - 1;

  while (lo <= hi) {
    const mid = Math.floor((lo + hi) / 2);
    if (nums[mid] === target) return mid;

    // Determine which half is sorted
    if (nums[lo] <= nums[mid]) {
      // Left half [lo..mid] is sorted
      if (nums[lo] <= target && target < nums[mid]) {
        hi = mid - 1;   // target in left sorted half
      } else {
        lo = mid + 1;   // target must be in right half
      }
    } else {
      // Right half [mid..hi] is sorted
      if (nums[mid] < target && target <= nums[hi]) {
        lo = mid + 1;   // target in right sorted half
      } else {
        hi = mid - 1;   // target must be in left half
      }
    }
  }

  return -1;
}

Reading it block by block

Lines 2–3 — initialise pointers. Standard binary search setup: lo=0, hi=n-1, loop while the window is non-empty.
Line 6 — early return. If nums[mid] is the target we are done. Always check this before the sorted-half logic.
Line 9 — identify the sorted half. nums[lo] ≤ nums[mid] means the left half has no wraparound — it is fully ascending. The = is essential: when the window is two elements, lo === mid and we must count the left half as sorted.
Lines 10–13 — target in sorted left half? Check if target falls in [nums[lo], nums[mid]). If yes, cut the right half away (hi = mid - 1); otherwise the target must be right of the pivot (lo = mid + 1).
Lines 15–20 — right half is sorted. Mirror logic: check if target falls in (nums[mid], nums[hi]]. If yes, advance lo = mid + 1; otherwise the target is in the left (possibly rotated) portion (hi = mid - 1).
Line 24 — not found. The loop terminates with lo > hi; the target was never matched. Return -1.
Complexity → O(log n) time — each iteration halves the search space. O(1) space — only lo, mid, hi pointers.

INTERVIEWFollow-ups they'll ask

  • "What if duplicates are allowed (LC 81)?" When nums[lo] === nums[mid] === nums[hi] you cannot determine which half is sorted, so increment lo and decrement hi — worst case degrades to O(n).
  • "Find the rotation index instead?" LC 153 (Find Minimum in Rotated Sorted Array): the pivot is the first element smaller than its predecessor; use the same sorted-half comparison but track the minimum rather than a target.
  • "Can you recover the pivot first, then binary-search?" Yes — two passes of O(log n) is still O(log n), but the single-pass approach is cleaner and the one interviewers expect.
  • "What breaks if you use strict < instead of ≤ on line 9?" A two-element window where lo === mid would misclassify the left half as unsorted and may loop infinitely or miss the target.

MNEMONIC The one-liner

"One half is always sorted — find it, range-check target, then commit."

TRIGGERS When you see ___ → reach for ___

"rotated sorted array, O(log n)"sorted-half binary search
identify pivot or minimum in rotated arraynums[lo] ≤ nums[mid] check
standard binary search but array may wraprange-check the sorted half first
LC 81 (with duplicates)same pattern + lo++/hi-- fallback for equals

SKELETON The reusable shape

skeleton.ts
function search(nums: number[], target: number): number {
  let lo = 0, hi = nums.length - 1;
  while (lo <= hi) {
    const mid = Math.floor((lo + hi) / 2);
    if (nums[mid] === target) return mid;
    if (nums[lo] <= nums[mid]) {          // left half sorted
      if (nums[lo] <= target && target < nums[mid]) hi = mid - 1;
      else lo = mid + 1;
    } else {                               // right half sorted
      if (nums[mid] < target && target <= nums[hi]) lo = mid + 1;
      else hi = mid - 1;
    }
  }
  return -1;
}

FLASHCARDS Tap to flip

After splitting at mid in a rotated array, which half is always sorted?
At least one. If nums[lo] ≤ nums[mid] the left half is sorted; otherwise the right half is sorted.
tap to flip
1 / 6
Answer to reveal explanations. No penalty for retries.Score: 0 / 7
QUESTION 01
For nums=[4,5,6,7,0,1,2], target=0, which half is sorted on the first iteration (lo=0, mid=3, hi=6)?
QUESTION 02
What is the time complexity of the rotated binary search?
QUESTION 03
After identifying that the right half is sorted, when do you move hi = mid - 1?
QUESTION 04
Why is nums[lo] ≤ nums[mid] (with =) used instead of strict <?
QUESTION 05
In LC 81 (rotated array with duplicates), what extra case must you handle?
QUESTION 06
nums=[1], target=0. What does the algorithm return?
QUESTION 07
What is the space complexity of this algorithm?