Day36~1005.K次取反后最大化的数组和、134. 加油站、135. 分发糖果

70 阅读3分钟

摘要

本文主要介绍了LeetCode贪心算法的几个题目,包括1005.K次取反后最大化的数组和、134. 加油站、135. 分发糖果。

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

1.1 思路

  • 第一步贪心:寻找绝对值最大的负数优先对其取反
  • 第二步贪心:优先取数组中最小的正数,对其进行取反

1.2 代码

    public int largestSumAfterKNegations(int[] nums, int k) {
        // 第一步贪心:寻找绝对值最大的负数优先对其取反
        Arrays.sort(nums);
        for(int i=0; i<nums.length; i++) {
            if(nums[i] < 0 && k > 0) {
                nums[i] = -nums[i];
                k--;
            }
        }
​
        // 第二步贪心:优先取数组中最小的正数,对其进行取反
        Arrays.sort(nums);
        if(k % 2 == 1) {
            nums[0] = -nums[0];
        }
        return Arrays.stream(nums).sum();
    }

2、134. 加油站

2.1 思路

  • curSum 用于跟踪从起始加油站到当前加油站的汽油差值。totalSum 用于跟踪整个行程的汽油差值。
  • 从第一个加油站开始遍历数组。对于每个加油站,计算该加油站的汽油剩余量 gas[i] - cost[i],并累加到 curSumtotalSum 中。
  • 如果 curSum 变为负数,说明从当前起始加油站出发无法到达当前加油站,需要重新选择下一个加油站作为新的起始点,同时将 curSum 重置为0。
  • 继续遍历直到完成整个数组。
  • 如果 totalSum 大于等于0,说明从某个起始加油站出发,可以绕行一圈回到该起始加油站,返回该起始加油站的索引;否则,返回-1,表示无法绕行一圈。

2.2 代码

   public int canCompleteCircuit(int[] gas, int[] cost) {
        int curSum = 0;
        int totalSum = 0;
        int start = 0;
​
        for(int i=0; i<gas.length; 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;
    }

3、135. 分发糖果

3.1 思路

  • 这道题目一定是要确定一边之后,再确定另一边,例如比较每一个孩子的左边,然后再比较右边,如果两边一起考虑一定会顾此失彼。

  • 先确定右边评分大于左边的情况(也就是从前向后遍历)

    • 局部最优:只要右边评分比左边大,右边的孩子就多一个糖果
    • 全局最优:相邻的孩子中,评分高的右孩子获得比左边孩子更多的糖果
  • 再确定左孩子大于右孩子的情况(从后向前遍历)

    • 局部最优:取candyVec[i + 1] + 1 和 candyVec[i] 最大的糖果数量,保证第i个小孩的糖果数量既大于左边的也大于右边的
    • 全局最优:相邻的孩子中,评分高的孩子获得更多的糖果

3.2 代码

    public int candy(int[] ratings) {
        int len = ratings.length;
        int[] candy = new int[ratings.length];
        Arrays.fill(candy, 1);
​
        // 右-左
        for(int i=1; i<len; i++) {
            if(ratings[i] > ratings[i-1]) {
                candy[i] = candy[i-1] + 1;
            }
        }
​
        // 左-右
        for(int i=len-2; i>=0; i--) {
            if(ratings[i] > ratings[i+1]) {
                candy[i] = Math.max(candy[i+1] + 1, candy[i]);
            }
        }
​
        int count = 0;
        for(int i=0; i<len; i++) {
            count += candy[i]; 
        }
        return count;
    }

参考资料

代码随想录-1005.K次取反后最大化的数组和

代码随想录-134. 加油站

代码随想录-135. 分发糖果