题目
老师想给孩子们分发糖果,有 N 个孩子站成了一条直线,老师会根据每个孩子的表现,预先给他们评分。
你需要按照以下要求,帮助老师给这些孩子分发糖果:
- 每个孩子至少分配到 1 个糖果。
- 评分更高的孩子必须比他两侧的邻位孩子获得更多的糖果。
那么这样下来,老师至少需要准备多少颗糖果呢?
示例 1:
输入:[1,0,2] 输出:5 解释:你可以分别给这三个孩子分发 2、1、2 颗糖果。
示例 2:
输入:[1,2,2] 输出:4 解释:你可以分别给这三个孩子分发 1、2、1 颗糖果。 第三个孩子只得到 1 颗糖果,这已满足上述两个条件。
解题
方法一:贪心
这在leetcode上是一道困难的题目,其难点就在于贪心的策略,如果在考虑局部的时候想两边兼顾,就会顾此失彼。
那么本题采用了两次贪心的策略:
- 一次是从左到右遍历,只比较右边孩子评分比左边大的情况。
- 一次是从右到左遍历,只比较左边孩子评分比右边大的情况。
这样从局部最优推出了全局最优,即:相邻的孩子中,评分高的孩子获得更多的糖果。
class Solution { public: int candy(vector<int>& ratings) { vector<int> candyVec(ratings.size(),1); for(int i=1;i<ratings.size();i++){ if(ratings[i]>ratings[i-1]) candyVec[i]=candyVec[i-1]+1; } for(int i=ratings.size()-2;i>=0;i--){ if(ratings[i]>ratings[i+1]) candyVec[i]=max(candyVec[i],candyVec[i+1]+1); } int res=0; for(int num:candyVec) res+=num; return res; } };
对于从右边开始遍历的时候,如果candyVec[i]>candyVec[i+1]+1
,说明本来就已经满足条件了,不需要更改
max(candyVec[i],candyVec[i+1]+1)
此时就为candyVec[i]
。
因此可以先遍历左边,再遍历右边的方式
for(int i=ratings.size()-2;i>=0;i--){ if(ratings[i]>ratings[i+1]) candyVec[i]=max(candyVec[i],candyVec[i+1]+1); }
关于求和
可以使用
return accumulate(candyVec.begin(),candyVec.end(),0);
accmulate(迭代器开头,迭代器末尾,初始数值);
换种写法
class Solution { public: int candy(vector<int>& ratings) { int n=ratings.size(); vector<int> dp(n,1); for(int i=1;i<ratings.size();i++){ if(ratings[i]>ratings[i-1]){ dp[i]=dp[i-1]+1; } } for(int i=ratings.size()-2;i>=0;i--){ if(ratings[i]>ratings[i+1]){ dp[i]=max(dp[i],dp[i+1]+1); } } return accumulate(dp.begin(),dp.end(),0); } };
java
class Solution { public int candy(int[] ratings) { int n=ratings.length; int[] dp=new int[n]; Arrays.fill(dp,1); for(int i=1;i<n;i++){ if(ratings[i]>ratings[i-1]){ dp[i]=Math.max(dp[i],dp[i-1]+1); } } for(int i=n-2;i>=0;i--){ if(ratings[i]>ratings[i+1]){ dp[i]=Math.max(dp[i],dp[i+1]+1); } } int sum=0; for(int i=0;i<n;i++){ sum+=dp[i]; } return sum; } }