3.6.11Sorting & Searching

Binary search — iterative, recursive; O(log n); searching in sorted - rotated arrays

2,148 words10 min readdifficulty · medium6 backlinks

WHY binary search exists

Think of guessing a number between 1 and 1000. Guess 500: "higher/lower" reply kills 500 numbers. Ten guesses (210=10242^{10}=1024) is enough. That's the whole trick.


WHAT it is


HOW — deriving the loop from first principles

We maintain a window [lo, hi] that is guaranteed to contain the target if it exists at all. This is the invariant — everything else follows from protecting it.

  1. Start: lo = 0, hi = n-1 (whole array).
  2. Pick mid between them. Why mid? It splits the window as evenly as possible, so the worse half is as small as possible → fewest steps in the worst case.
  3. Compare arr[mid] to target:
    • equal → found, return mid.
    • arr[mid] < target → target (if present) is to the right, so lo = mid + 1. Why +1? mid itself was just ruled out; keeping it risks an infinite loop.
    • arr[mid] > targethi = mid - 1 for the same reason.
  4. Stop when lo > hi (empty window) → not found.

Iterative code

def bsearch(arr, target):
    lo, hi = 0, len(arr) - 1
    while lo <= hi:                 # window non-empty
        mid = lo + (hi - lo) // 2   # overflow-safe
        if arr[mid] == target:
            return mid
        elif arr[mid] < target:
            lo = mid + 1            # discard left half incl. mid
        else:
            hi = mid - 1            # discard right half incl. mid
    return -1

Why lo <= hi not lo < hi? When lo == hi the window still has one element we haven't checked — dropping it would miss single-element matches.

Recursive code

def bsearch_rec(arr, target, lo, hi):
    if lo > hi:                     # base case: empty
        return -1
    mid = lo + (hi - lo) // 2
    if arr[mid] == target:
        return mid
    if arr[mid] < target:
        return bsearch_rec(arr, target, mid + 1, hi)   # right
    return bsearch_rec(arr, target, lo, mid - 1)       # left

Same logic; the call stack replaces the loop. Recursion depth is O(logn)O(\log n), so memory is O(logn)O(\log n) vs O(1)O(1) for iterative.


WHY it is O(logn)O(\log n) — derived

Let T(n)T(n) = comparisons in the worst case for nn elements. Each step does O(1)O(1) work then recurses on half: T(n)=T(n/2)+1,T(1)=1T(n) = T(n/2) + 1,\qquad T(1)=1 Unrolling: T(n)=1+1+T(n) = 1 + 1 + \dots until nn shrinks to 11. Number of halvings kk satisfies n/2k=12k=nk=log2nn/2^k = 1 \Rightarrow 2^k = n \Rightarrow k = \log_2 n. So T(n)=log2n+1=O(logn)\boxed{T(n) = \log_2 n + 1 = O(\log n)} Space: iterative O(1)O(1), recursive O(logn)O(\log n) (stack).

Figure — Binary search — iterative, recursive; O(log n); searching in sorted - rotated arrays

Searching in a ROTATED sorted array

A sorted array rotated at a pivot, e.g. [4,5,6,7,0,1,2]. It's no longer globally sorted, but at least one half around mid is always sorted. We exploit that.

def search_rotated(arr, target):
    lo, hi = 0, len(arr) - 1
    while lo <= hi:
        mid = lo + (hi - lo) // 2
        if arr[mid] == target:
            return mid
        if arr[lo] <= arr[mid]:                 # left half sorted
            if arr[lo] <= target < arr[mid]:    # target in left
                hi = mid - 1
            else:
                lo = mid + 1
        else:                                   # right half sorted
            if arr[mid] < target <= arr[hi]:    # target in right
                lo = mid + 1
            else:
                hi = mid - 1
    return -1

Why <= in arr[lo] <= arr[mid]? When lo == mid (window size 1–2) the "left half" is a single element, trivially sorted; <= keeps that case correct. Still O(logn)O(\log n) — each step discards a half.


Worked examples


Common mistakes (steel-manned)


Recall Feynman: explain to a 12-year-old

You're looking for a name in a phone book. You don't read every name! You flip to the middle. The name you want comes before the middle? Tear off and ignore the second half. Comes after? Ignore the first half. Open the middle of what's left, repeat. In a few flips you land on the exact page. Each flip throws away half the book — that's why even a giant book takes only a handful of flips. A "rotated" book is one where someone cut the pages and swapped them; but each piece you open is still alphabetical, so you can still tell which side to keep.


