Search in Rotated Sorted Array
Difficulty: Medium Source: NeetCode
Problem
There is an integer array
numssorted in ascending order (with distinct values).Prior to being passed to your function,
numsis possibly rotated at an unknown pivot indexksuch that the resulting array is[nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]].Given the array
numsafter the possible rotation and an integertarget, return the index oftargetif it is innums, or-1if it is not innums.You must write an algorithm with
O(log n)runtime complexity.Example 1: Input:
nums = [4, 5, 6, 7, 0, 1, 2],target = 0Output:4Example 2: Input:
nums = [4, 5, 6, 7, 0, 1, 2],target = 3Output:-1Constraints:
1 <= nums.length <= 5000-10^4 <= nums[i] <= 10^4- All values of
numsare uniquenumsis an ascending array that is possibly rotated-10^4 <= target <= 10^4
Prerequisites
Before attempting this problem, you should be comfortable with:
- Binary Search — standard half-elimination approach
- Rotated Arrays — recognizing which half of the array is sorted at any given
mid
1. Brute Force
Intuition
Ignore the rotation entirely and scan every element linearly.
Algorithm
- For each index
i, ifnums[i] == target, returni. - Return
-1.
Solution
def search_linear(nums, target):
for i, v in enumerate(nums):
if v == target:
return i
return -1
print(search_linear([4, 5, 6, 7, 0, 1, 2], 0)) # 4
print(search_linear([4, 5, 6, 7, 0, 1, 2], 3)) # -1
Complexity
- Time:
O(n) - Space:
O(1)
2. Binary Search
Intuition
At any split point mid, at least one of the two halves — [lo, mid] or [mid, hi] — must be fully sorted. You can tell which by comparing nums[lo] with nums[mid]. Once you know which half is sorted, check whether the target falls inside that half’s value range. If it does, search that half; otherwise search the other. This gives the usual O(log n) binary search despite the rotation.
Algorithm
- Set
lo = 0,hi = len(nums) - 1. - While
lo <= hi:mid = lo + (hi - lo) // 2.- If
nums[mid] == target, returnmid. - Left half is sorted (
nums[lo] <= nums[mid]):- If
nums[lo] <= target < nums[mid]: search left →hi = mid - 1. - Else: search right →
lo = mid + 1.
- If
- Right half is sorted (otherwise):
- If
nums[mid] < target <= nums[hi]: search right →lo = mid + 1. - Else: search left →
hi = mid - 1.
- If
- Return
-1.
flowchart LR
S(["nums=[4,5,6,7,0,1,2] target=0\nlo=0 hi=6"])
S --> m0["mid=3 nums[3]=7 ≠ 0\nnums[0]=4 ≤ nums[3]=7 → left sorted\ntarget=0 not in [4,7) → lo=4"]
m0 --> m1["mid=5 nums[5]=1 ≠ 0\nnums[4]=0 ≤ nums[5]=1 → left sorted\ntarget=0 in [0,1) → hi=4"]
m1 --> m2["mid=4 nums[4]=0 == 0 → return 4"]
Solution
def search(nums, target):
lo, hi = 0, len(nums) - 1
while lo <= hi:
mid = lo + (hi - lo) // 2
if nums[mid] == target:
return mid
# Left half is sorted
if nums[lo] <= nums[mid]:
if nums[lo] <= target < nums[mid]:
hi = mid - 1
else:
lo = mid + 1
# Right half is sorted
else:
if nums[mid] < target <= nums[hi]:
lo = mid + 1
else:
hi = mid - 1
return -1
print(search([4, 5, 6, 7, 0, 1, 2], 0)) # 4
print(search([4, 5, 6, 7, 0, 1, 2], 3)) # -1
print(search([1], 0)) # -1
Complexity
- Time:
O(log n) - Space:
O(1)
Common Pitfalls
Using strict inequality nums[lo] < nums[mid] to detect the sorted half. When lo == mid (single element window), nums[lo] == nums[mid], so you need <= to correctly identify the left half as sorted.
Wrong range check for the sorted half. For the left half, the target must satisfy nums[lo] <= target < nums[mid] (exclusive upper bound because mid itself was already checked). For the right half: nums[mid] < target <= nums[hi] (exclusive lower bound). Getting these bounds wrong causes you to search the wrong half.
Forgetting to return -1 after the loop. Unlike “find minimum”, this problem can legitimately miss the target entirely.