代码随想录算法训练营第34天 |第八章 贪心算法 part03

学习目标:

  • 1005.K次取反后最大化的数组和
  • 134. 加油站
  • 135. 分发糖果

学习内容:

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

//方法1
class Solution {
static bool cmp(int a, int b) {
    if(abs(a)> abs(b))
        return true;
    else
        return false;
}
public:
    int largestSumAfterKNegations(vector<int>& nums, int k) {
        sort(nums.begin(),nums.end(),cmp); //这个地方按照的是绝对值排序
        for(int i=0;i<nums.size();i++)
        {
            if(nums[i]<0 && k>0)
            {
                nums[i]=-nums[i];
                k--;
            }
        }
        //经过上一步后nums中所有负数已经变为正数,而使用的绝对值排序,所以最后一个是最小的正数
        if(k>0 && k%2!=0) nums[nums.size()-1] = nums[nums.size()-1] * (-1);
        int sum = 0;
        for(int i=0 ; i<nums.size();i++)
        {
            sum+=nums[i];
        }
        return sum;
    }
};

排序算法

sort函数需要调用#include <algorithm>库,自定义排序的时候定义static bool cmp.return true为降序排列,return false为升序排列。

错误以及注意事项

  • 这个方法真滴很巧妙。首先有限处理所有的负数,当所有的负数处理完后。找最小的正数反复折磨,但是由于是按照绝对值排序,所以不需要反复排序,直接取最后一个元素即可。

134. 加油站

class Solution {
public:
    int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
        int totalsum = 0;
        int cursum = 0;
        int startIndex = 0;
        for(int i = 0;i<gas.size();i++)
        {
            totalsum +=gas[i]-cost[i];
        }
        if(totalsum<0)
            return -1;
        for(int i = 0;i<gas.size();i++){
            cursum += gas[i]-cost[i];
            if(cursum<0){
                startIndex = i+1;
                cursum = 0;
            }
        }
        return startIndex;
    }
};

错误以及注意事项

  • 只学了方法二,方法一还没有搞明白。以及并不熟练。需要再做。

方法1:
直接从全局进行贪心选择,情况如下:
情况一:如果gas的总和小于cost总和,那么无论从哪里出发,一定是跑不了一圈的
情况二:rest[i] = gas[i]-cost[i]为一天剩下的油,i从0开始计算累加到最后一站,如果累加没有出现负数,说明从0出发,油就没有断过,那么0就是起点。
情况三:如果累加的最小值是负数,汽车就要从非0节点出发,从后向前,看哪个节点能把这个负数填平,能把这个负数填平的节点就是出发节点。

方法2:
i从0开始累加rest[i],和记为curSum,一旦curSum小于零,说明[0, i]区间都不能作为起始位置,因为这个区间选择任何一个位置作为起点,到i这里都会断油,那么起始位置从i+1算起,再从0计算curSum。

135. 分发糖果

class Solution {
public:
    int candy(vector<int>& ratings) {
        vector<int> candy(ratings.size(),1);
        for(int i = 1;i<ratings.size();i++)
        {
            if(ratings[i]>ratings[i-1])
                candy[i] = candy[i-1] +1;
        }
        for(int i = ratings.size()-2;i>=0;i--)
        {
            if(ratings[i]>ratings[i+1] && candy[i]<=candy[i+1])
                candy[i]=candy[i+1]+1;
        }
        int result=0;
        for(int i=0;i<candy.size();i++)
        {
            result += candy[i];
        }
        return result;

    }
};

错误以及注意事项

  • 第二个循环如果不是从后往前,而是继续从前往后,就会:
    在这个问题中,第二个循环的目的是为了处理评分降低但糖果数量不够的情况。如果我们从前往后遍历,我们可能会在处理某个位置时,已经将其分配的糖果数量增加了,但是后面的位置的糖果数量可能已经确定,我们不能再更改它们。
    因此,从后往前遍历确保了我们先处理评分较高的孩子,从而避免了在后面更改分配的糖果数量。这样可以确保我们在更新糖果数量时不会破坏前面的分配情况。

学习时间:

2024.2.26-2.27 11:25 焦虑。下周一周二面试。

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值