首页 > 编程语言 >算法刷题 Day 34 | ● 1005.K次取反后最大化的数组和 ● 134. 加油站 ● 135. 分发糖果

算法刷题 Day 34 | ● 1005.K次取反后最大化的数组和 ● 134. 加油站 ● 135. 分发糖果

时间:2023-02-09 21:36:18浏览次数:61  
标签:ratings nums int 取反 E6% 34 E5% vector 135

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

本题简单一些,估计大家不用想着贪心 ,用自己直觉也会有思路。

https://programmercarl.com/1005.K%E6%AC%A1%E5%8F%96%E5%8F%8D%E5%90%8E%E6%9C%80%E5%A4%A7%E5%8C%96%E7%9A%84%E6%95%B0%E7%BB%84%E5%92%8C.html

Tips:

  • 第一步:将数组按照绝对值大小从大到小排序,注意要按照绝对值的大小
  • 第二步:从前向后遍历,遇到负数将其变为正数,同时K--
  • 第三步:如果K还大于0,那么反复转变数值最小的元素,将K用完
  • 第四步:求和

我的题解:

class Solution {
public:
    int largestSumAfterKNegations(vector<int>& nums, int k) {
        sort(nums.begin(), nums.end());

        int sum = 0;

        for(int i = 0; i < nums.size(); i++){
            if(nums[i] < 0 && k > 0){
                nums[i] = -nums[i];
                k--;
            }
            sum += nums[i];
        }

        if(k == 0 || k % 2 == 0){
            return sum;
        }
        else{
            sort(nums.begin(),nums.end());
            sum -= nums[0] * 2;
            return sum;
        }        
    }
};

134.加油站

本题有点难度,不太好想,推荐大家熟悉一下方法二

https://programmercarl.com/0134.%E5%8A%A0%E6%B2%B9%E7%AB%99.html

Tips:

首先如果总油量减去总消耗大于等于零那么一定可以跑完一圈,说明 各个站点的加油站 剩油量rest[i]相加一定是大于等于零的。

每个加油站的剩余量rest[i]为gas[i] - cost[i]。

i从0开始累加rest[i],和记为curSum,一旦curSum小于零,说明[0, i]区间都不能作为起始位置,起始位置从i+1算起,再从0计算curSum。

如图: 134.加油站

那么为什么一旦[i,j] 区间和为负数,起始位置就可以是j+1呢,j+1后面就不会出现更大的负数?

如果出现更大的负数,就是更新j,那么起始位置又变成新的j+1了。

而且j之前出现了多少负数,j后面就会出现多少正数,因为耗油总和是大于零的(前提我们已经确定了一定可以跑完全程)。

那么局部最优:当前累加rest[j]的和curSum一旦小于0,起始位置至少要是j+1,因为从j开始一定不行。全局最优:找到可以跑一圈的起始位置

局部最优可以推出全局最优,找不出反例,试试贪心!

我的题解:

暴力法:(会超出时间限制)

class Solution {
public:
    int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
        for(int i = 0; i<gas.size(); i++){
            //这里 i 是起点
            int tank = gas[i];
            int j = i;
            while(tank>=cost[j]){
                tank -= cost[j];
                if(j < gas.size() - 1){
                    j++;
                }
                else{
                    j = 0;
                }
                if(j == i){
                    return i;
                }
                tank += gas[j];
            }         
        }
        return -1;
    }
};

贪心法:

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;
    }
};

135.分发糖果

本题涉及到一个思想,就是想处理好一边再处理另一边,不要两边想着一起兼顾,后面还会有题目用到这个思路

https://programmercarl.com/0135.%E5%88%86%E5%8F%91%E7%B3%96%E6%9E%9C.html

Tips:

这在leetcode上是一道困难的题目,其难点就在于贪心的策略,如果在考虑局部的时候想两边兼顾,就会顾此失彼。

那么本题我采用了两次贪心的策略:

  • 一次是从左到右遍历,只比较右边孩子评分比左边大的情况。
  • 一次是从右到左遍历,只比较左边孩子评分比右边大的情况。

这样从局部最优推出了全局最优,即:相邻的孩子中,评分高的孩子获得更多的糖果。

我的题解:

class Solution {
public:
    int candy(vector<int>& ratings) {
        int count = ratings.size();
        vector<int> candy = vector<int>(ratings.size(),1);
        for(int i = 1; i < ratings.size(); i++){
            if(ratings[i] > ratings[i-1] && candy[i] <= candy[i-1]){
                count += candy[i-1] + 1 - candy[i];
                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]){
                count += candy[i+1] + 1 - candy[i];
                candy[i] = candy[i+1] + 1;
            }
        }
        return count;

    }
};

标签:ratings,nums,int,取反,E6%,34,E5%,vector,135
From: https://www.cnblogs.com/GavinGYM/p/17107091.html

相关文章