题目描述
每人至少 1 颗糖;评分更高的要比相邻的拿更多。求最少糖果总数。
ratings = [1, 0, 2]
输出 = 5 (2,1,2)
思路解析
左扫只保证「比左边高的多 1」,右扫只保证「比右边高的多 1」,两次取最大值,两条规则就都满足了。
初始:每人 1 颗:先给每人 1 颗:candy = [1, 1, 1]。下面改的是糖果数,对照评分 [1, 0, 2]。
左扫 i=1:从左到右。i=1 评分 0 不比左边(1)高,糖果保持 1。
左扫 i=2:i=2 评分 2 比左边(0)高,糖果 = 左邻居 + 1 = 2。左扫完:[1, 1, 2]。
现在 candy=[1,1,2] 只保证了左规则。右边的约束还没管——所以得再从右往左扫一遍,用 max 合并。
右扫 i=1:现在从右到左。i=1 评分 0 不比右边(2)高,不变。
右扫 i=0:i=0 评分 1 比右边(0)高,糖果 = max(原值 1, 右邻居+1=2) = 2。取 max 是为了不破坏左扫的结果。
求和:最终 candy = [2, 1, 2],加起来 5 颗,就是最少糖果数。
一次只满足一边约束,最后合并——双向扫描是处理「左右都有约束」的好办法。
参考代码(Python)
Python
1candy = [1] * n
2for i in range(1, n): # 从左到右
3 if ratings[i] > ratings[i-1]:
4 candy[i] = candy[i-1] + 1
5for i in range(n-2, -1, -1): # 从右到左
6 if ratings[i] > ratings[i+1]:
7 candy[i] = max(candy[i], candy[i+1] + 1)
8return sum(candy)复杂度分析
- 时间复杂度:O(n) —— 扫两遍
- 空间复杂度:O(n) —— 一个糖果数组
套路模板
记住骨架:两遍方向相反、每遍只满足一边、第二遍用 max 合并。接雨水的「左右最高」预处理也是同一招。
Python
1# 「左右两边都有约束」的题都套
2a = [初值] * n
3for i in range(1, n): # 左→右:只管左约束
4 if 左条件: a[i] = a[i-1] + 1
5for i in range(n-2, -1, -1): # 右→左:只管右约束
6 if 右条件: a[i] = max(a[i], a[i+1] + 1) # 取max不破坏左
7return sum(a)易错点
- ❌ 右扫直接覆盖 candy[i] → ✅ candy[i] = max(candy[i], candy[i+1]+1)(直接赋值会破坏左扫已满足的约束)
- ❌ 右扫方向写错 → ✅ range(n-2, -1, -1)(从倒数第二个往前到 0)
以上文字与上方动画完全同一思路:先看动画建立直觉 → 读文字巩固 → 关掉页面自己默写一遍代码,能写出来才算真的掌握。