DSA sheet · Binary Search · Classic pattern

Search in Rotated Sorted Array

A sorted array has been "rotated": a block from the end was moved to the front. We must find a target in it. The teacher shows that we can still use binary search, even though the whole array is no longer sorted. The trick is one extra question at every step: "which half, left or right of mid, is sorted?" Once we know that, we use the sorted half to decide where the target can be.

Why it matters: this is the first problem where binary search works on an array that is not fully sorted. The same "which half is sorted" idea comes back in Minimum in Rotated Sorted Array, Find K Rotations, and many interview twists.

Every part below follows the same order:
① the question in simple words → ② what the constraints tell us → ③ intuition → ④ building the conditions from examples → ⑤ approach steps → ⑥ code → ⑦ code line by line → ⑧ dry run → ⑨ complexity & remember

Part 0 · Before starting

Why binary search works at all

Binary search looks at the middle element and, with one comparison, throws away half of the array. That's only allowed when we can say for sure "the answer cannot be in that half". In a sorted array that's easy: if the middle value is smaller than the target, everything to its left is even smaller, so the target can only be on the right.

Put another way, we need a yes/no question whose answers line up in order, like no no no yes yes yes. For a sorted array, "is arr[i] >= target?" is such a question. Here the array is rotated, so that simple question breaks. We'll find a new way to decide which half to throw away.

low, high and mid

Why mid = left + (right - left) // 2 and not (left + right) // 2

Both give the same number. The teacher explains why we prefer the first one. In Java or C++, an int can hold at most 2³¹ − 1. If right is already near that limit, left + right goes past it and wraps around to a negative number (overflow), so mid becomes garbage. right - left is never bigger than right, so the first form never overflows.

Doubt: does this matter in Python?
→ No. Python integers grow as big as needed and never overflow. Here n is at most 5000, so even in Java it wouldn't overflow. We still write the safe form out of habit, because in interviews you'll often write Java/C++ too, and the habit costs nothing.

What is a rotated sorted array?

Start with a sorted array. One rotation (to the right) takes the last element and puts it at the front; everything else moves one place right.

sorted:            0 1 2 4 5 6 7
after 1 rotation:  7 0 1 2 4 5 6     (7 moved to the front, 0 moved from index 0 to 1)
after 2 rotations: 6 7 0 1 2 4 5
after 3 rotations: 5 6 7 0 1 2 4
after 4 rotations: 4 5 6 7 0 1 2     (0 is now at index 4)

The teacher counts the rotations by watching the smallest value: each rotation pushes 0 one step to the right. 0 is now at index 4, so the array was rotated 4 times.

The result is two sorted pieces glued together: 4 5 6 7 and 0 1 2. Inside each piece the numbers go up. There is exactly one drop (7 → 0) where the second piece starts. (If the array is rotated 0 times, or n times, there's no drop at all and it's simply sorted.)

Key fact for this pageA rotated sorted array is sorted in two parts. Pick any mid: the single drop can be on only one side of it, so at least one of the two halves, left..mid or mid..right, is fully sorted.

Part A · Brute force: linear search

LeetCode 33

1The question in simple words

You get an array nums that was sorted in increasing order and then possibly rotated by some unknown amount. All values are different. You also get a target. Return the index of the target, or -1 if it isn't there.

index0123456
value4567012target 0 → answer 4

2What the constraints tell us

3Intuition

Forget the rotation. Just walk from left to right and stop when you see the target.

4Why we still don't stop here

The teacher's point: when an interviewer gives you a sorted (or rotated sorted) array, they expect binary search. And if n were huge, like 10⁹ or 10¹⁰, an O(n) scan would be too slow. So linear search is only our starting point.

5Approach steps

  1. For each index i from 0 to n − 1: if nums[i] == target, return i.
  2. If the loop ends, return −1.

6Code (Python)

Brute force: linear search
class Solution:
    def search(self, nums, target):
        for i in range(len(nums)):
            if nums[i] == target:      # found it
                return i
        return -1                      # checked everything, not there

7Code line by line

linewhat it means
for i in range(len(nums)):Visit every index once, left to right.
if nums[i] == target: return iThe first (and only, since values are unique) match is the answer.
return -1We looked everywhere and didn't find it.

8Dry run

[4,5,6,7,0,1,2], target 0: check 4 ✗, 5 ✗, 6 ✗, 7 ✗, 0 ✓ → return 4. Five checks.

9Complexity & remember

RememberLinear search passes here because n ≤ 5000, but the interviewer wants O(log n). Mention it, then move on.

Part B · Optimal: binary search with "which half is sorted?"

1The question (same as Part A)

Same input and output, but now we want O(log n) time.

2What the constraints tell us

3Intuition: can we apply binary search here?

