算法学习 | day29/60 K次取反后最大化的数组和/加油站/分发糖果

一、题目打卡

        1.1 k次取反后最大化的数组和

        题目链接:. - 力扣(LeetCode)

class Solution {
public:
    int largestSumAfterKNegations(vector<int>& nums, int k) {
        sort(nums.begin(),nums.end()); // 首先需要排序一下
        for(auto &it : nums){
            if(it<=0){
                it = it * -1;
                k--;
            }
            if(k==0) break;
        }
        sort(nums.begin(),nums.end());
        // for(auto &it:nums){
        //     cout << it << endl;
        // }
        while(k > 0){
            nums[0] = nums[0] * -1;
            k--;
        }

        int res = 0;
        for(auto &it : nums){
            res += it;
        }
        return res;
    }
};

        整体的思路是,先进行排序,然后在 k 次数大于0的情况下,尽可能多的去取反绝对值比较大的负数,如果没有负数了,并且反转的次数也还没有用完,那就再次进行扭转,这时候就一直反转最小的正数或者是0就行了。

        1.2 加油站

        题目链接:. - 力扣(LeetCode)        

// 尝试的第一版,直接贪心找到差值最大的位置,这样会出现问题:
/*
    [5,8,2,8]
    [6,5,6,6]
*/
// class Solution {
// public:
//     int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
//         int diff = INT_MIN;
//         int startInd;
//         int size = gas.size(); // 这里必须要提前统计,否则会不断循环
//         for(int i = 0 ; i < size;i++){
//             gas.push_back(gas[i]);
//             cost.push_back(cost[i]);
//             if(diff < gas[i] - cost[i]){
//                 diff = gas[i] - cost[i];
//                 startInd = i;
//             }
//         }
//         // queue<int> q;
//         // for(int i = 0 ; i < gas.size();i++){
//         //     // if(gas[i] - cost[i] > max_diff){
//         //     // 方便后面继续进行搜索
//         //     gas.push_back(gas[i]);
//         //     cost.push_back(cost[i]);
//         //     diff = gas[i] - cost[i];
//         //     if(diff > 0) q.push(i); // 存储所有可以作为起点的位置
//         //     // }
//         // }

//         // while(!q.empty()){
//         //     startInd = q.front();
//         //     q.pop();
//         //     // 初始化油量
//         //     int fuel = 0;
//         //     for(int ind = startInd; ind < startInd + gas.size(); ind++){
//         //         fuel = fuel + gas[ind] - cost[ind];
//         //         if(fuel < 0 ) break;
//         //         if(fuel >= 0 && ind + 1 == startInd + gas.size()) return startInd;
//         //     }
//         // }
//         // 初始化油量
//         int fuel = 0;
//         for(int ind = startInd; ind < startInd + size; ind++){
//             fuel = fuel + gas[ind] - cost[ind];
//             if(fuel < 0 ) break;
//             if(fuel >= 0 && ind + 1 == startInd + size) return startInd;
//         }
//         return -1;
//     }
// };

// class Solution {
// public:
//     int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
//         // int diff = INT_MIN;
//         // int startInd;
//         if(gas.size() == 1 && gas[0] >= cost[0]) return 0;
//         if(gas.size() == 1 && gas[0] < cost[0]) return -1;
//         int size = gas.size(); // 这里必须要提前统计,否则会不断循环
//         vector<int> startInds;
//         for(int i = 0 ; i < size;i++){
//             gas.push_back(gas[i]);
//             cost.push_back(cost[i]);
//             if(gas[i] - cost[i] > 0){ 
//                 startInds.push_back(i);
//             }
//         }
//         // 初始化油量
//         for(auto &startInd : startInds){
//             int fuel = 0;
//             for(int ind = startInd; ind < startInd + size; ind++){
//                 fuel = fuel + gas[ind] - cost[ind];
//                 if(fuel < 0 ) break;
//                 if(fuel >= 0 && ind + 1 == startInd + size) return startInd;
//             }
//         }
//         return -1;
//     }
// };

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

        题目我用暴力解法做了做,勉强通过了,暴力的思路也很简单,就是遇到差值是正的时候就进行检验,这时候就肯定是一个双层循环了,答案是用while写的,我感觉那种方法自己一直不太适应,我用的是增加列表的方法,还是答案方法更好一点:

class Solution {
public:
    int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
        for (int i = 0; i < cost.size(); i++) {
            int rest = gas[i] - cost[i]; // 记录剩余油量
            int index = (i + 1) % cost.size();
            while (rest > 0 && index != i) { // 模拟以i为起点行驶一圈(如果有rest==0,那么答案就不唯一了)
                rest += gas[index] - cost[index];
                index = (index + 1) % cost.size();
            }
            // 如果以i为起点跑一圈,剩余油量>=0,返回该起始位置
            if (rest >= 0 && index == i) return i;
        }
        return -1;
    }
};

        不过这个题目本身还是考察贪心的解法,我看了下答案的两个解法,感觉第二个稍微好理解一点,然后看了答案自己写了一次,我感觉这个关键的一个思路就是:如果当前累加的和为负数了,那么开始的位置一定是在这个位置的后面,这个思想虽然证明的过程我理解不了,但是代码过程还是比较好理解的,这里注意需要维护一个整体的和,最终用来判断是否可以完成闭环。

        1.3 分发糖果

        题目链接:. - 力扣(LeetCode)

// class Solution {
// public:
//     int candy(vector<int>& ratings) {
//         if(ratings.size() == 1) return 1;
//         if(ratings.size() == 2) return ratings[0] == ratings[1] ? 2 : 3;
//         vector<bool> flag(ratings.size(),false);
//         for(int i = 1 ; i < ratings.size() - 1 ; i++){
//             // if(!flag[i - 1] && ratings[i] > ratings[i - 1]){
//             if(ratings[i] > ratings[i - 1]){
//                 flag[i] = true;
//             }
//         }
//         // if(ratings[0] > ratings[1]) flag[0] = true;
//         // if(ratings.back() > ratings[ratings.size() - 2]) flag[ratings.size() - 1] = true;
//         if(ratings[0] > ratings[1]) flag[0] = true;
//         else if (ratings[0] < ratings[1]) flag[1] = true; 
//         if(ratings.back() > ratings[ratings.size() - 2]) flag[ratings.size() - 1] = true;
//         else if(ratings.back() < ratings[ratings.size() - 2]) flag[ratings.size() - 2] = true;
//         int res = ratings.size();
//         for(const auto &it : flag){
//             if(it) res++;
//         }
//         return res;
//     }
// };

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

        一开始思路的大方向是没有问题的,不过我是只考虑了单边也就是从左到右,而且我忘记处理了累加的情况,只是用bool判断是否相邻的更大,这个也算是贪心的一个方向了,只是我没有考虑的很完整。

        答案思路看了以后发现这个题目其实挺清晰的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值