A greedy algorithm builds a solution one step at a time, and at every step it makes whatever choice looks best right now — without reconsidering that choice later. There's no backtracking, no exploring alternatives, no looking ahead: just commit to the locally optimal option and move on. That makes greedy algorithms simple to write and usually very fast, but it comes with a catch — the locally optimal choice doesn't always add up to the globally optimal solution.
Example Where Greedy Works: Coin Change
With standard currency denominations like 25, 10, 5, and 1, you can make change for any amount by always picking the largest coin that doesn't exceed what's left — and that greedy strategy happens to always produce the fewest possible coins.
def greedy_coin_change(amount, coins):
coins = sorted(coins, reverse=True)
result = []
for coin in coins:
while amount >= coin:
amount -= coin
result.append(coin)
return result
print(greedy_coin_change(67, [25, 10, 5, 1]))
Output:
[25, 25, 10, 5, 1, 1]
Six coins, and there's genuinely no way to make 67 cents with fewer coins using this denomination set — the greedy choice at each step really was optimal.
Example Where Greedy Works: Activity Selection
Given a set of activities with start and end times, and the goal of scheduling as many non-overlapping activities as possible in one room, the greedy strategy is: always pick the activity that finishes earliest among the ones still available. This leaves the most remaining time for everything after it, and it provably produces the maximum possible number of scheduled activities.
When Greedy Fails
Here's the catch, made concrete: with a non-standard coin system — say denominations of 1, 3, and 4 — greedy breaks down. To make 6, greedy grabs the largest coin first (4), leaving 2, which it can only make as 1+1 — three coins total (4, 1, 1). But the actual optimal answer is two coins: 3 + 3. The locally "obvious" choice (grab the biggest coin) led to a solution that isn't globally optimal.
This is exactly why general coin-change problems (with arbitrary denominations) are typically solved with dynamic programming instead of a greedy approach — DP correctly considers every combination via overlapping subproblems, while greedy just commits and never looks back.
How to Know If Greedy Will Work
A greedy strategy only produces a correct, globally optimal answer when the problem has what's called the greedy-choice property — making the locally best choice never rules out reaching the globally best solution. There's no universal shortcut for proving this; it generally takes either a formal proof (often by showing an exchange argument: any optimal solution can be transformed into the greedy solution without making it worse) or enough intuition built from seeing where greedy has and hasn't worked before. When in doubt, and especially under interview time pressure, it's often safer to default to dynamic programming and only reach for greedy once you can clearly justify why the locally best choice is always safe.
