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

文章讲述了如何使用贪婪算法解决三个LeetCode问题:1005.K次取反后最大化的数组和,通过排序和遍历策略最大化数组和;134.加油站,分析了暴力解法和贪心算法的解决方案;135.分发糖果,通过两次遍历确保评分高的孩子得到更多糖果。
摘要由CSDN通过智能技术生成

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

思路:把负数变为正数

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

代码

class Solution {
public:
    static bool cmp(int a, int b){
        return abs(a) > abs(b);
    }
    int minnum = INT_MAX;
    int count = 0;
    int sum = 0;
    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] = -1* nums[i];
            k--;
           }
         if(nums[i] < minnum){
            count = i;
            minnum = nums[i];  
        }  
         sum += nums[i];
    }
  if( k %2 == 0 ) return sum ;
  else 
      return sum - nums[count] * 2;
    }
};

134. 加油站

思路:暴力跑一圈把每个点都当成起点

遍历每一个加油站为起点的情况,模拟一圈。

如果跑了一圈,中途没有断油,而且最后油量大于等于0,说明这个起点是ok的。

代码:超时

class Solution {
public:
    int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
        int curgas = 0;
        int index = 0;
       for(int i = 0; i < gas.size(); i++)
       {
           curgas = gas[i];
           index = i;
            int j = i;
            int pointsum = gas.size();
           while(pointsum) {
               cout<<j<<endl;
               if(j + 1 < gas.size()){
                   if(curgas >= cost[j])curgas = curgas - cost[j] + gas[j+1]; 
                   else {
                        curgas = curgas - cost[j];
                         break;  
                   }
                    // cout<<curgas<<endl;
              }
               else{                          //从最后加油站到第一个加油站
                    if(curgas >= cost[j]){
                        curgas = curgas - cost[j] + gas[0];
                        j = -1;
                    }
                       else {
                        curgas = curgas - cost[j];
                       break;  
                   }
                 }     
               j++;
               pointsum--;       
          } 
        //  cout<<" "<<curgas<<" "<<index<<endl;
          if(curgas >= 0) return index; 
        } 
           if(curgas < 0)return -1;
           else return index;
       } 
};

思路:贪心算法

直接从全局进行贪心选择,情况如下:

情况一:如果gas的总和小于cost总和,那么无论从哪里出发,一定是跑不了一圈的

情况二:rest[i] = gas[i]-cost[i]为一天剩下的油,i从0开始计算累加到最后一站,如果累加没有出现负数,说明从0出发,油就没有断过,那么0就是起点。

情况三:如果累加的最小值是负数,汽车就要从非0节点出发,从后向前,看哪个节点能把这个负数填平,能把这个负数填平的节点就是出发节点。

代码:

class Solution {
public:
    int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
        int min = INT_MAX;//从起点出发最小油量
        int gassum = 0;//所有油量
        for(int i = 0; i < gas.size(); i++){
            int gasrest = gas[i] - cost[i];//当前剩的油量
            gassum += gasrest;
            if(min > gassum) min = gassum;
        }
        cout<<min<<endl;
        if(gassum < 0)return -1;//情况一
        if(min >= 0)return 0;//可以从0出发
        //情况3
         for(int i = gas.size() - 1; i >= 0; i--){
             int gasrest = gas[i] - cost[i];
             min += gasrest;
             if(min >=0)return i;
         }
         return -1;  
    }
};

135. 分发糖果

思路:确定一边后,再确定另一边

局部最优:只要右边评分比左边大,右边的孩子就多一个糖果,全局最优:相邻的孩子中,评分高的右孩子获得比左边孩子更多的糖果
1.右孩子比左孩子好,从前向后遍历在这里插入图片描述

//比较前一个,右孩子比左孩子好
        for(int i = 1; i < ratings.size(); i++){
            if(ratings[i] > ratings[i - 1]){
                casum[i] = casum[i - 1] + 1;
            }
        }

2.左孩子比右孩子好,从后向前遍历
在这里插入图片描述在这里插入图片描述

//比较后一个,左孩子比右孩子好,从后向前遍历
          for(int i = ratings.size() - 1; i >= 0; i--){
            if(i - 1 >= 0 && ratings[i - 1] > ratings[i]){
               if(casum[i - 1] <= casum[i]) casum[i - 1] = casum[i] + 1;
            }
        }

完整代码

class Solution {
public:
    int candy(vector<int>& ratings) {
        vector<int>casum(ratings.size(),1);//分糖果总数,每个人先分一颗
        int sum = 0;
        //比较前一个,右孩子比左孩子好
        for(int i = 1; i < ratings.size(); i++){
            if(ratings[i] > ratings[i - 1]){
                casum[i] = casum[i - 1] + 1;
            }
        }
        //比较后一个,左孩子比右孩子好,从后向前遍历
          for(int i = ratings.size() - 1; i >= 0; i--){
            if(i - 1 >= 0 && ratings[i - 1] > ratings[i]){
               if(casum[i - 1] <= casum[i]) casum[i - 1] = casum[i] + 1;
            }
        }
        for(int i = 0; i < casum.size(); i++){
            sum +=casum[i];
        }
      return sum;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值