DSA sheet · Binary Search · Classic pattern

Find Minimum in Rotated Sorted Array

A sorted array was rotated, and we must find its smallest value in O(log n). The teacher doesn't hand us a formula. She draws a few rotated arrays, puts left, mid and right on each, and discovers the rule by looking at where the minimum actually is. The rule she ends up with: compare nums[mid] with nums[right]. If the right half is sorted, the minimum is at mid or to its left. If not, it's strictly to the right.

Why it matters: it teaches the "mid might be the answer, so keep it" style of binary search (right = mid, while left < right). It also finds the rotation point, which is exactly what "Find K Rotations" asks for.

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

Binary search checks the middle element and, from that single check, throws away half of the range for good. That's only safe if we can prove the answer is not in the half we drop. So the real work in every binary search problem is finding a yes/no test at mid that tells us which side the answer is on.

In this problem the test turns out to be "nums[mid] <= nums[right]?" Over a rotated array, its answers line up like no no no yes yes yes (no for the big piece, yes for the small piece), and the minimum is the first yes. That ordered yes/no pattern is exactly what binary search needs.

left, right, mid

Doubt: why not (left + right) // 2?
→ In Java/C++, if both indices are large, left + right can go past the int limit (2³¹ − 1) and turn negative. left + (right - left) // 2 never does. The teacher notes that here n ≤ 5000, so the plain form would also work, but asks us to make the safe form a habit. In Python ints never overflow, so both are fine; we use the safe form anyway.

What is a rotated sorted array?

Rotating once (clockwise, to the right) moves the last element to the front. The teacher's example:

1 2 3 4   →   1 rotation:  4 1 2 3   →   2 rotations:  3 4 1 2

After rotating, the array is two sorted pieces: a piece of big values, then a piece of small values. The minimum is the first element of the second piece, right after the one place where the values drop. Rotating n times brings the array back to normal sorted order, and then there's no drop at all; the minimum is simply at index 0.

4 5 6 7 0 1 2      ← rotated 4 times: pieces "4 5 6 7" and "0 1 2", minimum 0
11 13 15 17        ← rotated 4 times with n = 4: fully sorted again, minimum 11

Part A · Brute force: scan for the smallest

LeetCode 153

1The question in simple words

You get nums, an array of unique values that was sorted in increasing order and then rotated between 1 and n times. Return the minimum value (the value, not its index).

index01234
value34512answer 1

2What the constraints tell us

3Intuition

Look at every value and keep the smallest one seen so far.

4Why it's not enough

It ignores everything we know about the array (two sorted pieces). It's O(n), and the question explicitly asks for O(log n).

5Approach steps

  1. Start with best = nums[0].
  2. For every other value, if it's smaller, update best.
  3. Return best.

6Code (Python)

Brute force: linear scan
class Solution:
    def findMin(self, nums):
        best = nums[0]
        for x in nums:
            if x < best:
                best = x
        return best

7Code line by line

linewhat it means
best = nums[0]Our first guess for the minimum.
for x in nums: if x < best: best = xAny smaller value replaces the guess.
return bestAfter seeing every value, the guess is the true minimum.

8Dry run

[3,4,5,1,2]: best 3 → 3 → 3 → 1 → 1. Answer 1 after 5 looks.

9Complexity & remember

RememberPasses on n = 5000, but breaks the O(log n) requirement. Say it in the interview, then go to binary search.

Part B · Optimal: binary search, compare mid with right

1The question (same as Part A)

Return the minimum, but in O(log n).

2What the constraints tell us

3Intuition: look at where mid lands

The teacher's method: "I don't know any trick yet. I'll draw some cases, mark left, mid, right, and see what's true when the minimum is on each side." Here are her cases (drawn with my own numbers):

Case 1: right part NOT sorted → minimum is to the right of mid

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

The drop is somewhere between mid and right, and the minimum sits just after the drop. So the minimum is to the right of mid. Mid itself (5) is in the "big" piece, so it can't be the minimum.

Case 2: right part sorted, and mid IS the minimum

index:   0   1   2   3   4
value:   4   5  [1]  2   3
         L      M       R
                └───────┘   mid..right = 1 2 3 → sorted ✓
nums[mid] = 1  <  nums[right] = 3      ← mid is the answer here

Case 3: right part sorted, mid is the minimum again

index:   0   1   2   3   4   5   6
value:   5   6   7  [1]  2   3   4
         L          M           R
                    └───────────┘   1 2 3 4 → sorted ✓, mid = 1 = minimum

Case 4: right part sorted, but mid is NOT the minimum

index:   0   1   2   3   4
value:   5   1  [2]  3   4
         L      M       R
                └───────┘   2 3 4 → sorted ✓, but the minimum (1) is on the LEFT

Put cases 2, 3 and 4 side by side. In all three, the right part is sorted. Sometimes mid is the answer (2, 3) and sometimes the answer is further left (4). But in none of them is the answer to the right of mid, because everything right of mid in a sorted part is bigger than nums[mid].

