题目如下:
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?
分析如下:
开出一个O(n)大小的数组,用来记录每个小孩的那糖数,因为每个小孩至少要拿1颗糖,所以数组元素初始化为1.
case 1. 假设有小孩A, B , rating分别是{1,1},显然每个人各拿1颗糖就够,显然每个人拿糖颗数是{1, 1},最后答案为2.
case 2. 假设有小孩A, B, C, D, rating分别是{10, 32, 43, 55}, 那么每个人拿糖的颗数依次为{1, 2, 3, 4},最后答案为10. 这说明可以顺序扫描数组,找到一个递增序列,拿糖数从1开始递增。比如这里找到了递增序列A, B, C, D, 拿糖数从A = 1开始依次递增。
case3. 假设有小孩A, B ,C ,D E, F, rating 分别是{10, 32, 43, 55, 40, 11}, 那么每个人拿糖颗数是 {1, 2, 3, 4, 2, 1}, 这说明可以在顺序扫描数组之后,再反序扫描数组,得到反序扫描数组时的递减序列。比如顺序扫描了A, B ,C, D, E, F之后,得到{1, 2, 3, 4, 1, 1,},之后再反序扫描数组,找寻递增数列,每段递增数列的拿糖颗数也从1开始递增。反序扫到F,得到F=1, 扫到E 因为E> F, 所以E = 2。扫到D,因为D> E ,所以D= 3,但是其实这里的D和E, F不一样,D是之前顺序扫描时候已经被赋值过的值,D= 4,而反序扫描的时候,
D= 3, 显然只能取大值才能满足要求。所以反序扫描的时候,如果遇到已经在顺序扫描中赋值的小孩,要两个值中取较大的值。
上面描述的是贪心算法的思想。
我的代码:
//38ms
class Solution {
public:
int candy(vector<int> &ratings) {
if (ratings.size() <= 1) return 1;
int sum = 0;
vector<int> assign(ratings.size(), 1);
for (int i = 1; i < assign.size(); ++i) {
if (ratings[i] > ratings[i - 1]) {
if (assign[i-1] + 1 > assign[i]) {
assign[i] = assign[i-1] + 1;
}
}
}
for (int i = assign.size() - 2; i >= 0; --i) {
if (ratings[i] > ratings[i + 1]) {
if (assign[i+1] + 1 > assign[i]) {
assign[i] = assign[i+1] + 1;
}
}
}
for (int i = 0; i < assign.size(); ++i)
sum += assign[i];
return sum;
}
};