Day 33 | 1005.K次取反后最大化的数组和 & 134. 加油站 & 135. 分发糖果

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

这道题是我自己独立思考出来的,我写的代码还蛮冗余的哈哈哈。我发现自己写代码永远是想一出是一出,不会一次想出结果然后把代码精简一下哈哈哈。

解题思路:

先对数组进行排序,然后比较负数个数与k的大小。

①若k大,则翻转所有负数,此时所有元素都是正数。然后判断最小负数和最小正数哪个小,哪个小哪个就对和的影响更小,翻转这个数k-count次即可。

②若count大于等于k,则翻转前count个数,因为数组是经过排序的,前面count个数都是较小的负数,反转后变绝对值和会更大。

        Arrays.sort(nums);
        int count;
        for (count = 0; count < nums.length; count++) {
            if (nums[count] > 0) {
                break;
            }
        }   //count:小于0的数量
        if (count == 0) {
            for (int i = 0; i < k; i++) {
                nums[count] = nums[count] * -1;
            }
        }
        if (k <= count) {
            for (int i = 0; i < k; i++) {
                nums[i] = nums[i] * -1;
            }
        } else if (count > 0 && k > count) {
            int cha = k - count;
            for (int i = 0; i < count; i++) {
                nums[i] = nums[i] * -1;
            }
            if (count < nums.length) {
                if (nums[count] > nums[count - 1]) {
                    for (int i = 1; i <= k - count; i++)
                        nums[count - 1] = nums[count - 1] * -1;
                } else {
                    for (int i = 1; i <= k - count; i++) {
                        nums[count] = nums[count] * -1;
                    }
                }
            }else{
                for (int i = 1; i <= k - count; i++)
                    nums[count - 1] = nums[count - 1] * -1;
            }
        }
        int sum = 0;
        for (int i : nums) {
            sum += i;
        }
        return sum;

134. 加油站 

这道题。。难。。嗯嗯。。

 首先明确如何判断这道题是否有解?

        定义sum值,遍历结点每次收集gas-cost的值,若最后sum>=0,则说明最后的油量有剩余,有解。否则无解,返回-1即可。

方法一:

        定义min表示从0出发的油量总和最小值。初值为0,遍历结点每次取min与sum的小值。

本题有三种情况:

①无解,sum<0,返回-1.

②min>=0,说明有解,且在i=0处开始出发油量一直为正数,则i=0即为解。

③min<0,说明有解,则i从最后一个加油站往前遍历,每次给min添加rest[i],看哪个点能将油量填平使min>=0,则说明从这个点出发油量可以一直大于0。否则无解。

    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);  //min:从起点出发的油量最小值
        }
        if(sum<0){return -1;}
        if(min>=0){return 0;}

        for(int i=gas.length-1;i>=0;i--){
            int rest=gas[i]-cost[i];
            min+=rest;
            if(min>=0){ //将油量填满即为答案
                return i;
            }
        }
        return -1;
    }

方法二(贪心):

        定义起点start=0,curSum,记录i从0开始到i的剩余油量。当curSum<0时,首先说明rest[i]在此处小于0,且[0,i-1]curSum是大于0的。若有解,解一定不会在[0,i]这个区间,一定是i+1

        因此当curSum小于0时,记录i+1的值为新起点并将curSum值清零重新累加。

        最后判断若sum<0,无解。若sum=0,返回start值即可。

    public int canCompleteCircuit(int[] gas, int[] cost) {
        int sum = 0;
        int curSum = 0;
        int start = 0;
        for (int i = 0; i < gas.length; i++) {
            int rest = gas[i] - cost[i];
            sum += rest;
            curSum += rest;
            if (curSum < 0) {
                curSum=0;
                start = i + 1;
            }
        }
        if (sum < 0) {
            return -1;
        } else {
            return start;
        }
    
    }

35. 分发糖果

看到题目第一眼:这也叫困难?

开始写:哦,原来是我没理解题意。。。果然是我高攀了。 

        本题要进行两次遍历,分别判断当前值与左右两边的大小。我一开始只想从左往右遍历一遍即可,之和自己的左边比较,漏掉了还要和自己的右边比较(哈哈)。

 贪心解题思路:

        首先从左往右遍历,candy[0]=0,从1开始若比左边大则为左边candy+1。

        然后从右往左比较,最右边值不变,判断i是否比右边i+1大,candy[i]的值若比右边小则保持当前值,若比右边大则为candy[i+1]+1,最后取这两者的大值,既满足原来的条件(比左边大),又满足了当前遍历比右边大的条件

        最后返回sum值即可。

        int[] candy=new int[ratings.length];
        candy[0]=1;
        //比较左边
        //从左往右遍历,每次看前一个是不是比自己小
        for(int i=1;i<ratings.length;i++){
            if(ratings[i]>ratings[i-1]){
                candy[i]=candy[i-1]+1;
            }else{
                candy[i]=1;
            }
        }
        //比较右边
        //从右往左遍历,看右边的是不是比自己小
        for(int i=ratings.length-2;i>=0;i--){
            if(ratings[i]>ratings[i+1]){
                //如果当前的比右边大(此时已经比左边大),则取当前candy和右边candy+1的大值,满足既比左边大,也比右边大、
                candy[i]=Math.max(candy[i+1]+1,candy[i]);
            }
        }

        int sum=0;
        for(int i:candy){
            sum+=i;
        }
        return sum;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值