Skip to content

Latest commit

 

History

History
191 lines (122 loc) · 5.73 KB

File metadata and controls

191 lines (122 loc) · 5.73 KB

135. Candy

难度: Hard

刷题内容

原题连接

内容描述


There are N children standing in a line. Each child is assigned a rating value.

You are giving candies to these children subjected to the following requirements:

Each child must have at least one candy.
Children with a higher rating get more candies than their neighbors.
What is the minimum candies you must give?

Example 1:

Input: [1,0,2]
Output: 5
Explanation: You can allocate to the first, second and third child with 2, 1, 2 candies respectively.
Example 2:

Input: [1,2,2]
Output: 4
Explanation: You can allocate to the first, second and third child with 1, 2, 1 candies respectively.
             The third child gets 1 candy because it satisfies the above two conditions.

解题方案

思路 1 - 时间复杂度: O(N)- 空间复杂度: O(N)******

  • 首先我们从左往右边看,如果当前child的rating比它左边child的rating大,那么当前child分的candy肯定要比它左边多1
  • 然后从右往左边看,如果当前child的rating比它右边child的rating大,那么当前child分的candy肯定要比它右边多1

我们知道这两种情况我们都必须满足,所以最后我们取两者中的大者(这样才能同时满足两种情况),beats 24.83%

class Solution:
    def candy(self, ratings):
        """
        :type ratings: List[int]
        :rtype: int
        """
        left2right = [1] * len(ratings)
        right2left = [1] * len(ratings)
        for i in range(1, len(ratings)):
            if ratings[i] > ratings[i-1]:
                left2right[i] = left2right[i-1] + 1
        for i in range(len(ratings)-2, -1, -1):
            if ratings[i] > ratings[i+1]:
                right2left[i] = right2left[i+1] + 1
        res = 0
        for i in range(len(ratings)):
            res += max(left2right[i], right2left[i])
        return res

思路 2 - 时间复杂度: O(N)- 空间复杂度: O(N)******

刚才用了2个array,其实我们可以只用一个array, beats 28.77%

class Solution:
    def candy(self, ratings):
        """
        :type ratings: List[int]
        :rtype: int
        """
        res = [1] * len(ratings) # also compatable with [] input
        # left scan
        for i in range(1, len(ratings)):
            if ratings[i] > ratings[i-1]:
                res[i] = res[i-1] + 1
        # right scan
        for i in range(len(ratings)-2, -1, -1):
            if ratings[i] > ratings[i+1]:
                res[i] = max(res[i+1]+1, res[i])
        return sum(res)

思路 3 - 时间复杂度: O(N)- 空间复杂度: O(1)******

其实我们还有另外一种思路,可以将空间降到O(1)

假设:

      input: [2, 4, 6, 8, 7, 6, 5, 4, 3, 2, 7, 8, 9, 8, 7, 6, 5, 4, 3]
child index: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10,11,12,13,14,15,16,17,18,19]

我们先直接给第一个孩子1颗candy,然后继续往下遍历,我们发现第2个孩子的rating比第一个孩子的多,于是我们给第二个孩子2颗candy, 以此类推,第3个孩子3颗candy,第4个孩子4颗candy,这时候我们发现第5个孩子的rating比第4个孩子的rating要小, 所以第5个孩子的candy肯定要比第4个孩子的少才行,但是不能直接给第5个孩子1颗candy这么简单,因为说不定后面孩子的rating比第5个孩子更小呢? 如果第5个孩子只有1颗candy,后面的孩子岂不是没有candy了?这不符合题目要求,所以我们暂时继续走下去,我们发现一共降序走了6步,此时来到了第11个孩子, rating终于又变成升序了,这时候我们知道了,第5个孩子最少需要给6颗candy了,然后第6,7,8,9,10个孩子依次给5,4,3,2,1颗candy,总数就是6*(1+6)/2 但是问题来了,第5个孩子给了6颗candy,第4个孩子应该要比第5个孩子的candy更多呀, 于是我们补给第4个孩子3颗candy,此时第4个孩子有7颗candy (比第5个孩子的6颗多,符合题目要求)。继续走下去,第11个孩子给2颗candy,第12个孩子给3颗candy,第13个孩子给4颗candy,接下来又是降序了, 又是降序走了6步,一样的原理,第14,15,16,17,18,19个孩子分别给6,5,4,3,2,1颗candy,发现第13个孩子需要补3颗candy(现在7颗candy)

于是我们的candy的总和为

      input: [2, 4, 6, 8, 7, 6, 5, 4, 3, 2, 7, 8, 9, 8, 7, 6, 5, 4, 3]
child candy: [1, 2, 3, 7, 6, 5, 4, 3, 2, 1, 2, 3, 7, 6, 5, 4, 3, 2, 1]
child index: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10,11,12,13,14,15,16,17,18,19]

一共67颗candy

编码实现, beats 59.40%

class Solution:
    def candy(self, ratings):
        """
        :type ratings: List[int]
        :rtype: int
        """
        if not ratings:
            return 0
        res, prev, desc_cnt = 1, 1, 0
        for i in range(1, len(ratings)):
            if ratings[i] >= ratings[i-1]:
                if desc_cnt > 0:
                    res += desc_cnt * (desc_cnt + 1) / 2 # arithmetic progression
                    if desc_cnt >= prev:
                        res += desc_cnt - prev + 1
                    desc_cnt = 0
                    prev = 1
                # 当前child的rating和它左边child的rating一样,直接给1颗candy就满足了,否则需要给prev+1颗candy
                prev = 1 if ratings[i] == ratings[i-1] else prev + 1 
                res += prev
            else:
                desc_cnt += 1
        if desc_cnt > 0: # if we were descending at the end
            res += desc_cnt * (desc_cnt + 1) / 2 # arithmetic progression
            if desc_cnt >= prev:
                res += desc_cnt - prev + 1
        return int(res)