老师想给孩子们分发糖果,有 N 个孩子站成了一条直线,老师会根据每个孩子的表现,预先给他们评分。
你需要按照以下要求,帮助老师给这些孩子分发糖果:
- 每个孩子至少分配到 1 个糖果。
- 相邻的孩子中,评分高的孩子必须获得更多的糖果。
那么这样下来,老师至少需要准备多少颗糖果呢?
示例 1:
输入: [1,0,2]
输出: 5
解释: 你可以分别给这三个孩子分发 2、1、2 颗糖果。
示例 2:
输入: [1,2,2]
输出: 4
解释: 你可以分别给这三个孩子分发 1、2、1 颗糖果。
第三个孩子只得到 1 颗糖果,这已满足上述两个条件。
基本思路:本问题可以拆分成两个部分,从左往右和从右往左看都符合要求:
- 从左往右看,若ratings[i]>ratings[i-1],那么第i个孩子一定比i-1个孩子获得的果子多,否则为1,
- 从右往左看,若ratings[i]>ratings[i+1],那么第i个孩子一定比i+1个孩子获得的果子多,否则为1,
- 对于同一个位置的,去两者之间最大的就一定可以满足要求
int candy(vector<int>& ratings) {
int len=ratings.size();
int ans=0;
int cnt=1;
vector<int> leftCal(len,0);
for(int i=1;i<len;i++){
if(ratings[i]>ratings[i-1])
cnt++;
else
cnt=1;
leftCal[i]=cnt;
}
cnt=1;
for(int i=len-1;i>=0;i--){
if(i<len-1&&ratings[i]>ratings[i+1]){
cnt++;
}
else
cnt=1;
ans+=max(leftCal[i],cnt);
}
return ans;
}
基本思路:实质上和上面的方法相同,从左往右看,如果单增和上述的方法相同;但是如果遇到单减序列,可以看作从右往左的单增序列,或者是将递减序列逆转,
- 对于一个先增后减的序列,顶点属于谁?主要看左右两边序列的长度
int candy(vector<int>& ratings) {
int inc=1,des=0,res=1,len=ratings.size();
for(int i=1;i<len;i++){
if(ratings[i]>=ratings[i-1]){
dec=0;
pre=(ratings[i]==ratings[i-1])?1:pre+1;
res+=pre;
inc=pre; //记录严格递增的元素个数
}
else{
dec++;
if(inc==dec){ //说明从右往左看更大,顶点算在递减序列上
dec++;
}
res+=dec;
pre=1;
}
}
return ans;
}