π
Sorting & Searching
Hand-coded + bisect Β· lower/upper bound
11. Binary Search
Binary search reduces O(n) to O(log n) on sorted data. Master the recurrence by hand so you can apply it to non-trivial 'find the boundary' problems.
binary searchbisectlower bound
Duration
β± ~1 hour
Level
π Intermediate
Prerequisite
π― Lecture 9
OUTCOME
Solve any 'find the first/last/exact x' problem on a sorted array.
What you'll learn
- 1Hand-code binary search avoiding off-by-one errors
- 2Use bisect_left and bisect_right correctly
- 3Distinguish exact-match, lower-bound, and upper-bound queries
Overview
Binary search divides the search space in half each step β O(log n). It only works on a sorted (or monotone) sequence. Edge cases (off-by-one, infinite loops) are the main source of bugs.
Core Concepts
1. Find exact match
python
def binary_search(a, target):
lo, hi = 0, len(a) - 1
while lo <= hi:
mid = (lo + hi) // 2
if a[mid] == target:
return mid
elif a[mid] < target:
lo = mid + 1
else:
hi = mid - 1
return -12. Lower bound (first index >= target)
python
def lower_bound(a, target):
lo, hi = 0, len(a)
while lo < hi:
mid = (lo + hi) // 2
if a[mid] < target:
lo = mid + 1
else:
hi = mid
return lo # may be len(a) if all < target3. Upper bound (first index > target)
python
def upper_bound(a, target):
lo, hi = 0, len(a)
while lo < hi:
mid = (lo + hi) // 2
if a[mid] <= target:
lo = mid + 1
else:
hi = mid
return lo4. The bisect module
python
import bisect
a = [1, 3, 5, 5, 5, 7, 9]
bisect.bisect_left(a, 5) # 2 (first index of 5)
bisect.bisect_right(a, 5) # 5 (first index > 5)
bisect.bisect_right(a, 5) - bisect.bisect_left(a, 5) # count of 5s
bisect.insort(a, 4) # insert 4 in sorted orderπ‘
bisect is C-implemented and very fast. Always prefer it over hand-coding when you just need find/insert positions.
Examples
Example 1 β src/01_binary_search.py
Iterative and recursive binary search.
Example 2 β src/02_lower_upper.py
lower_bound and upper_bound by hand.
Example 3 β src/03_bisect_demo.py
bisect_left, bisect_right, insort.
Example 4 β src/04_search_2d.py
Search a row-and-column-sorted matrix.
Common Mistakes
- Forgetting hi = len(a) - 1 vs hi = len(a) inconsistency. Pick one convention and stick to it.
- (lo + hi) // 2 overflows in some languages β in Python it's fine, but be aware.
- Updating lo = mid (not mid+1) β infinite loop when range = 2.
- Searching an unsorted array. Sort first or use a hash.
Recap
- Pre-condition: sorted (or monotone) input.
- bisect_left / bisect_right cover most needs.
- Off-by-one bugs are common β test on boundary inputs.
Try It
- BOJ 1920 (Find a number).
- BOJ 10816 (Sorted card 2) β count occurrences.
Example code / lecture materials
All lecture materials and example code are openly available on GitHub.
View on GitHub β