代码随想录算法训练营 day 34: 1005.K次取反后最大化的数组和 ● 134. 加油站 ● 135. 分发糖果

61 阅读2分钟

1005. Maximize Sum Of Array After K Negations

这题的思路是先遍历数组,在k次数允许的前提下,把所有的负数先反转了。这样需要先把数组按照绝对值大小排序,排序从大到小。 在k次数用完的话, 算出总sum值返回即可。 未用完的话,就挑一个绝对值最小的,即排序后数组最后一位,反复反转直到k为0。

这题的思路误入的歧途有两个,第一个是没考虑绝对值排序,而是分开考虑负数,0和正数的处理。逻辑很繁琐。 第二个是没考虑直接改数组值。不改数组值的话,也有很多麻烦。

最后一点,java的Arrays.sort居然不支持lambda的比较函数。

class Solution {
    public int largestSumAfterKNegations(int[] nums, int k) {
        nums = IntStream.of(nums)
                .boxed()
                .sorted((a,b)->Math.abs(b) - Math.abs(a))
                .mapToInt(Integer::intValue).toArray();

        for(int i=0; i<nums.length; i++) {
            if(nums[i] < 0 && k>0) {
                nums[i] = (-1) * nums[i];
                k--;
            }
 
        }

        if(k>0) {
            while(k>0) {
                nums[nums.length - 1] = (-1) * nums[nums.length - 1];
                k--;
            }
        }

        return Arrays.stream(nums).sum();
        
    }
}

134. Gas Station 这题倒是找到思路了,但按照我的思路的写法,有很多边界条件,调了好几次才成功。 Carl的思路是,当前累加rest[i]的和curSum一旦小于0,起始位置至少要是i+1,因为从i之前开始一定不行。全局最优:找到可以跑一圈的起始位置。 这个思路写出来的就很简洁。计算一个油量为正的区间,一旦油量为负,startIdx就更新为下一个元素,油量清零。 同时保存一个总油量判断是否有解。

我的思路是,也是保存一个当前油量,在负的时候不做记录,在油量为正的时候,记录起始点。若油量转负,重新计算起始点。这个思路也能写出来,但边界条件很多。不要用,容易写错。

class Solution {
    public int canCompleteCircuit(int[] gas, int[] cost) {
        int len = gas.length;

        if(gas.length != cost.length || len <= 0) {
            return -1;
        }

        int bal = 0;
        int start_idx = 0;
        int curBal = 0;

        for(int i=0; i<len; i++) {
            int curDiff = gas[i] - cost[i];
            bal += curDiff;
            curBal += curDiff;

            if(curBal < 0) {
                start_idx = i+1;
                curBal = 0;
            }
        }

        if(bal < 0) {
            return -1;
        }

        return start_idx;
        
    }
}

135. Candy 这题彻底没思路了。走进了所谓的同时考虑局部的两侧,结果思路似乎有,但一想就几乎是写不出来的。 正确思路为:

  • 一次是从左到右遍历,只比较右边孩子评分比左边大的情况。
  • 一次是从右到左遍历,只比较左边孩子评分比右边大的情况。

这样从局部最优推出了全局最优,即:相邻的孩子中,评分高的孩子获得更多的糖果。

思路选对了就很好写。

class Solution {
    public int candy(int[] ratings) {
        int len = ratings.length;

        int[] candyArr = new int[len];

        candyArr[0] = 1;

        for(int i=1; i<len; i++) {
            if(ratings[i] > ratings[i-1]) {
                candyArr[i] = candyArr[i-1] + 1;
            }
            else {
                candyArr[i] = 1;
            }
        }

        for(int i=len-2; i>=0; i--) {
            if(ratings[i] > ratings[i+1]) {
                candyArr[i] = Math.max(candyArr[i], candyArr[i+1] + 1);
            }
        }

        int ans = 0;

        for(int num : candyArr) {
            ans += num;
        }

        return ans;
    }
}