# 分发糖果(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

# 一次遍历

要尽量少的将糖果分给小朋友,所以我们将问题分解为:

  • 如果分数是递增的:我们就每次给下一个小朋友多一个糖果
  • 如果分数是一样的:我们就只给他们一个糖果(除非之后是个递减的序列)
  • 如果分数是递减的:如果可以我们就只给他一个糖果,不然的话我们就给递减序列中较高的多个一个糖果;这里需要注意的是,如果相邻的递增和递减序列长度相等时,我们需要把递增序列的最后一个小朋友划入到递减序列中,不然随着递减序列增多,递减序列的第一个小朋友的糖就会比递增序列最后一个的多(但他的分并没有递增序列最后一个的高)
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