题目:
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个小孩站成一排,每个孩子有一个数字。为每个孩子分配糖果。有下面两个要求:
1、每个孩子至少一个糖果
2、如果这个孩子的数字比相邻的孩子的数字大,则糖果数要多于他的邻居。
问:至少要分配多少糖果?
思路:
1、两次遍历,求出每个孩子的糖果数量,然后相加
2、一次遍历,直接计算糖果总数。如果递增,则依次加上每一个(前一个糖果数量+1)。如果开始出现递减,则统计出递减的次数,详情见代码。
代码1:
class Solution {
public:
int candy(vector<int>& ratings)
{
int len = ratings.size();
if(len <= 1)
return len;
int result = 0;
vector<int> candy(len,1);
//如果比前一个小孩的数值大,则糖数+1,否则默认为1
for(int i = 1 ; i < len ; i++)
{
if(ratings[i] > ratings[i-1])
candy[i] = candy[i-1] + 1;
}
//result先把最后一个小孩的糖数加上,因为由上面一个循环就可以得到最后一个小孩的糖数
//如果最后一个比前一个小,则默认为1,如果比前一个大,则最后递增的可以确定下来
result = candy[len-1];
//逆序再遍历一遍,最后一个已经确定,由最后一个确定前面的
for(int i = len-2 ; i >= 0 ; i--)
{
if(ratings[i] > ratings[i+1])
candy[i] = max(candy[i+1]+1 , candy[i]);
result += candy[i];
}
return result;
}
};
代码2:
class Solution {
public:
int candy(vector<int>& ratings)
{
int len = ratings.size();
if(len <= 1)
return len;
int result = 1;
int cur = 1 , down = 0;//cur表示当前i应得的糖果数量,down表示递减的次数,如3,2,1,4 递减了2次
for(int i = 1 ; i < len ; i++)
{
if(ratings[i] >= ratings[i-1])
{
if(down > 0)
{
result += (1+down)*down / 2;//加上从down开始的地方到i-1,即糖果数量从down到1(等差数列和)
if(down >= cur)
result += down + 1 - cur;//如果递减开始的地方,即极大点比down小,则实际极大点的值应该是down+1,但是之前只加了cur,所以还要加上dowm-cur+1,比如数组1,5,4,3,2,1。前两个糖果数量按之前算的分别为1,2,后面四个是(4+1)*4/2=10,第三个4的糖果数量为4,因为之前第二个5的糖果数量当做2加上了,实际上应该是5个,所以应该再加上down + 1 - cur个糖果
down = 0;
cur = 1;
}
cur = ratings[i] == ratings[i-1] ? 1 : cur + 1;//求出当前i的糖果数量
result += cur;//加上当前糖果数量
}
else
down++;
}
if(down > 0)
{
result += (1+down)*down / 2;//如果后面递减,则加上最后的递减数列的糖果
if(down >= cur)
result += down - cur + 1;
}
return result;
}
};