Candy
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?
算法思想:
定义数组candy保存第i个孩子分到的糖果数,初始化全为1
找到等级向量数组中最小的元素,从数组中最小的元素开始
1、先往后遍历找到递增顺序的最大的元素,并依次向上累加,最小的元素candy[i]为1,右边比它大的元素candy[i+1]为2,以此类推
2、然后从最大的元素后一个元素(肯定比最大的这个元素小或者相等)开始,向后找到递减顺序最小的元素,如果下标值大于数组长度,退出循环。
以这个最小的元素作为基准点,向左依次向上累加,注意当递减到这个最大元素时,一定是取这个元素当前的值和依次递减累加求的的值得最大值,
否则值取得小了,前面的依次递增顺序求得的值就被破坏了。然后以这个最小元素开始,转入1执行;
3、再往前遍历找到递减顺序最大的元素,并依次向上累加;
4、然后从最大的元素前一个元素(肯定比最大的这个元素小或者相等)开始,向前找到递减顺序最小的元素,如果下标小于0,退出循环;
以这个最小元素作为基准点,向右依次向上累加,然后从这个最小元素开始,转入3执行;
最后将candy数组遍历求和,即得最小的糖果数。
class Solution{
public:
int ajustRight(vector<int> &ratings,int *candy,int k,int n){//向右递增顺序调整,返回的是最大元素的后一个元素
int i=k+1;
while(i<n&&ratings[i]>ratings[i-1]){
candy[i]=candy[i-1]+1>candy[i]?candy[i-1]+1:candy[i];
i++;
}
return i;
}
int ajustLeft(vector<int> &ratings,int *candy,int k){//向左递增顺序调整,返回最大元素前一个元素
int i=k-1;
while(i>=0&&ratings[i]>ratings[i+1]){
candy[i]=candy[i+1]+1>candy[i]?candy[i+1]+1:candy[i];
i--;
}
return i;
}
int findLMin(vector<int> &ratings,int k){//向左找最小的元素
int i=k;
while(i-1>=0){
if(ratings[i-1]<ratings[i])i--;
else break;
}
return i;
}
int findRMin(vector<int> &ratings,int k,int n){//向右找最小的元素
int i=k;
while(i+1<n){
if(ratings[i+1]<ratings[i])i++;
else break;
}
return i;
}
void ajust(vector<int> &ratings,int *candy,int k,int n){
candy[k]=1;
int t=k,h,minV;
while(1){
h=ajustRight(ratings,candy,t,n);//向右递增调整
if(h>=n)break;
minV=findRMin(ratings,h,n);//找到右边最小元素
candy[minV]=1;
ajustLeft(ratings,candy,minV);//向左递增调整
t=minV;
}
t=k;
while(1){
int h=ajustLeft(ratings,candy,t);//向左递增调整
if(h<0)break;
minV=findLMin(ratings,h);//找到左边最小元素
candy[minV]=1;
ajustRight(ratings,candy,minV,n);//向右递增调整
t=minV;
}
}
int candy(vector<int> &ratings){
int minR=0x7fffffff;
int n=ratings.size();
int *candy=new int[n];
for(int i=0;i<n;i++)candy[i]=1;
int index;
for(int i=0;i<n;i++){
if(minR>=ratings[i]){
minR=ratings[i];
index=i;//找寻最小元素下标
}
}
ajust(ratings,candy,index,n);
int sum=0;
for(int i=0;i<n;i++)sum+=candy[i];
return sum;
}
};
answer2:
迭代
时间O(n),空间O(n)
class Solution {
public:
int candy(vector<int> &ratings) {
const int n=ratings.size();
vector<int> increment(n);
//左右各扫描一遍
for(int i=1,inc=1;i<n;++i){
if(ratings[i]>ratings[i-1])
increment[i]=max(inc++,increment[i]);
else inc=1;
}
for(int i=n-2,inc=1;i>=0;--i){
if(ratings[i]>ratings[i+1])
increment[i]=max(inc++,increment[i]);
else inc=1;
}
return accumulate(&increment[0],&increment[0]+n,n);
}
};
递归 备忘录法
时间O(n),空间O(n)
class Solution {
public:
int candy(vector<int> &ratings) {
vector<int> f(ratings.size());
int sum=0;
for(int i=0;i<ratings.size();++i)
sum+=solve(ratings,f,i);
return sum;
}
int solve(const vector<int> &ratings,vector<int>& f,int i){
if(f[i]==0){
f[i]=1;
if(i>0&&ratings[i]>ratings[i-1])
f[i]=max(f[i],solve(ratings,f,i-1)+1);
if(i<ratings.size()-1&&ratings[i]>ratings[i+1])
f[i]=max(f[i],solve(ratings,f,i+1)+1);
}
return f[i];
}
};