135 Candy
There are N children standing in a line. Each child is assigned a rating value.You are giving candies to these children subjected to the following requirements:
Each child must have at least one candy.
Children with a higher rating get more candies than their neighbors.What is the minimum candies you must give?
已知我们有N个孩子,每个孩子有一个等级,我们给孩子们发糖果,每个孩子至少要发一颗糖果,等级高的孩子要比他的邻居有更多的糖果。求最少需要多少糖果。
这道题的一个重要约束条件是——等级高的孩子要比他的邻居发到更多的糖果,也就是说,对于等级为:低,高,低 的情况,假设给第一个孩子发了a颗糖果,等级最高的第二个孩子至少需要发a+1颗糖果,而第三个孩子只需要发1颗糖果(当然也可以发更多/更少的糖果,因为没有约束条件)。而同时,对于等级相同的孩纸——没有约束条件,也就是说等级相同的孩子,第二个孩子可以只发1颗糖果。
注意到以上点之后,最大的问题在于等级递减的情况了。假设对于低→高的情况我们严格地采取等级高的孩子多发一颗糖的,对于高→低的情况采取低的孩子只发一颗糖,同等级的孩子从第二个孩子开始只发一颗糖的策略。由于高→低的情况,低优先级的孩子最少只发1颗糖,但是若是这个孩子后面再跟了一个更低优先级的孩子,也就是高→中→低的情况,那么中间的那个孩子就不能只发一颗糖,而得多发一颗糖才能满足约束条件。那么这里就有两种情况:①等级高的孩子只比中等等级的孩子多发1颗糖。②等级高的孩子比中等等级的孩子多发不只1颗糖。对于第一种情况,那么不子中等等级的孩子需要多发1颗糖,而高等级的孩子也需要多发一颗糖,才能满足约束条件。对于第二中情况,等级高的孩子比中等等级的孩子多发了至少2颗糖,那么只需要给中等等级高的孩子多发1颗糖即可。以此类推,对于等级递减的情况,也就是高→中高→中→中低→……→低的情况,最低级不能发0颗糖,所以中间递减的部分每个孩子都要多发1颗糖。
所以我们需要记录递减序列的开始位置(s),他可以是递增序列的最后一位,也可以是同等级的最后一位,以及记录给这个孩子发了多少糖果。随后进入递减部分时,需要依此给中间的孩子补发1颗糖(设i为当前位置,也就是需要在总数补上i-s颗糖果),而如果给第s个孩子比第s+1个孩子多发了不止1颗糖,只需要补i-s-1颗糖,因为尽管给第s+1个孩子多发了1颗糖,但他还是比第s个孩子发的糖果少,保持了数量的优先顺序。
参考代码如下:
class Solution {
public:
int candy(vector<int>& ratings) {
if(ratings.size() <= 1)
return ratings.size();
int result = 1;
int candy = 1;
int max = 0;
int c = 1;
for(int i = 1; i < ratings.size(); i++) {
if(ratings[i] > ratings[i-1]) {
candy++;
max = i;
c = candy;
}
else if(ratings[i] == ratings[i-1] ){
candy = 1;
max = i;
c = candy;
}
else {
if(candy == 1) {
if(c == 1)
result += i - max;
else {
c--;
if(c == 1)
result += i - max;
else
result += i - max - 1;
}
}
candy = 1;
}
result += candy;
}
return result;
}
};
看了一下discuss,里面有一种更好理解的方法。首先设每个孩子发1颗糖果,优先级高的孩子比前一孩子多发一颗糖果。而对于递减序列,从右往前处理便是递增序列,使用同样的处理方式便能计算得到每个孩子应发的糖数。最后将其全部加起来便能得到想要的结果了。
参考代码如下:
class Solution {
public:
int candy(vector<int>& ratings) {
if(ratings.size() <= 1)
return ratings.size();
int num[ratings.size()];
int n = ratings.size();
for(int i = 0; i < n; i++)
num[i] = 1;
for(int i = 1; i < n; i++) {
if(ratings[i] > ratings[i-1])
num[i] = num[i-1] + 1;
}
for(int i = n-1; i > 0; i--) {
if(ratings[i-1] > ratings[i])
num[i-1] = max(num[i-1], num[i]+1);
}
int result = 0;
for(int i = 0; i < n; i++)
result += num[i];
return result;
}
};