每个孩子至少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)的解法都不太好想到,很巧妙的做法
这道题还有其它解法,但是都比较复杂,这里就不贴了