22. Greedy
Greedy algorithms pick the locally optimal choice at each step. Their power and danger is that this isn't always globally optimal — you must prove (or strongly believe) the greedy choice is correct.
What you'll learn
- 1Solve the activity selection / meeting room problem
- 2Solve coin change with canonical coin systems
- 3Use the exchange argument to prove greedy correctness
Overview
A greedy approach makes the choice that looks best right now without regard for future consequences. It's the simplest paradigm — when it works.
Core Concepts
1. Activity selection (meeting rooms)
def max_activities(intervals):
# Sort by end time — greedy pick earliest-ending
intervals.sort(key=lambda x: x[1])
end = -float('inf')
count = 0
for s, e in intervals:
if s >= end:
count += 1
end = e
return countProof intuition: picking the earliest-ending activity leaves the most room for future activities.
2. Coin change (with canonical coin systems)
def coin_change_greedy(coins, target):
"""Works for canonical systems like Korean Won, USD.
Does NOT work for arbitrary coins — use DP then."""
coins.sort(reverse=True)
count = 0
for c in coins:
count += target // c
target %= c
return count if target == 0 else -1Greedy coin change only works when the coin system is 'canonical' (e.g., {1, 5, 10, 50, 100, 500}). For arbitrary coin sets (e.g., {1, 3, 4}), greedy is wrong — use DP.
3. Fractional knapsack (vs 0/1)
def fractional_knapsack(items, capacity):
"""Items can be taken in fractions. Greedy works here, unlike 0/1."""
items.sort(key=lambda iw: -iw[1] / iw[0]) # value/weight desc
total = 0
for w, v in items:
if capacity >= w:
total += v; capacity -= w
else:
total += v * (capacity / w); break
return total4. Proving greedy is correct
Exchange argument: assume there's an optimal solution that doesn't include the greedy choice. Swap one element with the greedy choice — show the solution remains at least as good. This gives a contradiction.
Examples
Example 1 — src/01_meeting_room.py
Maximum non-overlapping intervals.
Example 2 — src/02_coin_change.py
Greedy for Korean Won.
Example 3 — src/03_fractional_knapsack.py
Fractional knapsack — greedy works.
Example 4 — src/04_counterexample.py
Show that greedy fails for coins {1, 3, 4} when target is 6.
Common Mistakes
- Applying greedy where DP is needed (0/1 knapsack, arbitrary-coin change).
- Sorting by the wrong criterion — meeting rooms must sort by END, not start.
- Skipping the proof — always sanity-check with a small example.
- Forgetting strictness in comparisons (≥ vs >).
Recap
- Greedy = sort by the right key, then sweep.
- Proof: exchange argument or 'no-regret' reasoning.
- Not all problems admit greedy — check with examples first.
Try It
- BOJ 1931 (Meeting rooms).
- BOJ 11399 (ATM withdrawal time).
- BOJ 11047 (Coin 0 — Korean Won).
All lecture materials and example code are openly available on GitHub.
View on GitHub ↗