135. 分发糖果


每个孩子至少1个,则ans >= N
N个孩子排成直线,不是环,不用考虑首尾问题

然后遍历每个孩子,如果这个孩子评分比相邻的孩子高,那么给他+1,如果与相邻的孩子相等,则他们获得的糖果数没有要求

模拟 AC

思路:
整个数组里面,评分最低的肯定是获得糖果最少的并且一定是1,因为整个最少糖果数组肯定是由1生成的
按照评分最少的元素开始遍历ratings,然后检查它周围的元素,如果它周围元素大,那么就给它周围元素更新为当前糖果数+1

class Solution:
    def candy(self, ratings: List[int]) -> int:
        if ratings == []:
            return 0

        N = len(ratings)
        ans = [1] * N 
        que = []
        for pos,v in enumerate(ratings):
            # rating, position
            que.append((v,pos))
        que = sorted(que)

        # print(que)

        for v,pos in que:
            # 如果不是边界元素,那么判断相邻元素
            if pos != 0 and ratings[pos-1] > ratings[pos]:
                ans[pos-1] = ans[pos] + 1 
            if pos != (N-1) and ratings[pos+1] > ratings[pos]:
                ans[pos+1] = ans[pos] + 1

        return sum(ans)

这个模拟策略的更新代码有一点瑕疵,即
ans[pos-1] = ans[pos] + 1 有可能ans[pos-1]已经大于ans[pos]+1了,
对于测试样例

[0,1,2,3,2,1]

按照上述策略分配的糖果为

[1,2,3,3,2,1],原本rating为3的孩子应该拿到4颗,但是被ans[pos] + 1更新了,此时变为3

正确答案应该是

[1,2,3,4,2,1]

所以我们修改一下代码

class Solution:
    def candy(self, ratings: List[int]) -> int:
        if ratings == []:
            return 0

        N = len(ratings)
        ans = [1] * N 
        que = []
        for pos,v in enumerate(ratings):
            # rating, position
            que.append((v,pos))
        que = sorted(que)

        # print(que)

        for v,pos in que:
            # 如果不是边界元素,那么判断相邻元素
            if pos != 0 and ratings[pos-1] > ratings[pos]:
                ans[pos-1] = max(ans[pos-1],ans[pos] + 1)
            if pos != (N-1) and ratings[pos+1] > ratings[pos]:
                ans[pos+1] = max(ans[pos+1],ans[pos] + 1)

        return sum(ans)

在这里插入图片描述
通过了 看来还有优化的空间

时间复杂度 O ( N l o g N ) O(NlogN) O(NlogN)
空间复杂度 O ( N ) O(N) O(N)

题解

两趟遍历

在这里插入图片描述

嗯。。刚开始我也想到了两趟遍历,不过没能说服自己为什么这么做能成立,就没细想了

class Solution:
    def candy(self, ratings: List[int]) -> int:
        left = [1 for _ in range(len(ratings))]
        right = left[:]
        for i in range(1, len(ratings)):
            if ratings[i] > ratings[i - 1]: left[i] = left[i - 1] + 1
        count = left[-1]
        for i in range(len(ratings) - 2, -1, -1):
            if ratings[i] > ratings[i + 1]: right[i] = right[i + 1] + 1
            count += max(left[i], right[i])
        return count

作者:jyd
链接:https://leetcode-cn.com/problems/candy/solution/candy-cong-zuo-zhi-you-cong-you-zhi-zuo-qu-zui-da-/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

关键就是把规则分为两个部分,然后单独处理每个部分,很巧妙的解法

一趟遍历

用递增递减的序列分析,非常巧妙的做法
在这里插入图片描述

class Solution:
    def candy(self, ratings: List[int]) -> int:
        n = len(ratings)
        ret = 1
        inc, dec, pre = 1, 0, 1

        for i in range(1, n):
            if ratings[i] >= ratings[i - 1]:
                dec = 0
                pre = (1 if ratings[i] == ratings[i - 1] else pre + 1)
                ret += pre
                inc = pre
            else:
                dec += 1
                if dec == inc:
                    dec += 1
                ret += dec
                pre = 1
        
        return ret

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/candy/solution/fen-fa-tang-guo-by-leetcode-solution-f01p/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

上面的代码中,pre是前一个人获得的糖果数,同时也是递增序列的长度,inc记录递增序列的长度,需要用pre来更新
dec是下降序列的长度,如果下降序列的长度等于之前递增序列的长度时候,要加上之前递增序列的最后一个元素
ret就是最后的答案了

总结

一道hard的题目, O ( N l o g N ) O(NlogN) O(NlogN)的解法不难想到,但是两个 O ( N ) O(N) O(N)的解法都不太好想到,很巧妙的做法
这道题还有其它解法,但是都比较复杂,这里就不贴了

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值