● 860.柠檬水找零
● 406.根据身高重建队列
● 452. 用最少数量的箭引爆气球
1. 柠檬水找零
关联 leetcode 860.柠檬水找零
-
思路
- 使用金额的三种情况
- 情况一 :
- 账单是5, 直接收下
- 情况二 :
- 账单是10, 消耗一个5, 收获一个10
- 情况三 :
- 账单是20, 优先消耗一个10和一个5,如果不够,再消耗三个5
- 情况一 :
- 贪心[ 针对情况三 ]
- 局部
- 优先消耗 10元, 5元的更万能
- 全局
- 完成账单清零
- 局部
- 使用金额的三种情况
-
题解
func lemonadeChange(bills []int) bool { if bills[0] > 5 || len(bills) < 1 { return false } restMoney := make(map[int]int) //剩余零钱, 可以用数字提升效率, 这里用map看的更清楚 for _, b := range bills { switch b { case 5: restMoney[5] += 1 case 10: restMoney[5] -= 1 if restMoney[5] < 0 { return false } restMoney[10] += 1 case 20: if restMoney[10] > 0 { restMoney[10] -= 1 restMoney[5] -= 1 } else { restMoney[5] -= 3 } if restMoney[5] < 0 { return false } restMoney[20] += 1 // 这一步可以不要, 20不会用来找零 } } return true }
2. 根据身高重建队列
关联 leetcode 406.根据身高重建队列
-
思路
- 两个指标出现时, 每次解决一个指标
- 本题的 k, h 每次贪一个指标
- 本题来说
- 身高是绝对序列, 唯一有序
- 前面的人数是可能唯一有序
- 选择 身高 作为第一次遍历指标
- 贪心
- 前提 已经按照身高降序排序,
- 再按照 k 值升序
- k小的前面人更少, 所以这个人在更前面的位置
- 局部最优
- 优先按身高高的people的k来插入。插入操作过后的people满足队列属性
- 全局最优
- 最后都做完插入操作,整个队列满足题目队列属性
- 两个指标出现时, 每次解决一个指标
-
题解
func reconstructQueue(people [][]int) [][]int { sort.Slice(people, func(i, j int) bool { if people[i][0] == people[j][0] { return people[i][1] < people[j][1] } return people[i][0] > people[j][0] }) rets := make([][]int, len(people)) for i := 0; i < len(people); i++ { insertVal := people[i] insertIdx := people[i][1] //插入 if rets[insertIdx] == nil { rets[insertIdx] = insertVal continue } before := rets[:insertIdx] after := make([][]int, len(rets[insertIdx:])) copy(after, rets[insertIdx:]) before = append(before, insertVal) rets = append(before, after...) } return rets[:len(people)] }
3. 用最少数量的箭引爆气球
关联 leetcode 452. 用最少数量的箭引爆气球
-
思路
- 贪心
- 局部最优
- 重叠最多的气球
- 全局最优
- 最少的箭
- 局部最优
- 排序
- 选择左/右边界来排序
- 算重叠
- 当前 左边界 与 前一个 右边界关系
- 算重叠
- 选择左/右边界来排序
- 贪心
-
题解
func findMinArrowShots(points [][]int) int { if len(points) < 2 { return len(points) } sort.Slice(points, func(i, j int) bool { return points[i][0] < points[j][0] }) res := 1 //至少需要一只箭 for i := 1; i < len(points); i++ { // i从1开始, 要与左边的相比, 至少是从左开始数第二个 if points[i][0] > points[i-1][1] { // 当前的左边 比 前一个的右边大 res++ //多需要一只箭 } else { // 当前的左边 <= 上一个右边 == 当前的气球和上一个气球有重叠或贴边 points[i][1] = min(points[i-1][1], points[i][1]) // 更新重叠气球的最小右边界 } } return res } func min(a, b int) int { if a < b { return a } return b }