[代码随想录]Day29-贪心算法part03

题目:1005.K次取反后最大化的数组和

思路:

思路是:

  1. 先把负数从小到大变成正数(即绝对值由大到小)
  2. 如果还需要变化(k>0),就变化最小的数

在第一步变化的同时顺便记录一个数组和,那么结束之后会有三种情况:

  1. k == 0;也就是说负数的个数大于等于k,直接返回结果
  2. k % 2 == 0; 此时全是正整数,如果k是偶数的话,可以相当于没有变化,直接返回结果
  3. k % 2 != 0; 此时全是正整数,如果k是奇数的话,需要把最小的数变成负数,因为之前res里已经添加了最小,因此需要- 2 * nums[0]

代码1:

func largestSumAfterKNegations(nums []int, k int) int {
    res := 0
    lens := len(nums)
    sort.Ints(nums) // 排序
    for i := 0; i < lens; i++ { // 一边把负数变正一边求和
        if nums[i] >= 0 {  // 求和1
            res += nums[i]
            continue
        }
        if k > 0 { // 如果k大于0就可以变
            nums[i] = -nums[i]
            k--
        }
        res += nums[i] // 求和2
    }
    sort.Ints(nums) // 变完之后再排序一次
    if k % 2 == 1 { // 如果k剩下奇数个,把最小的元素去掉即可(因为之前加了,所以要减去2 * nums[0]
        res -= 2 * nums[0]
    }
    return res
}

代码2:

func largestSumAfterKNegations(nums []int, k int) int {
    res := 0
    lens := len(nums)
    sort.Slice(nums, func(i, j int) bool { // 用这个直接求绝对值的排序(由大到小)
        return math.Abs(float64(nums[i])) > math.Abs(float64(nums[j]))
    })
    for i := 0; i < lens; i++ {
        if nums[i] >= 0 {
            res += nums[i]
            continue
        }
        if k > 0 { // 这样也会先添加大的负数
            nums[i] = -nums[i]
            k--
        }
        res += nums[i]
    }
    if k % 2 == 1 {
        res -= 2 * nums[lens-1] // 最小的元素是nums[lens-1]
    }
    return res
}

参考:

代码随想录

题目:134. 加油站

思路:

其实这个思路和最大子序列和差不多:如果正向是负向效果(油会更少),那么在这里开始肯定不行所以没必要遍历这种index,如果是正向效果,那我的tmp之前有数的话岂不是更好?所以直接for一边就可以。

代码:

func canCompleteCircuit(gas []int, cost []int) int {
    gas = append(gas, gas...)
    cost = append(cost, cost...)
    lens := len(gas)
    tmp := 0
    index := 0 // 记录起始位置
    for i := 0; i < lens; i++ {
        tmp += gas[i] - cost[i] // 记录当前剩下的油
        if tmp < 0 { // 小于0就跑不了
            tmp = 0
            index = i + 1 // 试试下一个点
            continue
        }
        if i - index == lens / 2 - 1 { // 如果跑完了全程就返回index
            return index
        }
    }
    return -1
}

参考:

代码随想录

题目:135. 分发糖果

思路:

本题采用了两次贪心的策略:
一次是从左到右遍历,只比较右边孩子评分比左边大的情况。
一次是从右到左遍历,只比较左边孩子评分比右边大的情况。
这样从局部最优推出了全局最优,即:相邻的孩子中,评分高的孩子获得更多的糖果。

代码:

func candy(ratings []int) int {
    /**先确定一边,再确定另外一边
        1.先从左到右,当右边的大于左边的就加1
        2.再从右到左,当左边的大于右边的就再加1
    **/
    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
}

参考:

代码随想录

posted @   WtcSky  阅读(6)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示