Flashcards

Binary search precondition?
The array must be sorted (or sorted-then-rotated for the rotated variant).
Time complexity of binary search and why?
O(logn)O(\log n); recurrence T(n)=T(n/2)+1T(n)=T(n/2)+1 halves the search each step, log2n\log_2 n steps.
Overflow-safe mid formula?
mid = lo + (hi - lo) // 2, equal to (lo+hi)/2(lo+hi)/2 but avoids integer overflow.
Why lo = mid + 1 instead of lo = mid?
mid was already compared and excluded; without +1+1 the window may not shrink → infinite loop.
Correct loop condition and why?
while lo <= hi; with < you'd skip the single remaining element when lo == hi.
Space complexity: iterative vs recursive?
Iterative O(1)O(1); recursive O(logn)O(\log n) due to call stack depth.
In a rotated array, how to find the sorted half?
If arr[lo] <= arr[mid] the left half is sorted; otherwise the right half is sorted.
Once you know the sorted half, how do you decide where to go?
Range-check: if target lies within that sorted half's bounds, search it; else search the other half.
What does binary search return when not found?
Conventionally 1-1, reached when lo > hi (empty window).
Why is the worst case log2n\lceil \log_2 n\rceil comparisons?
Each comparison halves the candidate set; after kk halvings only n/2kn/2^k remain, hitting 1 at k=log2nk=\log_2 n.

Connections

  • Linear SearchO(n)O(n) baseline; binary search beats it only when data is sorted.
  • Sorting Algorithms — must sort first (O(nlogn)O(n\log n)) to enable binary search.
  • Logarithms — the inverse-of-halving that gives the complexity.
  • Recurrence RelationsT(n)=T(n/2)+1T(n)=T(n/2)+1 analysis.
  • Time Complexity & Big-O — places O(logn)O(\log n) between O(1)O(1) and O(n)O(n).
  • Lower & Upper Bound (bisect) — variants finding first/last position.
  • Binary Search Tree — same divide idea as a data structure.

Concept Map

enables

compares target to

leads to

maintains

halving gives

implemented as

implemented as

computed by

then rotated for

beats

Sorted array precondition

Binary search

Middle element compare

Discard half of window

Invariant window lo..hi

O log n time

Iterative loop

Recursive calls

Overflow-safe mid formula

Rotated array variant

Linear search O n

Hinglish (regional understanding)

Intuition Hinglish mein samjho

Dekho, binary search ka funda simple hai: array sorted hona chahiye. Phir tum beech wale (middle) element ko dekhte ho. Agar target middle se bada hai to left half pura phenk do, kyunki sorted hai to target wahan ho hi nahi sakta. Agar chhota hai to right half phenk do. Har step me aadha array gayab — isiliye 1000 elements me bhi sirf ~10 comparisons lagte hain. Yahi reason hai ki complexity O(logn)O(\log n) hai, kyunki har baar half karne ka ulta (inverse) log hota hai.

Do tarike hain likhne ke: iterative (while loop, lo aur hi pointers) aur recursive (function khud ko half pe call karta hai). Iterative me memory O(1)O(1), recursive me O(logn)O(\log n) stack ki wajah se. Mid nikalte waqt hamesha mid = lo + (hi-lo)//2 likho — (lo+hi)//2 overflow de sakta hai bade numbers me. Aur lo = mid + 1 / hi = mid - 1 me ±1\pm1 mat bhoolna, warna infinite loop me phans jaoge. Loop condition lo <= hi rakho, < nahi — warna last single element miss ho jayega.

Rotated array thoda twist hai, jaise [4,5,6,7,0,1,2] — yeh ghuma hua sorted hai. Trick: mid ke ek taraf hamesha proper sorted rahega. Check karo arr[lo] <= arr[mid] — agar true to left half sorted hai, wahan range-check karke decide karo target idhar hai ya udhar. Phir bhi O(logn)O(\log n) hi rehta hai. Bas yaad rakho: pehle sorted half pehchano, phir range check.

Yeh topic interviews aur real systems (databases, libraries ka bisect) dono me bahut use hota hai, isliye iska invariant — "window me agar target hai to wahi rahega" — dimaag me clear rakhna.

Go deeper — visual, from zero

Test yourself — Sorting & Searching

Connections