Binary Search
Efficient search in sorted data — the O(log n) pattern
Free tier: read the explanation here. Upgrade to Pro for Drills, Speed challenges & Mastery badges.
UpgradeKnowledge Debt detected
You can study this freely — but your score may plateau if these foundations have gaps. The Mastery badge requires them to be solid.
Explanation
finds an element in a sorted array in O(log n) by repeatedly halving the .
The core algorithm:
python def binary_search(arr: list, target: int) -> int: lo, hi = 0, len(arr) - 1 while lo <= hi: mid = (lo + hi) // 2 if arr[mid] == target: return mid # found elif arr[mid] < target: lo = mid + 1 # target is in right half else: hi = mid - 1 # target is in left half return -1 # not found arr = [1, 3, 5, 7, 9, 11, 13] binary_search(arr, 7) # 3 (index)
Why O(log n): each step halves the search space. For 1,000,000 items, you need at most 20 comparisons.
Using Python's bisect module:
python import bisect arr = [1, 3, 5, 7, 9] idx = bisect.bisect_left(arr, 5) # 2 — leftmost valid insertion point idx = bisect.bisect_right(arr, 5) # 3 — rightmost
Generalisation — binary search on the answer:
python # Problem: find minimum speed such that all packages delivered in D days def min_speed(weights, D): def can_deliver(speed): days = 1 current = 0 for w in weights: if current + w > speed: days += 1 current = 0 current += w return days <= D lo, hi = max(weights), sum(weights) while lo < hi: mid = (lo + hi) // 2 if can_deliver(mid): hi = mid else: lo = mid + 1 return lo
Pattern: if you can ask "is X sufficient?" and the answer transitions from No to Yes at some threshold, binary search finds that threshold in O(log(range)).
Examples
Find first occurrence (left bisect)
bisect_left gives the first position where target could be inserted
import bisect
def find_first(arr: list, target: int) -> int:
"""Return index of first occurrence, or -1 if not found."""
idx = bisect.bisect_left(arr, target)
if idx < len(arr) and arr[idx] == target:
return idx
return -1
arr = [1, 2, 2, 2, 3, 4]
find_first(arr, 2) # 1 (first 2 is at index 1)
find_first(arr, 5) # -1Search in rotated sorted array
Classic interview variant — binary search still works on rotated sorted arrays
def search_rotated(nums: list[int], target: int) -> int:
lo, hi = 0, len(nums) - 1
while lo <= hi:
mid = (lo + hi) // 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
search_rotated([4, 5, 6, 7, 0, 1, 2], 0) # 4How well did you understand this?
Next in Algorithms & Data Structures
Stack