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

目录

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

134. 加油站

135. 分发糖果


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

本题简单一些,估计大家不用想着贪心 ,用自己直觉也会有思路。 

代码随想录

题解思路:

解法就是先把数组按绝对值从大到小排列,然后先将数组里面的负数取反为整数,如果k的次数还剩余,在一个劲的逮着绝对值最小的数取反,这里对排在最后也是最小的数取反也有技巧就是如果剩余的k的次数是奇数,只需要最后的数取一次反即可,如果是偶数,取反过来取反过去,等于没取反,因此不用处理就行,最后就是按题意将数组中的各个数累加即可。

class Solution {
    public int largestSumAfterKNegations(int[] nums, int k) {
        int result = 0;
        Stream<Integer> integerNums = Arrays.stream(nums).boxed();// 将数组先转换成一个 Integer类型的stream流
        Integer[] newNums = integerNums.toArray(Integer[]::new);  //将流转换为数组
        Arrays.sort(newNums, (o1,o2)->Math.abs(o2) - Math.abs(o1));  //将新数组按大到小排序,使用比较器排序时,必须是对引用类型的数组进行操作,即必须先将int类型的数组转换成Integer类型的数组。
        

        for(int i = 0; i < newNums.length; i++){ //利用k次机会,先把数组中的绝对值较大的负数尽可能的都取反
            if(newNums[i] < 0 && k > 0){
                newNums[i] *= -1;
                k--;
            }
        }
        if(k % 2 != 0) newNums[newNums.length - 1] *= -1; //如果都把负数取反后还剩余k次,k若为奇数,把绝对值最小的数取反即可,k若为偶数,则不需要处理

        for(Integer element : newNums){ //k次取反后累加数组中的各个元素就是最大化的数组和
            result += element;
        }
        return result;
    }
}

134. 加油站

本题有点难度,不太好想,推荐大家熟悉一下方法二 

代码随想录

题解思路:

卡哥给的题解中没有模拟环绕一周的过程,只是遍历了一轮数组后,可以这么思考:
1、总净增油量是一定的,因此遍历一轮就可以判断是否可以环绕一周,如果总净增油量大于等于0,说明可以,反之不可以;
2、出发站点只能从这n个加油站,也就是gas下标索引值范围内选择,这里注意如果totalSum小于0的话,此时有可能出现start = n + 1,也就是数组越界,但是总净增油量小于0,下面代码会执行返回-1,不会返回start的值;如果totalSum大于等于0的话,一定不会出现start = n + 1的情况,最顶的话也就是start = n,也就是从最后一个站点出发,因为前面正增油量太小了,加上第n个站点的正增油量才能抵消消耗的油量,使得最后totalSum大于等于0。

class Solution {
    public int canCompleteCircuit(int[] gas, int[] cost) {
        int totalSUm = 0;
        int currentSum = 0;
        int start = 0;
        for(int i = 0; i < gas.length; i++){
            currentSum += gas[i] - cost[i]; //计算每个加油站点的总净增油量,如果是负数则表示不能从出发点加油站到开往到正在遍历的第i个加油站,如果是正数表示到达后剩余的油量,即可以到达
            totalSUm  += gas[i] - cost[i]; //计算一轮即所有站点的净增油量如果是负数,表示不管从哪个点出发都不可能环绕一周
            if(currentSum < 0) {  //前面的每个和累加净增油量与当前的负增油量相加小于0,说明不能走到当前遍历的第i个站点,因此需要换从下一个站点开始
                start = i + 1;    //如果前面的所有正数累加都抵不过当前第i个站点的负增油量,那么从前面的每个正的净增油量站点出发都不可能到达第i个站点,就需要从下一个站点去重新判断了。这里注意如果totalSum小于0的话,此时有可能出现start = n + 1,也就是数组越界,但是总净增油量小于0,下面代码会执行返回-1,不会返回start的值;如果totalSum大于等于0的话,一定不会出现start = n + 1的情况,最顶的话也就是start = n,也就是从最后一个站点出发,因为前面正增油量太小了,加上第n个站点的正增油量才能抵消消耗的油量,使得最后totalSum大于等于0,
                currentSum = 0;   //重新判断时需要将正净增油量累加的初始值置为0
            }
        }
        if(totalSUm < 0 ) return -1; //如果总的净增油量小于0,那么一定不会环绕一周
        return start;
    }
}

135. 分发糖果

本题涉及到一个思想,就是想处理好一边再处理另一边,不要两边想着一起兼顾,后面还会有题目用到这个思路 

代码随想录

题解思路:

我们取序列中的任意三点B1 A B2,如果 A > B2 ,则按照左规则处理后,B2不会比A多;按照右规则处理后,A一定比B2多,那么A一定会被更新(变大),此时变大后的A才会满足比右边分高时,分的糖果数量要更多

class Solution {
    public int candy(int[] ratings) {
        int[] candyCount = new int[ratings.length];
        Arrays.fill(candyCount, 1);

        for(int i = 1; i < ratings.length; i++){
            if(ratings[i] > ratings[i - 1]){ //左规则:只判断右边比左边大的情况下,给每个小孩发放的数量,此时从前往后遍历
                candyCount[i] = candyCount[i - 1] + 1;
            }
        }
        for(int i = ratings.length - 2; i >= 0; i--){ //右规则:只判断左边比右边大的情况下,给每个小孩发放的数量,此时从后往前遍历,此时更新糖果数组中数量最大的值,才能满足某个孩子比左右两个孩子分都高时,分得的糖果数量会更多
            if(ratings[i] > ratings[i + 1]){
                candyCount[i] = Math.max(candyCount[i], candyCount[i + 1] + 1);  //更新右规则下的A
            }
        }

        int result = 0;
        for(int element : candyCount){
            result += element;
        }
        return result;
    }
}

猜你喜欢

转载自blog.csdn.net/tore007/article/details/130893322