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

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

leetcode题目链接:1005. K 次取反后最大化的数组和 - 力扣(LeetCode)

文章讲解:代码随想录 (programmercarl.com)

视频讲解:贪心算法,这不就是常识?还能叫贪心?LeetCode:1005.K次取反后最大化的数组和_哔哩哔哩_bilibili

解题思路

我们将数组按绝对值大小进行排序,每次对负数取反就行。如果遍历完数组,k还没消耗完,就对最小的整数取反。如果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)
            {
                sort(nums.begin(), nums.end());
                for (k; k > 0; k--)
                    nums[0] = -nums[0];
                break;
            }
            nums[i] = -nums[i];
            k--;
            if (k == 0)
                break;
        }
        sort(nums.begin(), nums.end());
        if(k%2==1) nums[0]=-nums[0];
        for (auto& r : nums)
            sum += r;
        return sum;
    }
};

按绝对值

class Solution {
static bool cmp(int a, int b) {
    return abs(a) > abs(b);
}
public:
    int largestSumAfterKNegations(vector<int>& A, int K) {
        sort(A.begin(), A.end(), cmp);       // 第一步
        for (int i = 0; i < A.size(); i++) { // 第二步
            if (A[i] < 0 && K > 0) {
                A[i] *= -1;
                K--;
            }
        }
        if (K % 2 == 1) A[A.size() - 1] *= -1; // 第三步
        int result = 0;
        for (int a : A) result += a;        // 第四步
        return result;
    }
};

解题思路 

其实本题有点像最大子数组和那个题。

如果从0或1开始,剩余加到2时,必然是负数,也就是说从0,1开始均不可能回到起点。

那么我们如果遍历中遇到和是负数的情况,就从第i+1(2+1=3)这个位置再开始尝试。

遍历完数组后,如果总的剩余和也是负数,那就代表不论从哪走,都不可能回到起点。

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

解题思路

如果我们同时比较左右两边,很容易比错。我们可以这么做。

第一遍遍历,只看右边孩子大于左边的情况,如果大于,右边孩子糖果数就是左边+1。

第二遍遍历,倒着遍历,只看左边孩子大于右边的情况,如果大于,就取当前糖果数和右边糖果数+1的最大值。

 

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] = max(Candy[i], Candy[i + 1] + 1);
        }
        int sum = 0;
        for (auto r : Candy)
            sum += r;
        return sum;
    }
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值