Both DP and greedy need optimal substructure. The difference: greedy also requires the greedy-choice property (a local optimum is globally optimal), while DP is needed when you must consider multiple choices and overlapping subproblems.
Both DP and greedy need optimal substructure. The difference: greedy also requires the greedy-choice property (a local optimum is globally optimal), while DP is needed when you must consider multiple choices and overlapping subproblems.
Optimal substructure? -- both need this
+ greedy-choice property holds? -> GREEDY (fast, one pass of choices)
+ must compare many sub-solutions / they overlap? -> DYNAMIC PROGRAMMING
# Greedy FAILS for coins {1,3,4}, amount 6 -> 4+1+1 (3 coins)
# DP finds the true optimum: 3+3 (2 coins)
def min_coins(amount, coins):
INF = float('inf')
dp = [0] + [INF] * amount
for a in range(1, amount + 1):
for c in coins:
if c <= a:
dp[a] = min(dp[a], dp[a - c] + 1) # try every coin
return dp[amount]
min_coins(6, [1, 3, 4]) # -> 2
Greedy commits to one choice; DP explores all and keeps the best.
Greedy is usually O(n log n); DP trades more time/space (often O(n·m)) for correctness.
Using greedy without proving its property gives wrong answers that pass small tests. When in doubt, reach for DP or verify greedy against brute force.
Picking greedy when it is valid saves enormous time; picking it when it is not produces silent bugs.
Knowing which paradigm fits — and being able to prove it — is a senior-level distinction.
It prevents both over-engineering with DP and under-delivering with an unsound greedy choice.
A library of IT interview questions with detailed answers — from Junior to Senior.
Donate