mirror of
https://github.com/prdlk/leetcode.git
synced 2026-11-02 13:12:44 +00:00
101 lines
2.7 KiB
Plaintext
101 lines
2.7 KiB
Plaintext
---
|
|
title: 'Binary Search'
|
|
description: 'In algorithms, arrays and strings are very similar. They are both ordered collections of elements. The difference is that arrays are mutable, while strings are immutable.'
|
|
---
|
|
|
|
## The idea
|
|
|
|
You look for a name in a phone book. You do not start at page 1.
|
|
You open the middle. Too far? Go left. Not far enough? Go right.
|
|
Each step throws away half the book.
|
|
|
|
100 items → 7 steps. 4 billion items → 32 steps.
|
|
|
|
**The core rule:** ask a yes/no question that flips exactly once.
|
|
Everything left of the flip is "no". Everything right is "yes".
|
|
Binary search finds the flip point.
|
|
|
|
## The picture
|
|
|
|
```mermaid
|
|
flowchart TD
|
|
A["Array: 1 3 5 7 9 11 13<br/>Target: 9"] --> B["mid = 7<br/>7 < 9 → discard left half"]
|
|
B --> C["Array: 9 11 13<br/>mid = 11<br/>11 > 9 → discard right half"]
|
|
C --> D["Array: 9<br/>mid = 9<br/>Found ✓"]
|
|
|
|
style D fill:#2e7d32,color:#fff
|
|
```
|
|
|
|
## The template
|
|
|
|
```python
|
|
def binary_search(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
|
|
if nums[mid] < target:
|
|
lo = mid + 1
|
|
else:
|
|
hi = mid - 1
|
|
return -1
|
|
```
|
|
|
|
## Search the answer space (LC 875 — Koko Eating Bananas)
|
|
|
|
The array does not need to exist. You can binary search over *possible answers*.
|
|
Ask: "does speed k work?" Slow speeds fail. Fast speeds work.
|
|
The answer flips once. Find the flip.
|
|
|
|
```mermaid
|
|
flowchart LR
|
|
A["k=1<br/>NO"] --> B["k=2<br/>NO"] --> C["k=3<br/>NO"] --> D["k=4<br/>YES ← answer"] --> E["k=5<br/>YES"] --> F["k=6<br/>YES"]
|
|
|
|
style D fill:#2e7d32,color:#fff
|
|
```
|
|
|
|
```python
|
|
import math
|
|
|
|
def min_eating_speed(piles: list[int], h: int) -> int:
|
|
def k_works(k: int) -> bool:
|
|
return sum(math.ceil(p / k) for p in piles) <= h
|
|
|
|
lo, hi = 1, max(piles)
|
|
|
|
while lo < hi:
|
|
mid = (lo + hi) // 2
|
|
if k_works(mid):
|
|
hi = mid # mid works — keep it, look left
|
|
else:
|
|
lo = mid + 1 # mid fails — discard it
|
|
return lo
|
|
```
|
|
|
|
## Not the same as two pointers
|
|
|
|
Two pointers **walks** — it inspects every element it passes. O(n).
|
|
Binary search **jumps** — it inspects one midpoint and discards half unseen. O(log n).
|
|
|
|
## Complexity
|
|
|
|
| | Time | Space |
|
|
|---|---|---|
|
|
| Sorted array | O(log n) | O(1) |
|
|
| Answer space | O(n log m) | O(1) |
|
|
|
|
n = array size, m = answer range.
|
|
|
|
## Close-out ritual
|
|
|
|
Before you submit, say out loud:
|
|
1. Time and space complexity.
|
|
2. One edge case trace: empty array, one element, or target not present.
|
|
|
|
## Plan problems
|
|
|
|
**A-set:** LC 704 · 74 · 875 · 33 · 153
|
|
**B-set:** LC 35 · 162 · 34 · 4 ⭐
|