Think about when making the best local choice leads to a global best solution.
Greedy algorithms work when the problem has the greedy choice property, meaning a local optimal choice leads to a global optimum, and optimal substructure, meaning optimal solutions to subproblems build the overall solution.
coins = [25, 10, 5, 1] amount = 30 result = [] for coin in coins: while amount >= coin: amount -= coin result.append(coin) print(result)
Check how the greedy approach picks the largest coin first and subtracts until it can't.
The greedy approach picks 25 first, then 5 to make 30. It does not try to use three 10s because 25 is larger and chosen first.
dp = [0, 1] + [0]*4 for i in range(2, 6): dp[i] = dp[i-1] + dp[i-2] print(dp)
Remember Fibonacci starts with 0,1 and each next number is sum of previous two.
The dp array stores Fibonacci numbers from 0 to 5: 0,1,1,2,3,5.
Think about when greedy choices do not lead to the best overall solution.
Dynamic programming is used when problems have overlapping subproblems and optimal substructure but lack the greedy choice property, so greedy algorithms may fail.
Think about how to pick jobs to maximize profit without conflicts.
The job scheduling with deadlines problem is classically solved by a greedy approach that sorts jobs by profit and schedules each in the latest free slot before its deadline.
