Zowel DP als greedy hebben optimale substructuur nodig. Het verschil: greedy vereist ook de greedy-choice property (een lokaal optimum is globaal optimaal), terwijl DP nodig is wanneer je meerdere keuzes en overlappende subproblemen moet overwegen.
Zowel DP als greedy hebben optimale substructuur nodig. Het verschil: greedy vereist ook de greedy-choice property (een lokaal optimum is globaal optimaal), terwijl DP nodig is wanneer je meerdere keuzes en overlappende subproblemen moet overwegen.
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 legt zich vast op één keuze; DP verkent alles en houdt het beste.
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.
Greedy kiezen wanneer het geldig is bespaart enorm veel tijd; het kiezen wanneer het niet geldig is veroorzaakt stille bugs.
Weten welk paradigma past — en in staat zijn om het te bewijzen — is een onderscheid op senior-niveau.
Het voorkomt zowel over-engineering met DP als onder-leveren met een ondeugdelijke greedy-keuze.