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

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

完成

思路:

题目虽然简单,但是要想清楚哪里用到了贪心的策略。
本题贪心的思路是,依次找最小的负值进行翻转,结束后如果k仍冗余,找最小的一个正数连续翻转,把k耗尽,让损失最小。

代码

class Solution {
    public int largestSumAfterKNegations(int[] nums, int k) {
        int sum = 0;
        Arrays.sort(nums);
        // 把负值回正,直到k耗尽或没有负值
        for (int i = 0; i < nums.length; i++) {
            if(nums[i]<=0&&k>0){
                nums[i] = -nums[i];
                k--;
            }else break;
        }
        // k比负值多,如果k是偶数,相当于没翻转
        if(k%2!=0){
            Arrays.sort(nums);
            nums[0]=-nums[0];
        }
        for(int value : nums) sum+=value;
        return sum;
    }
}

134. 加油站

完成

代码

class Solution {
    public int canCompleteCircuit(int[] gas, int[] cost) {
        int sum = 0;
        int min = 0;
        for (int i = 0; i < gas.length; i++) {
            // 计算总油量-总消耗
            sum += (gas[i] - cost[i]);
            // 记录累加的油量和消耗的差的最小值
            min = Math.min(sum, min);
        }

        if (sum < 0) return -1;
        // 如果从0开始,min一直>0,则可以直接返回0
        if (min >= 0) return 0;

        for (int i = gas.length - 1; i > 0; i--) {
            min += (gas[i] - cost[i]);
            if (min >= 0) return i;
        }

        return -1;
    }
}

135. 分发糖果

完成

思路:

本题需要综合考虑两边的rating,才能确定该元素的得分。但是同时考虑两边容易乱,因此先考虑左边,再考虑右边。

一开始的想法是先找到最小值,再从最小值开始依次向左遍历和向右遍历。但是这样对每个元素来说就只考虑了左边或右边,而不是左边和右边。

如果从头和尾遍历考虑左右情况,那么头尾元素应该分配多少糖果?这是我纠结的点,但其实只需要赋1即可,后面还会在左右遍历中更新。

代码

class Solution {
    public int candy(int[] ratings) {
        int[] res = new int[ratings.length];
        res[0] = 1;
        // 从前向后遍历,比较元素和其左边
        for (int i = 1; i < res.length; i++) {
            if(ratings[i]>ratings[i-1]){
                res[i] = res[i-1]+1;
            }else res[i] = 1;
        }
        // 从后向前遍历,比较元素和其右边
        for (int i = ratings.length-2; i >= 0; i--) {
            if(ratings[i]>ratings[i+1]){
                // 这里不能直接赋值,要保留前向遍历的结果
                res[i] = Math.max(res[i], res[i+1]+1);
            }else res[i] = Math.max(1, res[i]);
        }

        return Arrays.stream(res).sum();
    }
}
  • 6
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值