代码随想录训练营Day 36|力扣1005.K次取反后最大化的数组和、134. 加油站、135. 分发糖果

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

代码:(贪心算法)

class Solution {
public:
    static bool cmp(int a,int b){
        return abs(a) > abs(b);
    }
    int largestSumAfterKNegations(vector<int>& nums, int k) {
        sort(nums.begin(),nums.end(),cmp); // 把数组按照绝对值大小排序
        int sum = 0;
        for(int i = 0;i < nums.size();i++){
            if(nums[i] < 0 && k > 0){ // 遇到负数,就把它当成负数相加
                k--;
                nums[i] = 0 - nums[i];
            }
            sum += nums[i];
        }
        if(k % 2 == 1){
            sum = sum - nums[nums.size() - 1] + (0 - nums[nums.size() - 1]);
            // 1 2 3 -6
            // sum = sum - (-6) + (0 - (-6))
        }
        return sum;
    }   
};

 思路:

这道题怎么贪?

先把数组里的负数,按照绝对值大小排序。遇到负数,就耗费k一次,把它变成正数。

局部最优为:尽可能地加更多的正数;全局最优:总和最大

那如果遍历了一次数组,k还没用完怎么办?

局部最优:取绝对值最小的数来切换正负,消耗完所有的k;全局最优:使得正负的改变,对总和的影响最小。

2.加油站

 代码:(贪心算法)

class Solution {
public:
    int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
        int cursum = 0;
        int totalsum = 0;
        int start = 0;
        for(int i = 0;i < gas.size();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;
    }
};

思路:

这道题怎么贪?

局部最优是:当前净油量必须大于0才能继续行驶;全局最优:成功从起始位置到终止位置

当前的“净油量”是什么?

就是目前走过的每个站点 加的油量 - 消耗的油量。

你怎么找起始位置?怎么判断是否能走完全程?

起始位置start,通过我们的净油量来看。如果净油量已经小于0,代表这个站点,以及之前的站点都不能作为起始位置,选择下一站作为我们的起始位置。这样遍历一圈,看看最后start最后是多少。(而且题上说:如果存在解,则 保证 它是 唯一 的。所有求到的start就是唯一的。)

判断是否有解,是通过累计所有站点的净油量totalsum。 如果小于0,说明不可能走完全程。

3.分发糖果

代码: 

class Solution {
public:
    int candy(vector<int>& ratings) {
        vector<int> result(ratings.size() ,1);
        int sum = 0;
        // 从左到右遍历 如果右边大于左边,则其分数要比左边多1
        for(int i = 1;i < ratings.size();i++){
            if(ratings[i - 1] < ratings[i]){
                result[i] = result[i - 1] + 1;
            }
        }
        // 从右到左遍历 如果左边大于右边,则其分数要比右边多1
        for(int i = ratings.size() - 1; i > 0;i--){
            if(ratings[i - 1] > ratings[i]){
                result[i - 1] = max(result[i] + 1,result[i - 1]);
            }
        }
        // 计算糖果总和
        for(int i = 0;i < result.size();i++){
            sum += result[i];
        }
        return sum;
    }
};

思路:

这种涉及到考虑多个因素的题,要一个一个来考虑,不要想着一次性全做好(人生也是这样

那你怎么取分别考虑呢?

我第一次从左到右遍历数组,如果右边大于左边的分数,那就让其糖果数比左边的多一个。

第二次从右到左遍历数组,如果左边大于右边的分数,那就让其糖果数比右边的多一个(这个数,要和上一次得到的糖果数取一个最大值)。 

为什么第二次的遍历顺序是从右到左遍历呢?

因为 rating[5]与rating[4]的比较 要利用上 rating[5]与rating[6]的比较结果,所以 要从后向前遍历。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值