贪心算法经典题目及Golang实现
贪心算法是一种在每一步选择中都采取当前状态下最优的选择,从而希望导致全局最优解的算法策略。以下是一些LeetCode上经典的贪心算法题目及其Golang实现,并总结一个通用的解题模板。
经典贪心题目及Golang实现
1. 分发饼干 (455. Assign Cookies)
1 2 3 4 5 6 7 8 9 10 11 12 13
| func findContentChildren(g []int, s []int) int { sort.Ints(g) sort.Ints(s) child, cookie := 0, 0 for child < len(g) && cookie < len(s) { if s[cookie] >= g[child] { child++ } cookie++ } return child }
|
2. 无重叠区间 (435. Non-overlapping Intervals)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| func eraseOverlapIntervals(intervals [][]int) int { if len(intervals) == 0 { return 0 } sort.Slice(intervals, func(i, j int) bool { return intervals[i][1] < intervals[j][1] }) count := 1 end := intervals[0][1] for i := 1; i < len(intervals); i++ { if intervals[i][0] >= end { count++ end = intervals[i][1] } } return len(intervals) - count }
|
3. 用最少数量的箭引爆气球 (452. Minimum Number of Arrows to Burst Balloons)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| func findMinArrowShots(points [][]int) int { if len(points) == 0 { return 0 } sort.Slice(points, func(i, j int) bool { return points[i][1] < points[j][1] }) arrows := 1 pos := points[0][1] for i := 1; i < len(points); i++ { if points[i][0] > pos { arrows++ pos = points[i][1] } } return arrows }
|
4. 买卖股票的最佳时机 II (122. Best Time to Buy and Sell Stock II)
1 2 3 4 5 6 7 8 9
| func maxProfit(prices []int) int { profit := 0 for i := 1; i < len(prices); i++ { if prices[i] > prices[i-1] { profit += prices[i] - prices[i-1] } } return profit }
|
5. 跳跃游戏 (55. Jump Game)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| func canJump(nums []int) bool { farthest := 0 for i := 0; i < len(nums); i++ { if i > farthest { return false } farthest = max(farthest, i+nums[i]) } return true }
func max(a, b int) int { if a > b { return a } return b }
|
6. 跳跃游戏 II (45. Jump Game II)
1 2 3 4 5 6 7 8 9 10 11
| func jump(nums []int) int { jumps, curEnd, farthest := 0, 0, 0 for i := 0; i < len(nums)-1; i++ { farthest = max(farthest, i+nums[i]) if i == curEnd { jumps++ curEnd = farthest } } return jumps }
|
7. 加油站 (134. Gas Station)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| func canCompleteCircuit(gas []int, cost []int) int { total, curr, start := 0, 0, 0 for i := 0; i < len(gas); i++ { total += gas[i] - cost[i] curr += gas[i] - cost[i] if curr < 0 { start = i + 1 curr = 0 } } if total >= 0 { return start } return -1 }
|
8. 任务调度器 (621. Task Scheduler)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| func leastInterval(tasks []byte, n int) int { freq := make([]int, 26) for _, t := range tasks { freq[t-'A']++ } sort.Ints(freq) maxFreq := freq[25] idleSlots := (maxFreq - 1) * n for i := 24; i >= 0 && freq[i] > 0; i-- { idleSlots -= min(freq[i], maxFreq-1) } if idleSlots > 0 { return idleSlots + len(tasks) } return len(tasks) }
func min(a, b int) int { if a < b { return a } return b }
|
贪心算法通用模板
虽然贪心算法没有固定的模板,但通常可以遵循以下步骤:
- 排序:很多贪心问题需要对输入数据进行排序
- 初始化:设置必要的变量(如计数器、指针等)
- 遍历处理:遍历排序后的数据,做出贪心选择
- 验证结果:检查是否满足题目要求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| func greedyAlgorithm(input []Type) ResultType { sort.Slice(input, func(i, j int) bool { return compare(input[i], input[j]) }) result := 0 current := initialValue for _, item := range input { if canMakeGreedyChoice(current, item) { update(current, item) result++ } } return result }
|
贪心算法适用场景
贪心算法通常适用于以下类型的问题:
- 可以分解为子问题的问题
- 子问题的最优解能递推到最终问题的最优解
- 无后效性,即某个状态以后的过程不会影响以前的状态
常见应用场景包括:
- 分配问题(如分发饼干)
- 区间问题(如无重叠区间)
- 调度问题(如任务调度器)
- 股票买卖问题
- 跳跃游戏类问题
贪心算法的关键在于证明贪心策略的正确性,这通常需要数学证明或直观理解。在实际应用中,如果无法确定贪心策略是否正确,可以先尝试,然后验证是否能够得到全局最优解。