● 1005.K次取反后最大化的数组和
● 134. 加油站
● 135. 分发糖果
1005.K次取反后最大化的数组和
关联 leetcode 1005.K次取反后最大化的数组和
-
思路
- 优先对负数取反
- 优先对绝对值最大的负数取反
- 贪两次
- 先将所有负数取反 ===》全正整数
- 将最小的数进行剩下的取反操作
- 优先对负数取反
-
题解
func largestSumAfterKNegations(nums []int, k int) int { res := 0 // 对数组按绝对值排序: 倒序排列,保证优先处理到的是最大的负数 sort.Slice(nums, func(i, j int) bool { fi := float64(nums[i]) fj := float64(nums[j]) return math.Abs(fi) > math.Abs(fj) }) for i := 0; i < len(nums); i++ { if nums[i] < 0 && k > 0 { //翻转负数 nums[i] = -nums[i] k-- } } // 翻转当前数组最小数剩下的k次 if k%2 == 1 {// nums[len(nums)-1] *= -1 } for _, num := range nums { res += num } return res }
134. 加油站
关联 leetcode 134. 加油站
-
思路
- 单向行驶,运动方向固定
- 先收获当前加油站的汽油,再开向下一个加油站,消耗汽油
- 如果有解只有唯一解
- 找到合法解就返回
- 有效出发点:
- 获得 汽油数>消耗数
- 贪最多的
- 获得 汽油数>消耗数
- 当前累计油耗 < 0:
- 从该位置的后一个位置出发
-
题解
func canCompleteCircuit(gas []int, cost []int) int { res := 0 //默认从第0号索引出发 即 第一个元素 curSum, totalSum := 0, 0 for i := 0; i < len(gas); i++ { curSum += gas[i] - cost[i] totalSum += gas[i] - cost[i] //总数直接累计 if curSum < 0 { //当前累计剩余油量小于零, 从改该位置后一个位置开始出发 res = i + 1 //从下一个位置开始 curSum = 0 //curSum重新从0开始累计 } } if totalSum < 0 { //总剩余油量totalSum小于0,说明无法环绕一圈 return -1 } return res }
135. 分发糖果
关联 leetcode 135. 分发糖果
-
思路
- 先确定比较每一个孩子的左边(/右边), 再去比较剩余的那边
- 如果两边一起比较一定会顾此失彼
- 贪心
- 先贪右边, 右边评分更高
- 从前往后遍历
- 局部最优
- 右边评分 > 左边
- 右边糖果+1
- 右边评分 > 左边
- 全局最优
- 相邻孩子:
- 评分高的右孩子比左孩子有更多糖果
- 相邻孩子:
- 再贪左边
- 从后往前遍历
- 局部最优
- 取 (当前孩子的糖果数量) 和 (右孩子+1) 相比最大的值
- 全局最优
- 当前中间评分最高的孩子比他 左边 和 右边 的糖果都多
- 最终
- 相邻孩子,评分更高的糖果更多
- 先贪右边, 右边评分更高
- 先确定比较每一个孩子的左边(/右边), 再去比较剩余的那边
-
题解
func candy(ratings []int) int { res := 0 //初始化分糖数组, 每个值都是1, 保证最小一颗 candyArr := make([]int, len(ratings)) for i := 0; i < len(candyArr); i++ { candyArr[i] = 1 } //向右贪 for i := 1; i < len(ratings); i++ { if ratings[i] > ratings[i-1] { candyArr[i] = candyArr[i-1] + 1 } } //向左贪 for i := len(ratings) - 1; i > 0; i-- { if ratings[i-1] > ratings[i] { candyArr[i-1] = max(candyArr[i-1], candyArr[i]+1) } } for _, c := range candyArr { res += c } return res } func max(a, b int) int { if a > b { return a } return b }