题目
老师想给孩子们分发糖果,有 N 个孩子站成了一条直线,老师会根据每个孩子的表现,预先给他们评分。
你需要按照以下要求,帮助老师给这些孩子分发糖果:
每个孩子至少分配到 1 个糖果。
相邻的孩子中,评分高的孩子必须获得更多的糖果。
那么这样下来,老师至少需要准备多少颗糖果呢?
示例 1:
输入: [1,0,2]
输出: 5
解释: 你可以分别给这三个孩子分发 2、1、2 颗糖果。
示例 2:
输入: [1,2,2]
输出: 4
解释: 你可以分别给这三个孩子分发 1、2、1 颗糖果。
第三个孩子只得到 1 颗糖果,这已满足上述两个条件。
思路
- 为数不多能做出来的困难题,虽然思路不是很清晰
- 数组count是用来记录递增时的各个孩子的糖果数,递减时不使用count记录,所以递减部分的count都等于1
- countDecline是记录分给递减时孩子的糖果数
- declineBeginIndex是递减开始的索引,需要在合适的时候(遇到递增或相同时)变回-1,-1的意义就是还没确定当前递减开始的索引
- 递增部分就是改变count和更新declineBeginIndex,相同部分就是更新declineBeginIndex
- 递减部分,如果declineBeginIndex等于-1就更新它,随后更新countDecline,因为前面都是最优的,如果出现新的递减,末尾两个糖果数必定是等于1,所以要将前面所有递减部分都+1
- 最重要的部分是,举个例子
- 1,2,5,3,2,1。rating=5的地方,count=3,当遍历到最后的rating=1的地方时,会更新ranting=3的地方count=3,那么就要把rating=5的count+1
- 1,2,5,3,2。而这里,递减时rating=5的count不用更新
- 看了题解,思路是类似的,不过别人会更清晰,代码也更容易理解。两次遍历,第一次从左往右,用left数组记录递增部分(其实就是我的count);第二次从右往左,用一个变量right记录递减部分,然后取right和left对应值较大的作为最终结果的一部分(解决了我的第7点)
代码
class Solution {
public:
int candy(vector<int>& ratings) {
vector<int> count(ratings.size(), 1);
int countDecline = 0, declineBeginIndex = -1;
for(int i = 1; i < ratings.size(); ++i){
if(ratings[i] > ratings[i-1]){
count[i] = count[i-1] + 1;
declineBeginIndex = -1;
}
else if(ratings[i] < ratings[i-1]){
if(declineBeginIndex == -1) declineBeginIndex = i;
if(ratings[declineBeginIndex] < ratings[declineBeginIndex-1]
&& 1 + i - declineBeginIndex == count[declineBeginIndex-1]) ++count[declineBeginIndex-1];
countDecline += i - declineBeginIndex;
}
else declineBeginIndex = -1;
}
int ans = 0;
for(auto c:count) ans += c;
return ans + countDecline;
}
};