# 分发糖果(135)
# 题目
老师想给孩子们分发糖果,有 N 个孩子站成了一条直线,老师会根据每个孩子的表现,预先给他们评分。
你需要按照以下要求,帮助老师给这些孩子分发糖果:
每个孩子至少分配到 1 个糖果。 相邻的孩子中,评分高的孩子必须获得更多的糖果。 那么这样下来,老师至少需要准备多少颗糖果呢?
# 示例
输入: [1,0,2]
输出: 5
解释: 你可以分别给这三个孩子分发 2、1、2 颗糖果。
输入: [1,2,2]
输出: 4
解释: 你可以分别给这三个孩子分发 1、2、1 颗糖果。第三个孩子只得到 1 颗糖果,这已满足上述两个条件。
# 算法
# 两次遍历
相邻孩子中评分高的将获得更多糖果,可以进行如下操作:
- 自左向右遍历:
ratings[i] > ratings[i-1]
的话,第i个孩子
获得的糖果是第i-1个孩子
获得的糖果的数量+1
- 自右向左遍历:
ratings[i] > ratings[i+1]
的话,第i个孩子
获得的糖果是第i+1个孩子
获得的糖果的数量+1
- 我们对于
第i个孩子
取上面两条规则的较大值
,即第i个孩子
获得的糖果数量
第一个操作满足了后一个孩子比前一个孩子评分高,后一个孩子将获得更多糖果;第二个操作满足了前一个孩子比后一个孩子评分高,前一个孩子将获得更多的苹果。我们对两条规则合并取每一项的较大值,即满足了相邻的评分高的孩子获得更多糖果,得到最优解。
export const candy = (ratings) => {
let count = 0;
const left = [],
right = [];
for (let i = 0; i < ratings.length; i++) {
if (i > 0 && ratings[i] > ratings[i - 1]) left[i] = left[i - 1] + 1;
else left[i] = 1;
}
for (let i = ratings.length - 1; i >= 0; i--) {
if (i < ratings.length - 1 && ratings[i] > ratings[i + 1]) right[i] = right[i + 1] + 1;
else right[i] = 1;
count += Math.max(left[i], right[i]);
}
return count;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 一次遍历
要尽量少的将糖果分给小朋友,所以我们将问题分解为:
- 如果分数是递增的:我们就每次给下一个小朋友多一个糖果
- 如果分数是一样的:我们就只给他们一个糖果(除非之后是个递减的序列)
- 如果分数是递减的:如果可以我们就只给他一个糖果,不然的话我们就给递减序列中较高的多个一个糖果;这里需要注意的是,如果相邻的递增和递减序列长度相等时,我们需要把递增序列的最后一个小朋友划入到递减序列中,不然随着递减序列增多,递减序列的第一个小朋友的糖就会比递增序列最后一个的多(但他的分并没有递增序列最后一个的高)
export const candy = (ratings) => {
let count = 1,
up = 1,
down = 0;
for (let i = 1; i < ratings.length; i++) {
if (ratings[i] > ratings[i - 1]) {
if (down !== 0) up = 1;
down = 0;
up++;
count += up;
} else if (ratings[i] === ratings[i - 1]) {
down = 0;
up = 1;
count++;
} else {
down++;
if (down === up) down++;
count += down;
}
}
return count;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22