题目
n 个孩子站成一排。给你一个整数数组 ratings 表示每个孩子的评分。
你需要按照以下要求,给这些孩子分发糖果:
每个孩子至少分配到 1 个糖果。
相邻两个孩子评分更高的孩子会获得更多的糖果。
请你给每个孩子分发糖果,计算并返回需要准备的 最少糖果数目 。
限制条件:
n
=
=
r
a
t
i
n
g
s
.
l
e
n
g
t
h
n == ratings.length
n==ratings.length
1
<
=
n
<
=
2
∗
104
1 <= n <= 2 * 104
1<=n<=2∗104
0
<
=
r
a
t
i
n
g
s
[
i
]
<
=
2
∗
104
0 <= ratings[i] <= 2 * 104
0<=ratings[i]<=2∗104
示例
示例 1:
输入:ratings = [1,0,2]
输出:5
解释:你可以分别给第一个、第二个、第三个孩子分发 2、1、2 颗糖果。
示例 2:
输入:ratings = [1,2,2]
输出:4
解释:你可以分别给第一个、第二个、第三个孩子分发 1、2、1 颗糖果。
第三个孩子只得到 1 颗糖果,这满足题面中的两个条件。
思路
题意
该题目的意思是:判断每个孩子是否比其相邻孩子的得分高,若得分更高,则分配更多的糖果,且保证相邻孩子中,得分高的孩子比得分低的孩子的糖果数更多。这个分配思路使得得分高,但周围孩子得分同样高的孩子分配的糖果数少,例如对于ratings为[1,3,3,3,1]的输入,最后分配的最少糖果数为[1,2,1,2,1],索引为2的孩子只分配了一个糖果,因为其相邻孩子的得分和他相同,与周围孩子没有区分度。
实现思路
由于题目中的相邻孩子表示其前一个和后一个孩子,所以需要遍历两次,判断当前孩子和其前一个孩子/后一个孩子的得分和糖果数;每次遍历判断当前孩子的得分是否高于其相邻孩子,若高于其相邻孩子,且当前孩子分发的糖果小于等于其相邻孩子分发的糖果,则令当前孩子分发的糖果数为其相邻孩子分发的糖果数加1(需要满足最小糖果数),否则说明糖果数分配的合理,继续遍历。
代码
按照上述思路,C++ 代码实现如下:
class Solution {
public:
int candy(vector<int>& ratings) {
int n = ratings.size(), sum=0;
// 每人分发的糖果数量,每人至少一颗糖果
vector<int> candies(n, 1);
for (int i = 1; i < n; i++){
/* 判断第i个孩子是否比第i-1个孩子的评分高,
若第i个孩子评分更高,且第i个孩子的糖果数少于第i-1个孩子,
则令其糖果数大于前一个孩子的糖果数,为了保证获得最小糖果数,
这里直接对前一个孩子的糖果数加1来表示第i个孩子的糖果数
*/
if (ratings[i] > ratings[i - 1] && candies[i] <= candies[i - 1]){
candies[i] = candies[i - 1] + 1;
}
}
sum += candies[n - 1];
/* 反向遍历原理同上,此时需要判断第i个孩子和第i + 1个孩子
两次循环结束后把分配的糖果数相加即为最少分发的糖果数
这里为了减少循环的次数,直接在第二个循环下计算最小分发的糖果数量
*/
for (int i = n - 2; i >= 0; i--){
if (ratings[i] > ratings[i + 1] && candies[i] <= candies[i + 1]){
candies[i] = candies[i + 1] + 1;
}
sum += candies[i];
}
return sum;
}
};
复杂度分析
两次循环遍历的时间复杂度为O(n)(常数项2忽略),由于保存了每个孩子分发的糖果数量,空间复杂度为O(n)。