What the cases teach • nums[mid] > nums[right] (right part not sorted) → the minimum is strictly right of mid.
• nums[mid] < nums[right] (right part sorted) → the minimum is at mid or to its left. Mid might be the answer, so don't throw it away.

4Building the conditions

Rule 1: right part not sorted → left = mid + 1

The array is rotated clockwise, so the small values are pushed to the right. If mid..right is not sorted, the drop (and the minimum right after it) is in there. Everything from left to mid belongs to the big piece. We can throw all of it away, mid included: left = mid + 1.

Rule 2: right part sorted → right = mid (not mid - 1)

The minimum is at mid or to its left. Why mid and not mid - 1? The teacher's reason: mid - 1 means "I'm sure mid is not the answer". But cases 2 and 3 showed mid can be the answer. So we keep it: right = mid, and continue searching left..mid.

The rulesif nums[mid] <= nums[right]: right = mid
else: left = mid + 1
Doubt 1: the teacher writes <=. When can nums[mid] == nums[right]?
→ Only when mid and right are the same index (values are unique). Inside our loop left < right, so mid (which rounds down) is always less than right. So the equal case never happens in practice, and < or <= behave the same. <= is just a harmless, safe choice.

The loop: while left < right (not <=)

We keep shrinking until left and right meet. When they point to the same index, only one candidate is left, so that's the minimum. Return nums[left] (or nums[right]; they're the same cell).

Doubt 2: why not while left <= right like in normal binary search?
→ With <=, when left == right we'd go in again: mid = left = right, the test nums[mid] <= nums[right] is true, so right = mid, and nothing changes. The loop would run forever. Rule of thumb: when one branch is right = mid (mid kept), use while left < right and read the answer after the loop.
Doubt 3: is it safe that we stop without ever "checking" the answer?
→ Yes. Each rule only throws away positions that can't be the minimum. So the minimum is always inside left..right. When the range has one cell, that cell must be it.

5Approach steps

  1. left = 0, right = n - 1.
  2. While left < right: mid = left + (right - left) // 2.
  3. If nums[mid] <= nums[right] (right part sorted) → right = mid.
  4. Else (right part has the drop) → left = mid + 1.
  5. Return nums[left].

6Code (Python)

Optimal: compare mid with right
class Solution:
    def findMin(self, nums):
        left, right = 0, len(nums) - 1

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

            if nums[mid] <= nums[right]:   # right part sorted
                right = mid                # mid may be the minimum: keep it
            else:                          # right part has the drop
                left = mid + 1             # minimum is strictly right of mid

        return nums[left]                  # left == right: the only candidate

7Code line by line

linewhat it means
left, right = 0, len(nums) - 1The minimum could be anywhere at the start.
while left < right:Stop when only one index is left. That index is the answer.
mid = left + (right - left) // 2Middle index (overflow-safe form). Rounds down, so mid < right always.
if nums[mid] <= nums[right]:Values climb from mid to right, so the right part is sorted. Nothing right of mid can beat nums[mid].
right = midDrop everything right of mid, but keep mid: it might be the minimum.
left = mid + 1The drop is between mid and right. Mid and everything left of it are in the big piece.
return nums[left]left == right. Return the value, as the problem asks.

8Dry run