Normal binary search needs the whole array sorted. Ours isn't. But the teacher notices that if we look from mid, one side is always a normal sorted piece. We can only make a safe decision using a sorted piece, because only there can we say "the target is between this low end and this high end, or it isn't".

Picture 1: mid lands in the left piece

index:   0   1   2   3   4   5   6
value:   4   5   6  [7]  0   1   2
         L          M           R
         └──────────┘                left..mid = 4 5 6 7 → sorted ✓
                    └───────────┘    mid..right = 7 0 1 2 → NOT sorted ✗ (drop 7→0)

mid = 0 + (6 − 0) // 2 = 3, value 7. From index 0 to 3 the values go up: 4, 5, 6, 7. From 3 to 6 they don't: 7, 0, 1, 2. So 7 belongs to the left sorted piece, and we can trust the left half.

Picture 2: mid lands in the right piece

index:   0   1   2   3   4   5
value:   4   5  [0]  1   2   3
         L      M           R
         └──────┘                    left..mid = 4 5 0 → NOT sorted ✗ (drop 5→0)
                └───────────┘        mid..right = 0 1 2 3 → sorted ✓

mid = 0 + (5 − 0) // 2 = 2, value 0. The left half 4 5 0 is not sorted. But 0 1 2 3 is. So 0 belongs to the right sorted piece, and here we trust the right half.

The only new stepCompared with normal binary search, there is just one extra question: which half is sorted? After that, it's the usual "is the target inside this sorted range or not?"

4Building the conditions from examples

Condition 0: is nums[mid] the target?

Before anything else, if nums[mid] == target, we're done: return mid. The teacher puts this check first, so that every later branch knows the target is not at mid. That's why later we can use strict < at mid and move to mid - 1 / mid + 1.

Condition 1: how do we know the left half is sorted?

We only know three positions: left, mid, right. So we must decide using their values.

Rule 1if nums[mid] >= nums[left]: → the left half is sorted.
else: → the right half is sorted.
Doubt 1: why >= and not just >? The values are unique.
→ Because mid can be the same index as left. That happens when only 1 or 2 elements are left (e.g. left = 4, right = 5 → mid = 4). Then nums[mid] == nums[left] because it's the same cell. A one-element piece is sorted, so we want the "left is sorted" branch. With > we'd wrongly go to the "right is sorted" branch. Try [3, 1], target 1: with >, mid = 0, we'd treat 3 1 as the sorted right half, see that 1 is not in (3, 1], and throw away the 1. Wrong answer −1.
Doubt 2: what if both halves are sorted?
→ That happens once the drop has been thrown away (or if the array was never rotated). Then nums[mid] >= nums[left] is true, we take the left branch, and it behaves exactly like normal binary search. Fine.

Condition 2 (left half sorted): is the target inside it?

Knowing the left half is sorted does not mean the target is there. The teacher stresses this: we must check the range. A sorted piece from nums[left] to nums[mid] contains exactly the values between those two ends.

Rule 2if nums[left] <= target < nums[mid]: right = mid - 1
else: left = mid + 1
Doubt 3: why <= at nums[left] but < at nums[mid]?
→ The target might sit exactly at left, so that end must be included. But it can't be at mid: Condition 0 already checked that. So the mid end is excluded.
Doubt 4: why mid - 1 and mid + 1, not mid?
→ Mid has already been checked and it's not the target. Keeping it in the range would only waste a step (and in some loops can make it run forever). So we step past it.

Condition 3 (right half sorted): is the target inside it?

Now use Picture 2, [4,5,0,1,2,3], mid value 0. The sorted right half covers 0 to 3.

Rule 3if nums[mid] < target <= nums[right]: left = mid + 1
else: right = mid - 1

It's the mirror of Rule 2: the end at mid is strict (already checked), and the end at right is included.

The loop: while left <= right

Every step moves left or right, so we repeat the whole thing in a loop. Why <= and not <? When left == right there is still one element to check, and it might be the target. With < we'd skip it. When left passes right, the range is empty and the target isn't there → return −1.

5Approach steps

  1. Set left = 0, right = n - 1.
  2. While left <= right: compute mid = left + (right - left) // 2.
  3. If nums[mid] == target → return mid.
  4. If nums[mid] >= nums[left] (left half sorted): if nums[left] <= target < nums[mid] → right = mid - 1, else left = mid + 1.
  5. Else (right half sorted): if nums[mid] < target <= nums[right] → left = mid + 1, else right = mid - 1.
  6. After the loop → return −1.

6Code (Python)

Optimal: binary search on a rotated array
class Solution:
    def search(self, nums, target):
        left, right = 0, len(nums) - 1

        while left <= right:
            mid = left + (right - left) // 2

            if nums[mid] == target:                 # Condition 0
                return mid

            if nums[mid] >= nums[left]:             # left half is sorted
                if nums[left] <= target < nums[mid]:
                    right = mid - 1                 # target is in the left half
                else:
                    left = mid + 1                  # target is in the right half
            else:                                   # right half is sorted
                if nums[mid] < target <= nums[right]:
                    left = mid + 1                  # target is in the right half
                else:
                    right = mid - 1                 # target is in the left half

        return -1

