Which condition best indicates that a greedy algorithm is suitable instead of dynamic programming?
Think about when greedy algorithms can make decisions step-by-step without revisiting previous choices.
Greedy algorithms work well when the problem has optimal substructure but no overlapping subproblems, allowing local choices to lead to a global optimum without revisiting states.
What is the output of the following Go code that tries to find the minimum coins for amount 6 using coins [1, 3, 4]?
package main import "fmt" func greedyCoinChange(coins []int, amount int) int { count := 0 for i := len(coins) - 1; i >= 0; i-- { for amount >= coins[i] { amount -= coins[i] count++ } } if amount != 0 { return -1 } return count } func main() { coins := []int{1, 3, 4} amount := 6 fmt.Println(greedyCoinChange(coins, amount)) }
Trace how the greedy picks coins starting from the largest coin.
The greedy picks 4 once (amount=2 left), then picks 1 twice, total 3 coins. But the optimal solution is 2 coins (3+3). Greedy returns 3 here.
What is the output of this Go code that uses dynamic programming to find minimum coins for amount 6 with coins [1, 3, 4]?
package main import "fmt" import "math" func dpCoinChange(coins []int, amount int) int { dp := make([]int, amount+1) for i := 1; i <= amount; i++ { dp[i] = math.MaxInt32 for _, c := range coins { if i-c >= 0 && dp[i-c] != math.MaxInt32 { if dp[i-c]+1 < dp[i] { dp[i] = dp[i-c] + 1 } } } } if dp[amount] == math.MaxInt32 { return -1 } return dp[amount] } func main() { coins := []int{1, 3, 4} amount := 6 fmt.Println(dpCoinChange(coins, amount)) }
Dynamic programming tries all combinations to find the minimum coins.
The DP finds the minimum coins as 2 (3 + 3) which is better than greedy's 3 coins.
What error does the following Go code produce when trying to select maximum activities using a greedy approach?
package main import "fmt" type Activity struct { start, end int } func maxActivities(activities []Activity) int { count := 1 prevEnd := activities[0].end for i := 1; i < len(activities); i++ { if activities[i].start > prevEnd { count++ prevEnd = activities[i].end } } return count } func main() { acts := []Activity{{1,3},{2,5},{4,7},{6,9}} fmt.Println(maxActivities(acts)) }
Check if the activities are sorted correctly before applying greedy.
The code assumes activities are sorted by end time but they are not, so the greedy picks suboptimal activities. The output is 3.
Which reason best explains why dynamic programming is necessary instead of greedy algorithms for some problems?
Think about when greedy local choices fail to find the best overall solution.
Dynamic programming is needed when problems have overlapping subproblems and greedy choices can lead to suboptimal solutions, requiring exploration of all subproblems.
