leetcode 135. 分发糖果

题目链接

解析

1、两次遍历
在这里插入图片描述

class Solution {
   public int candy(int[] ratings) {
int[] candies = new int[ratings.length];
        int sum = 0;

        candies[0] = 1;

        for (int i = 1; i < ratings.length; i++) {
            if (ratings[i] > ratings[i - 1])
                candies[i] = candies[i - 1] + 1;
            else
                candies[i] = 1;

        }
        for (int i = ratings.length - 1; i >= 1; i--) {
            if (ratings[i - 1] > ratings[i])
                candies[i - 1] = Math.max(candies[i] + 1, candies[i - 1]);
            sum += candies[i];
        }
        
        return sum + candies[0];
    }
}

2、一次遍历

法一我们把每个小朋友的糖果数量保存到了数组里,最后求和,法二我们选择在遍历的过程中就直接求和,但是这次求和中 增加的糖果数量 并不一定就是这个小朋友应该分配的糖果数

为了理解这个算法,首先我们定义递增序列,递减序列,假设rating数组为123210,那么递增序列是什么,递减序列又是什么?中间这个3其实他的存在很暧昧,可以说他是递增序列的一部分,也可以说他是递减序列的一部分。但是我们定义,3只能属于一个序列。我们的算法是从前到后遍历rating数组,当遍历到rating=1以及之前时,3都属于增序列,当遍历到0时,就把3从增序列拿出来,让他属于减序列!那么理论说法就是:我们当前遍历到的减序列长度与和他相邻的增序列长度相等时(也就是dec = inc),就把暧昧数字从增序列取出来,然后让他属于减序列!

我们用pre储存递增序列中这一个小朋友应该分到的糖果数,同时也是目前为止递增序列的长度,inc也储存递增序列的长度(但是并不重复,具体看对于递减序列的操作) 可以看到,在递增序列中每次增加的糖果数就是 这一个小朋友应该分到的糖果数

我们用dec存储这次遍历中处于递减序列的第一个小朋友应该分得的糖果数(从左到右排序)。举个栗子,rating数组为123210。首先需要知道,我们是从第二个小朋友开始遍历的,对于我们第三次遍历,我们按顺序从前往后找到了第四个小朋友(rating = 2),此时他应该分得的糖果数为1,那么我们的dec正好是1。之后遍历到了第五个小朋友(rating=1),此时递减序列有了两个小朋友分别是(rating=2和rating=1),此时dec = 2,当我们遍历到第六个小朋友时,根据我们前面的定义,递减序列的第一个数字变成了3,此时递减序列为3210,那么减序列第一个小朋友需要分到的糖果数就是4,但是此时dec是3,所以我们还需要dec++

最后还需要解释一下这种遍历过程中求和算法的正确性,对于递增序列,其正确性不言而喻。因为此时pre存储的就是这个小朋友现在的糖果数,然后sum+=pre就可以正确计算递增序列小朋友的糖果数;对于递减序列,我们其实是倒着加的,为什么说是倒着呢,这里举一个栗子,还是rating数组为123210,对应的糖果数组candies为124321 ,我们规定从左加到右为正序,递增序列的计算是1+2+3,但是递减序列的计算为1+2+4。但是到这里可能会有疑问,递增序列明明是1,2 为什么算的是1+2+3。这是因为我们在计算过程中递增序列发生了变化!因为中间有一步,暧昧数字变成了递减序列的一部分,这时对于rating数组为123210的情况来说,在增序列中我们计算了1+2+3,减序列计算了1+2,因为此时遍历到了rating=0,也就是说,增序列多加了3,减序列少加了3+4,所以我们把rating=3放到减序列,相当于是在减序列加了3,因为这个加入者,减序列的长度也从上一次遍历的2变成了这一次遍历的4,所以dec还需要再次++!

不过为毛O(1)空间复杂度的解法内存消耗比O(n)空间复杂度的解法还要大
在这里插入图片描述

class Solution {
   public int candy(int[] ratings) {
int[] candies = new int[ratings.length];
      int sum = 1, dec = 0, inc = 1, pre = 1;

        for (int i = 1; i < ratings.length; i++) {
            //递增序列
            if (ratings[i] >= ratings[i - 1]) {
                dec = 0;
                pre = ratings[i] == ratings[i - 1] ? 1 : pre + 1;
                sum += pre;
                inc = pre;
            } else {
                dec++;
                if (dec == inc)
                    dec++;
                sum += dec;
                pre = 1;
            }
        }

        return sum;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值