-
1005K次取反后最大化的数组和
- 代码随想录 (programmercarl.com)
-
第一印象
- 可以分情况讨论数组中负数的个数n与k的关系。
- n<k即取反绝对值大的负数
- n=k即取反全部负数
- k-n为奇数则保留一个绝对值最小的负数
- k-n为偶数则等同于全部取反
-
讲解观后感
- 利用按照绝对值的排列方式,帮助省略实现了k的讨论过程,很巧妙。
-
解题代码
-
func largestSumAfterKNegations(nums []int, K int) int {
sort.Slice(nums, func(i, j int) bool {
return math.Abs(float64(nums[i])) > math.Abs(float64(nums[j]))
})
for i := 0; i < len(nums); i++ {
if K > 0 && nums[i] < 0 {
nums[i] = -nums[i]
K--
}
}
if K%2 == 1 {
nums[len(nums)-1] = -nums[len(nums)-1]
}
result := 0
for i := 0; i < len(nums); i++ {
result += nums[i]
}
return result
}
-
134加油站
- 代码随想录 (programmercarl.com)
-
第一印象
- 出发地肯定需要从一个有结余的节点开始,暴力的方法可以是遍历所有有结余的节点来检查。
-
讲解观后感
-
- 方法一
全局最优的方法。直接求得所有节点的剩余值,并寻找可以解决最低值的节点。不一定算是贪心算法,但解法巧妙,理解起来也不难。
-
- 方法二
区间剩余和小于0那么起始点就向后加1的方法,采用了局部最优的方式,是点型的贪心思想。
-
解题代码
- 方法一
-
func canCompleteCircuit(gas []int, cost []int) int {
curSum := 0
min := math.MaxInt64
var rest int
for i:=0;i<len(gas);i++ {
rest = gas[i] - cost[i]
curSum += rest
if curSum < min {
min = curSum
}
}
if curSum < 0 {
return -1
}
if min>=0 {
return 0
}
for j:=len(gas)-1;j>=0;j-- {
rest = gas[j] - cost[j]
min += rest
if min>=0 {
return j
}
}
return -1
}
- 方法二
-
func canCompleteCircuit(gas []int, cost []int) int {
curSum := 0
totalSum := 0
start := 0
for i := 0; i < len(gas); i++ {
curSum += gas[i] - cost[i]
totalSum += gas[i] - cost[i]
if curSum < 0 {
start = i+1
curSum = 0
}
}
if totalSum < 0 {
return -1
}
return start
}
-
135分发糖果
- 代码随想录 (programmercarl.com)
-
第一印象
- 想办法统计极值点出现的位置,并确定极值两头的高度。
-
讲解观后感
- 这在leetcode上是一道困难的题目,其难点就在于贪心的策略,如果在考虑局部的时候想两边兼顾,就会顾此失彼。
本题卡尔采用了两次贪心的策略:
- 一次是从左到右遍历,只比较右边孩子评分比左边大的情况。
- 一次是从右到左遍历,只比较左边孩子评分比右边大的情况。
- 所以就取
candyVec[i + 1] + 1 和 candyVec[i] 最大的糖果数量,candyVec[i]只有取最大的才能既保持对左边candyVec[i - 1]的糖果多,也比右边candyVec[i + 1]的糖果多。
-
解题代码
-
func candy(ratings []int) int {
need := make([]int, len(ratings))
sum := 0
// 初始化(每个人至少一个糖果)
for i := 0; i < len(ratings); i++ {
need[i] = 1
}
// 1.先从左到右,当右边的大于左边的就加1
for i := 0; i < len(ratings) - 1; i++ {
if ratings[i] < ratings[i+1] {
need[i+1] = need[i] + 1
}
}
// 2.再从右到左,当左边的大于右边的就右边加1,但要花费糖果最少,所以需要做下判断
for i := len(ratings)-1; i > 0; i-- {
if ratings[i-1] > ratings[i] {
need[i-1] = findMax(need[i-1], need[i]+1)
}
}
//计算总共糖果
for i := 0; i < len(ratings); i++ {
sum += need[i]
}
return sum
}
func findMax(num1 int, num2 int) int {
if num1 > num2 {
return num1
}
return num2
}