题目:
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?
思路:
思路1:首先要考虑,题目中没有提到连续两个小孩,当他们的ratings相同时应当如何处理。例如,144321。显然,两个ratings为4的小孩不会拿到相同的candy,并且两者之间没有关系。所以我们可以将ratings相同且相邻的小孩分成两个子队列来考虑。
由于上述过程中, 我们将相等的情况排除了,所以在接下来的讨论中,我们可以知道两个相邻的小孩的情况只可能为大于或者小于的关系。
1) 最简单的情况是k个小孩,他们是连续递增或者递减的关系。则candy总数是(1+k)*k/2。
2)在1)的条件上增加复杂度,k个小孩,先递增再递减。这时候两段都是从个数为1开始发放candy,向中间递推直到遇到最大值。最大值这个位置应当取两段递推的较大值。
3)复杂的情况都能够划分为如上1)与2)的子队列。
因此,我们遍历一遍一个不包含相等ratings的队列来找到所有最小值,这些值都应当取1。接下来,我们取相邻最小值组成依次计算,如3)所述。每个部分按照1),2)的计算方法去发放candy。注,开始与结束的位置需要特殊考虑。
思路2:
首先,每个小孩发一个candy。
然后,从右往左,当ratings递减时依次累加发candy。
最后,从左往右,当ratings递增时依次累加发candy,遇到最高点时注意不要覆盖上一步的数据。
整个过程可以由如下的图示来表示:
代码:
思路1:
class Solution {
public:
int count;
vector<int> ratings;
int candy(vector<int> &ratings) {
this->ratings = ratings;
count=0;
int begin=0;int end=1;
while(ratings.size()>end)
{
if(ratings[end-1]==ratings[end])
{
countBottom(begin,end-1);
begin=end;
}
end++;
};
countBottom(begin,end-1);
//将相邻位置rating相同的队列分割为子队列
return count;
}
void countBottom(int i, int j)
{
if(i==j)
{
count+=1;
return;
}
else if(i+1==j)
{
count+=3;
return;
}
//数目小于2的情况,一定单调
vector<int> bottom;
for(int cur=i+1;cur<j;cur++)
{
if(cur == i+1&&ratings[cur-1]<ratings[cur])
{
bottom.push_back(cur-1);
}
else if(cur == i+1&&ratings[cur-1]>ratings[cur])
{
bottom.push_back(cur-2);
}
if(ratings[cur-1]>ratings[cur]&&ratings[cur]<ratings[cur+1])
{
bottom.push_back(cur);
}
if(cur == j-1&&ratings[cur]>ratings[cur+1])
{
bottom.push_back(cur+1);
}
else if(cur == j-1&&ratings[cur]<ratings[cur+1])
{
bottom.push_back(cur+2);
}
}
//寻找队列中的最小值,特殊考虑开始与结束位置
if(bottom.size()>0)
{
count+=bottom.size();
if(bottom[0]==i-1)
{
count--;
}
if(bottom[bottom.size()-1]==j+1)
{
count--;
}
//开始与结束为止可能是个无效的位置
for(int i=1;i<bottom.size();i++)
{
if(bottom[i-1]+1<=bottom[i]-1)
{
int max=ratings[bottom[i-1]+1];
int index=bottom[i-1]+1;
for(int j=bottom[i-1]+1;j<bottom[i];j++)
{
if(ratings[j]>max)
{
max=ratings[j];
index=j;
}
}
//找到最大值的位置
count+=((index-(bottom[i-1]+1))<((bottom[i]-1)-index)?(((bottom[i]-1)-index)+2):((index-(bottom[i-1]+1))+2));
//最大值的取值
if(index>(bottom[i-1]+1))
{
count+=((index-(bottom[i-1]+1))*(index-(bottom[i-1]+1)+3)/2);
}
//最大值的左侧
if(index<(bottom[i]-1))
{
count+=(((bottom[i]-1)-index)*((bottom[i]-1)-index+3)/2);
}
//最大值的右侧
}
}
}
}
};
思路2:
class Solution {
public:
int* candies;
int candy(vector<int> &ratings) {
candies = new int[ratings.size()];
for(int i = 0; i < ratings.size(); i++){
candies[i] = 1;
}
for(int i = ratings.size() - 1; i > 0; i--){
if(ratings[i] < ratings[i - 1]){
candies[i - 1] = candies[i] + 1;
}
}
for(int i = 0; i < ratings.size() - 1; i++){
if(ratings[i] < ratings[i + 1]){
int tmp = candies[i] + 1;
if(candies[i + 1] < tmp){
candies[i + 1] = tmp;
}
}
}
int sum = 0;
for(int i = 0; i < ratings.size(); i++){
sum += candies[i];
}
return sum;
}
};