题目描述
思路解析动画文字版
记住这条「左右各扫一遍、每位取两遍最大」,下面每一帧都在套它。
上面这行是每个孩子的评分(长度固定)。先满足「每人至少 1 颗」,给所有人都发 1 颗——这是 RESULT 里 candy 数组的起点,接下来两遍扫描会把该加的加上去。
第一遍从左往右,看孩子 0。最左孩子没有左邻,保持 1 颗。这一遍只管「右边评分更高的要比它左边糖多」这一个方向。
第一遍从左往右,看孩子 1。ratings[1]=3 > ratings[0]=1(右高于左)→ candy[1]=candy[0]+1=2。这一遍只管「右边评分更高的要比它左边糖多」这一个方向。
第一遍从左往右,看孩子 2。ratings[2]=4 > ratings[1]=3(右高于左)→ candy[2]=candy[1]+1=3。这一遍只管「右边评分更高的要比它左边糖多」这一个方向。
第一遍从左往右,看孩子 3。ratings[3]=5 > ratings[2]=4(右高于左)→ candy[3]=candy[2]+1=4。这一遍只管「右边评分更高的要比它左边糖多」这一个方向。
第一遍从左往右,看孩子 4。ratings[4]=2 ≤ ratings[3]=5(不比左邻高)→ 维持 candy[4]=1。这一遍只管「右边评分更高的要比它左边糖多」这一个方向。
第一遍从左往右,看孩子 5。ratings[5]=1 ≤ ratings[4]=2(不比左邻高)→ 维持 candy[5]=1。这一遍只管「右边评分更高的要比它左边糖多」这一个方向。
第一遍从左往右,看孩子 6。ratings[6]=3 > ratings[5]=1(右高于左)→ candy[6]=candy[5]+1=2。这一遍只管「右边评分更高的要比它左边糖多」这一个方向。
第一遍从左往右,看孩子 7。ratings[7]=2 ≤ ratings[6]=3(不比左邻高)→ 维持 candy[7]=1。这一遍只管「右边评分更高的要比它左边糖多」这一个方向。
第一遍从左往右,看孩子 8。ratings[8]=1 ≤ ratings[7]=2(不比左邻高)→ 维持 candy[8]=1。这一遍只管「右边评分更高的要比它左边糖多」这一个方向。
第一遍从左往右,看孩子 9。ratings[9]=6 > ratings[8]=1(右高于左)→ candy[9]=candy[8]+1=2。这一遍只管「右边评分更高的要比它左边糖多」这一个方向。
第一遍从左往右,看孩子 10。ratings[10]=5 ≤ ratings[9]=6(不比左邻高)→ 维持 candy[10]=1。这一遍只管「右边评分更高的要比它左边糖多」这一个方向。
第一遍扫完。此时每个「比左邻评分高」的孩子都已经比左邻糖多了。但「比右邻评分高」的孩子(处在下坡段)还没被照顾——下面第二遍从右往左补。
第二遍从右往左,看孩子 10。最右孩子没有右邻,保持当前糖数不变。取 max 很关键:既照顾「左边评分更高要比右边糖多」,又不破坏第一遍已满足的左邻约束。
第二遍从右往左,看孩子 9。ratings[9]=6 > ratings[10]=5,但 candy[9]=2 已≥candy[10]+1=2,取 max 后不变。取 max 很关键:既照顾「左边评分更高要比右边糖多」,又不破坏第一遍已满足的左邻约束。
第二遍从右往左,看孩子 8。ratings[8]=1 ≤ ratings[9]=6(不比右邻高)→ 维持 candy[8]=1。取 max 很关键:既照顾「左边评分更高要比右边糖多」,又不破坏第一遍已满足的左邻约束。
第二遍从右往左,看孩子 7。ratings[7]=2 > ratings[8]=1(左高于右)→ candy[7]=max(2, candy[8]+1)=2。取 max 很关键:既照顾「左边评分更高要比右边糖多」,又不破坏第一遍已满足的左邻约束。
第二遍从右往左,看孩子 6。ratings[6]=3 > ratings[7]=2(左高于右)→ candy[6]=max(3, candy[7]+1)=3。取 max 很关键:既照顾「左边评分更高要比右边糖多」,又不破坏第一遍已满足的左邻约束。
第二遍从右往左,看孩子 5。ratings[5]=1 ≤ ratings[6]=3(不比右邻高)→ 维持 candy[5]=1。取 max 很关键:既照顾「左边评分更高要比右边糖多」,又不破坏第一遍已满足的左邻约束。
第二遍从右往左,看孩子 4。ratings[4]=2 > ratings[5]=1(左高于右)→ candy[4]=max(2, candy[5]+1)=2。取 max 很关键:既照顾「左边评分更高要比右边糖多」,又不破坏第一遍已满足的左邻约束。
第二遍从右往左,看孩子 3。ratings[3]=5 > ratings[4]=2,但 candy[3]=4 已≥candy[4]+1=3,取 max 后不变。取 max 很关键:既照顾「左边评分更高要比右边糖多」,又不破坏第一遍已满足的左邻约束。
第二遍从右往左,看孩子 2。ratings[2]=4 ≤ ratings[3]=5(不比右邻高)→ 维持 candy[2]=3。取 max 很关键:既照顾「左边评分更高要比右边糖多」,又不破坏第一遍已满足的左邻约束。
第二遍从右往左,看孩子 1。ratings[1]=3 ≤ ratings[2]=4(不比右邻高)→ 维持 candy[1]=2。取 max 很关键:既照顾「左边评分更高要比右边糖多」,又不破坏第一遍已满足的左邻约束。
第二遍从右往左,看孩子 0。ratings[0]=1 ≤ ratings[1]=3(不比右邻高)→ 维持 candy[0]=1。取 max 很关键:既照顾「左边评分更高要比右边糖多」,又不破坏第一遍已满足的左邻约束。
两遍都扫完。每个孩子取了两遍里的更大值,左右相邻约束同时满足,且每步只在必须时才 +1,所以这就是最少的发法:总共 22 颗。
边界先想清:纯下坡时全靠第二遍,纯上坡时全靠第一遍。
两个高频追问:O(1) 优化 + 最优性直觉。
参考代码
def candy(ratings): n = len(ratings) c = [1] * n # ① 每人至少 1 颗 for i in range(1, n): # 第一遍 左→右 if ratings[i] > ratings[i-1]: c[i] = c[i-1] + 1 # 右高于左:比左邻多 1 for i in range(n-2, -1, -1): # 第二遍 右→左 if ratings[i] > ratings[i+1]: c[i] = max(c[i], c[i+1] + 1) # 取 max 不破坏左邻约束 return sum(c)复杂度
- 时间:O(n),左右各扫一遍数组,共 2n 步
- 空间:O(n),一个 candy 数组记录每个孩子的糖数
易错点
面试追问把动画讲成自己的话
追问能不能只用 O(1) 额外空间做?
追问为什么两遍贪心能保证总数最少?
这道题到这就讲完了。动画和文字是同一套思路——别光看,关掉页面自己默写一遍。然后顺着主线继续:
按要求补齐数组
LeetCode 330 · 困难 · 沿着 贪心套路 继续往下推进
把这道题真正学会,再走
图解算法年卡 ¥99 /年
- ✓本题每步动画的吴师兄语音讲解(全站陆续覆盖)
- ✓小欧带 8 步通关训练——追问到不看答案也能写对、能 30 秒讲给面试官听
- ✓学习报告,记录每道题的掌握程度
76k+ GitHub Star · 吴师兄开源图解算法,几十万开发者在看的算法讲解
想成体系刷透这类套路?去图解算法专题