Run 1: Case 1, [3,4,5,1,2] (the teacher's walk-through)

stepleftrightmidnums[mid]nums[right]decisionthrown away
1042525 > 2 → right part not sorted → left = 33, 4, 5
2343121 ≤ 2 → right part sorted → right = 32
end33left == right → return nums[3] = 1
index01234
step 1345125 > 2 → 5 can't be the minimum; go right
step 2345121 ≤ 2 → keep 1, drop 2
end34512one cell left → 1 ✓

In step 2, mid lands on the same index as the new left. Since 1 < 2, we keep 1 and move right onto it. Now both pointers sit on the same cell, which is what stops the loop.

Run 2: Case 4, [5,1,2,3,4] (right part sorted, but the answer is to the left)

stepleftrightmidnums[mid]nums[right]decision
1042242 ≤ 4 → right = 2
2021121 ≤ 2 → right = 1
3010515 > 1 → left = 1
end11return 1

Run 3: [4,5,6,7,0,1,2] (LeetCode example 2)

mid 3 (7 > 2) → left = 4 · mid 5 (1 ≤ 2) → right = 5 · mid 4 (0 ≤ 1) → right = 4 · left == right → 0 ✓

Run 4: [11,13,15,17] (rotated n times = plain sorted)

mid 1 (13 ≤ 17) → right = 1 · mid 0 (11 ≤ 13) → right = 0 · return 11 ✓. With no drop, the "right part sorted" rule fires every time and walks right down to index 0.

9Complexity & remember

Remembernums[mid] <= nums[right] → right = mid (mid may be the answer). Else → left = mid + 1. Loop while left < right, return nums[left].

Part C · Her homework: why not compare with left first?

At the end of the video the teacher asks: "Why do we check whether the right half is sorted, and not the left half?" She says the logic fails if you check the left half first, and asks us to work out why on our own. Here is the answer.

1The question

Suppose we test nums[mid] >= nums[left] ("left half is sorted") instead. What should we do when it's true?

2What we can and can't conclude

A: left half sorted, minimum on the RIGHT
3  4  [5]  1  2
L      M      R
└──────┘ sorted
min = 1 → right of mid
B: left half sorted, minimum on the LEFT
1  2  [3]  4  5
L      M      R
└──────┘ sorted
min = 1 → at left

3Intuition

In both A and B the same test is true (5 ≥ 3 and 3 ≥ 1). Yet in A we must go right, and in B we must stay left. One test, two different correct moves. That means the test alone can't decide which half to throw away. A fixed rule like "left half sorted → go right" gives the wrong answer on B (it would return 4).

Comparing with right doesn't have this problem. If nums[mid] < nums[right], nothing to the right of mid is smaller, so always go left (keep mid). If nums[mid] > nums[right], the drop is to the right, so always go right. Each test result has exactly one correct move.

4Can the left comparison be rescued?

Yes, with one extra check. The confusing case B is when the whole range left..right is already sorted. We can spot that first: if nums[left] < nums[right], there is no drop in the range, so the minimum is simply nums[left]. After that check, the range definitely contains the drop, and "left half sorted" really does mean "minimum is to the right".

Doubt: so which one should I use in an interview?
→ Compare with right (Part B): it needs no extra check. Knowing why left-first fails without the guard is what the teacher wants us to learn. She suggests trying it yourself first: write the other version, see it fail, then work out why.

5Approach steps (left-first, with the guard)

  1. While left < right: if nums[left] < nums[right] → the range is sorted → return nums[left].
  2. Otherwise compute mid. If nums[mid] >= nums[left] → mid is in the big piece → left = mid + 1.
  3. Else mid is in the small piece and might be the minimum → right = mid.
  4. Return nums[left].

6Code (Python)

Left-first version (needs the sorted-range guard)
class Solution:
    def findMin(self, nums):
        left, right = 0, len(nums) - 1
        while left < right:
            if nums[left] < nums[right]:   # no drop inside left..right
                return nums[left]
            mid = left + (right - left) // 2
            if nums[mid] >= nums[left]:    # mid is in the big piece
                left = mid + 1
            else:                          # mid is in the small piece
                right = mid
        return nums[left]

7Line by line (only the new parts)

linewhat it means
if nums[left] < nums[right]: return nums[left]The guard. It removes case B, the one that made the left test ambiguous.
if nums[mid] >= nums[left]: left = mid + 1The range has a drop, and left..mid has no drop, so the drop (and the minimum) is right of mid.
else: right = midThe drop is between left and mid; mid is in the small piece and may be the minimum.

8Dry run on case B, with and without the guard

versionstep 1 (l 0, r 4, mid 2, value 3)step 2result
no guard3 ≥ 1 → left = 3l 3, r 4, mid 3: 4 ≥ 4 → left = 45 ✗
with guard1 < 5 → range sorted → return 1-1 ✓

9Complexity & remember

Still O(log n) time, O(1) space.

RememberCompare mid with right: every result has exactly one correct move. "Left half is sorted" can mean "go right" or "stay left", so it needs an extra check.

Part D · Revision page

Linear scanCompare with rightCompare with left + guard
timeO(n)O(log n)O(log n)
loopfor each valuewhile left < rightwhile left < right
mid may be answer-right = midright = mid
mid is not answer-left = mid + 1left = mid + 1
extra check-nonerange already sorted → return nums[left]
Search in Rotated Array (Problem 5)Minimum in Rotated Array (this page)
looking for a given targetlooking for the smallest value
while left <= right, moves to mid ± 1while left < right, right = mid keeps mid
tests which half is sorted using nums[left]tests which half is sorted using nums[right]
If you remember only 5 lines 1. A rotated array = big sorted piece, then small sorted piece; the minimum starts the small piece.
2. nums[mid] <= nums[right] → right part sorted → the answer is mid or to its left → right = mid.
3. Otherwise the drop is to the right → left = mid + 1.
4. while left < right, then return nums[left].
5. If mid might be the answer, move to mid; if it surely isn't, move past it.
Mistakes to avoid ✗ right = mid - 1 (can throw away the minimum)
✗ while left <= right together with right = mid (infinite loop)
✗ comparing with nums[left] without the sorted-range guard
✗ returning the index instead of the value
✗ only "watching" the solution: the teacher's advice is to close the notes and write it yourself
test it yourself (paste under the solution above)
s = Solution()
print(s.findMin([3, 4, 5, 1, 2]))           # 1
print(s.findMin([4, 5, 6, 7, 0, 1, 2]))     # 0
print(s.findMin([11, 13, 15, 17]))          # 11
print(s.findMin([5, 1, 2, 3, 4]))           # 1
print(s.findMin([7]))                       # 7

Based on this video: Find Minimum in Rotated Sorted Array