力扣 135. 分发糖果
n
个孩子站成一排。给你一个整数数组 ratings
表示每个孩子的评分。
你需要按照以下要求,给这些孩子分发糖果:
- 每个孩子至少分配到
1
个糖果。 - 相邻两个孩子评分更高的孩子会获得更多的糖果。
请你给每个孩子分发糖果,计算并返回需要准备的 最少糖果数目 。
示例 1:
输入:ratings = [1,0,2]
输出:5
解释:你可以分别给第一个、第二个、第三个孩子分发 2、1、2 颗糖果。
示例 2:
输入:ratings = [1,2,2]
输出:4
解释:你可以分别给第一个、第二个、第三个孩子分发 1、2、1 颗糖果。
第三个孩子只得到 1 颗糖果,这满足题面中的两个条件。
提示:
n == ratings.length
1 <= n <= 2 * 104
0 <= ratings[i] <= 2 * 104
题解
贪心,来自:https://www.youtube.com/watch?v=PzBYQA6FshA
因为要分发得最少,所以应该从前往后判断+从后往前,考虑两个方向。
第一次从前往后,使用数组left记录从前往后判断得到的分配结果,如1,2,6,5,4,3,2
。
因为最低分配一个,所以默认每一个人一个,left
全1,接下来遍历比较当前元素和前一个元素:
- 当前元素>前一个元素,则当前元素应该比前一个得到更多的糖,则更新分配为前一个
+1
,left[i]=left[i-1]+1
; - 否则,分配1;
此时得到Left=1,2,3,1,1,1
,可以发现没有从后往前的遍历,分配并不完全正确。
接下来从后往前,此时可以节约数组,只用一个变量right
记录当前分配最大值,遍历比较当前元素和后一个元素:
- 当前元素>后一个元素,则当前元素应该比后一个得到更多的糖,则更新分配为前一个
+1
,right++
,需要判断right
和left
对应的分配,选取较大值; - 否则,
right
重置为1;
sum
可以在从后往前遍历中进行累计。
查看代码
class Solution {
public:
int candy(vector<int>& ratings) {
int n=ratings.size();
vector<int>left(n,1);//从左往右
//从左往右,比较当前i和前一个i-1
for(int i=1;i<n;++i){
left[i]=ratings[i]>ratings[i-1]?left[i-1]+1:1;
}
//从右往左,为了节约right数组,用变量right记录最大的值,边跑边比较,并且结合第一遍的结果选最大的,直接修改在left中
int right=1;
int sum=0;
for(int j=n-2;j>=0;--j){
//比较当前j和后一个j+1
if(ratings[j]>ratings[j+1]){
++right;//累计
//选最大的
left[j]=left[j]>right?left[j]:right;
}
else
right=1;
sum+=left[j];//累计
}
sum+=left[n-1];//最后一个小朋友分配的还没有加
return sum;
}
};