一、题目描述
有 n 个孩子站成一排,每个孩子都有一个评分 ratings[i]。
你需要给这些孩子分发糖果,满足以下规则:
-
每个孩子至少分到 1 个糖果
-
评分更高的孩子必须比相邻孩子获得更多糖果
要求计算 最少需要多少个糖果。
示例1
输入: ratings = [1,0,2]
输出: 5
解释:
糖果分配: [2,1,2]
示例2
输入: ratings = [1,2,2]
输出: 4
解释:
糖果分配: [1,2,1]
二、问题分析
我们只需要关注 相邻孩子之间的评分关系。
如果:
ratings[i] > ratings[i-1]
说明 右边孩子评分更高,必须给更多糖果。
如果:
ratings[i] > ratings[i+1]
说明 左边孩子评分更高,必须给更多糖果。
问题在于:
一次遍历无法同时满足两个方向的约束。
因此需要:
两次遍历
三、贪心算法思路
核心思想:
先保证左规则,再保证右规则
步骤如下:
1 初始化糖果
每个孩子至少一个糖果:
candies = [1,1,1,1,...]
2 从左向右遍历
如果右边评分更高:
ratings[i] > ratings[i-1]
则:
candies[i] = candies[i-1] + 1
示例:
ratings = [1,2,3]
变化过程:
初始 [1,1,1]
遍历后 [1,2,3]
3 从右向左遍历
如果左边评分更高:
ratings[i] > ratings[i+1]
需要调整:
candies[i] = max(candies[i], candies[i+1] + 1)
为什么要 max?
因为 第一次遍历可能已经分配更多糖果,不能被覆盖。
四、图解过程
示例:
ratings = [1,0,2]
第一步 初始化
ratings [1,0,2]
candies [1,1,1]
第二步 左 → 右
0 < 1 → 不变
2 > 0 → candies[2] = 2
结果
candies = [1,1,2]
第三步 右 → 左
0 < 2 → 不变
1 > 0 → candies[0] = 2
最终
candies = [2,1,2]
计算总数
2 + 1 + 2 = 5
五、完整 C 语言代码
#include <stdlib.h>
int candy(int* ratings, int ratingsSize) {
if (ratingsSize == 0) return 0;
int* candies = (int*)malloc(sizeof(int) * ratingsSize);
// 每个孩子至少1颗糖
for (int i = 0; i < ratingsSize; i++) {
candies[i] = 1;
}
// 从左向右遍历
for (int i = 1; i < ratingsSize; i++) {
if (ratings[i] > ratings[i - 1]) {
candies[i] = candies[i - 1] + 1;
}
}
// 从右向左遍历
for (int i = ratingsSize - 2; i >= 0; i--) {
if (ratings[i] > ratings[i + 1] && candies[i] <= candies[i + 1]) {
candies[i] = candies[i + 1] + 1;
}
}
int sum = 0;
for (int i = 0; i < ratingsSize; i++) {
sum += candies[i];
}
free(candies);
return sum;
}
六、复杂度分析
时间复杂度
O(n)
遍历数组两次。
空间复杂度
O(n)
使用了一个 candies 数组。
七、算法总结
这道题是 经典贪心问题。
关键思想:
局部最优 → 全局最优
策略:
-
每人至少一个糖果
-
左→右保证右边评分高
-
右→左保证左边评分高
-
取最大值避免覆盖
最终即可得到 最少糖果数。
八、同类贪心题推荐
如果你在刷 LeetCode Top150,这几题属于同一思路:
| 题号 | 题目 |
|---|---|
| 55 | 跳跃游戏 |
| 45 | 跳跃游戏 II |
| 134 | 加油站 |
| 135 | 分发糖果 |