7Code line by line

linewhat it means
left, right = 0, len(nums) - 1The whole array is our search range at the start.
while left <= right:Keep going while the range has at least one element.
mid = left + (right - left) // 2The middle index, written in the overflow-safe way.
if nums[mid] == target: return midLucky hit. Also means every later branch knows mid is not the target.
if nums[mid] >= nums[left]:The values climb from left to mid, so the left half is sorted. >= covers mid == left.
if nums[left] <= target < nums[mid]: right = mid - 1The target fits in the sorted left half's range, so throw away mid and everything right of it.
else: left = mid + 1The target isn't in the left half's range, so it can only be on the right.
else: # right half sortedThe drop is between left and mid, so mid..right must be the sorted piece.
if nums[mid] < target <= nums[right]: left = mid + 1The target fits in the sorted right half's range, so throw away the left side and mid.
else: right = mid - 1Not in the right half's range, so it must be on the left.
return -1The range became empty; the target isn't in the array.

8Dry run

Run 1: [4,5,6,7,0,1,2], target 0 (the teacher's example)

stepleftrightmidnums[mid]which half sorted?decisionthrown away
106377 ≥ 4 → left4 ≤ 0 < 7? no → left = 4indices 0–3
246511 ≥ 0 → left0 ≤ 0 < 1? yes → right = 4indices 5–6
34440-0 == target → return 4-
index0123456
step 14567012mid = 3; left half 4..7 sorted, 0 not in it
step 24567012mid = 5; left half 0..1 sorted, 0 is in it
step 34567012mid = 4 → found ✓

Note what happened in step 2: once we moved left to 4, we didn't know yet whether 0 1 2 was sorted. We simply computed a new mid and asked the same question again. This time both halves were sorted, and the left-branch handled it like normal binary search.

Run 2: same array, target 3 (not present)

stepleftrightmidnums[mid]which half sorted?decision
10637left (7 ≥ 4)4 ≤ 3? no → left = 4
24651left (1 ≥ 0)0 ≤ 3 < 1? no → left = 6
36662left (2 ≥ 2, same cell)2 ≤ 3 < 2? no → left = 7
end76left > right → loop stops → return -1

Run 3: [4,5,0,1,2,3], target 4 (uses the right-sorted branch)

stepleftrightmidnums[mid]which half sorted?decisionthrown away
105200 ≥ 4? no → right0 < 4 ≤ 3? no → right = 1indices 2–5
20104-4 == target → return 0-

With target 2 instead: step 1 sees 0 < 2 ≤ 3 → left = 3. Then left 3, right 5, mid 4, value 2 → return 4.

9Complexity & remember

The teacher's closing remark: on LeetCode the linear version also shows as fast, because n is only 5000. Binary search only becomes a must when n is huge (like 10⁹), but the interviewer expects it anyway.

Remember1. mid is target? return.
2. nums[mid] >= nums[left] → left half sorted, else right half sorted.
3. Is the target inside the sorted half's range? Yes → go there. No → go to the other half.

Part C · Revision page

Linear searchBinary search (which half sorted)
ideacheck every elementone half is always sorted; use it to decide
timeO(n)O(log n)
spaceO(1)O(1)
when it's enoughn small (≤ 5000 here)always; what the interviewer expects
sorted halfrange test (target inside?)if yesif no
left (nums[mid] >= nums[left])nums[left] <= target < nums[mid]right = mid - 1left = mid + 1
right (else)nums[mid] < target <= nums[right]left = mid + 1right = mid - 1
If you remember only 5 lines 1. A rotated sorted array = two sorted pieces; around any mid, one side is sorted.
2. Check nums[mid] == target first.
3. nums[mid] >= nums[left] → left half sorted; else right half sorted.
4. Only trust the sorted half: is the target between its two ends? Go there; otherwise go to the other half.
5. while left <= right, move to mid ± 1, return −1 at the end.
Mistakes to avoid ✗ assuming the target is in the sorted half just because it's sorted (check the range!)
✗ nums[mid] > nums[left] instead of >= (breaks when mid == left)
✗ including mid in the range tests or setting left = mid / right = mid
✗ while left < right (skips the last single element)
✗ forgetting to return −1
test it yourself (paste under the solution above)
s = Solution()
print(s.search([4, 5, 6, 7, 0, 1, 2], 0))   # 4
print(s.search([4, 5, 6, 7, 0, 1, 2], 3))   # -1
print(s.search([4, 5, 0, 1, 2, 3], 4))      # 0
print(s.search([1], 0))                     # -1
print(s.search([3, 1], 1))                  # 1

Based on this video: Search in Rotated Sorted Array