【LeetCode每天一题】Candy(分糖果)
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.
思路
该题需要求得最少需要的糖果数,并且每一个小孩获得的糖果数都必须满足题中两点条件。根据这个条件我们可以设置两个数组,一个数组存储的是我们从左向右根据每一个孩子的rating来分发糖果, 另一个数组存储的是从右向左根据每一个孩子的rating分配的糖果数。然后将两个数组中对应位置取最大的值。最后可以得到总的糖果数。至于为什么需要从右到左和从左到右两次操作,因为在rating列表中,会有一个情况就是[0,2,1,0]这种情况下如果只遍历一次会产生错误的结果。时间复杂度为O(n),空间复杂度为O(n)。
另外其实上面的申请两个辅助数组,我们可以将其简化成一个数组。因为我们可以在第二次遍历的时候直接使用从左到右的结果进行比较,而不用在单独存储了。
在三月份的时候做过头条的面试题,和这个分糖果类似,只不过小孩是围城一个圈的,这就相对来说更加复杂一些。具体的解决办法就是我们申请的数组为rating长度加1,最后一个位置赋值为第一个rating 的值,最后这样左的目的就是将其连接起来形成一个环,然后左到右,从从右到左。不断的调整。直到满足条件位置。大概思路就是这样解决的。
解决代码
1 class Solution(object):
2 def candy(self, ratings):
3 """
4 :type ratings: List[int]
5 :rtype: int
6 """
7 if not ratings:
8 return 0
9 candy = [1]*len(ratings) # 申请一个数组,并初始化为1
10
11 for i in range(1, len(ratings)): # 从左向右开始遍历
12 if ratings[i] > ratings[i-1]: # 如果当前孩子的rating大于左边的孩子,则糖果数加1
13 candy[i] = candy[i-1]+1
14 res = candy[-1] # 取最后一个的糖果数
15 for i in reversed(range(len(ratings)-1)): # 从右向左遍历
16 if ratings[i] > ratings[i+1]: # 如果当前孩子的rating大于右边的孩子,则糖果数加1
17 candy[i] = max(candy[i], candy[i+1]+1) # 直接选择最大的值
18 res += candy[i]
19 return res