LeetCode | 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?


思路:

思路1:首先要考虑,题目中没有提到连续两个小孩,当他们的ratings相同时应当如何处理。例如,144321。显然,两个ratings为4的小孩不会拿到相同的candy,并且两者之间没有关系。所以我们可以将ratings相同且相邻的小孩分成两个子队列来考虑。

由于上述过程中, 我们将相等的情况排除了,所以在接下来的讨论中,我们可以知道两个相邻的小孩的情况只可能为大于或者小于的关系。
1) 最简单的情况是k个小孩,他们是连续递增或者递减的关系。则candy总数是(1+k)*k/2。
2)在1)的条件上增加复杂度,k个小孩,先递增再递减。这时候两段都是从个数为1开始发放candy,向中间递推直到遇到最大值。最大值这个位置应当取两段递推的较大值。
3)复杂的情况都能够划分为如上1)与2)的子队列。

因此,我们遍历一遍一个不包含相等ratings的队列来找到所有最小值,这些值都应当取1。接下来,我们取相邻最小值组成依次计算,如3)所述。每个部分按照1),2)的计算方法去发放candy。注,开始与结束的位置需要特殊考虑。

思路2:
首先,每个小孩发一个candy。
然后,从右往左,当ratings递减时依次累加发candy。
最后,从左往右,当ratings递增时依次累加发candy,遇到最高点时注意不要覆盖上一步的数据。
整个过程可以由如下的图示来表示:


代码:

思路1:
class Solution {
public:
    int count;
    vector<int> ratings;
    int candy(vector<int> &ratings) {
        this->ratings = ratings;
        count=0;
        int begin=0;int end=1;
        while(ratings.size()>end)
        {
            if(ratings[end-1]==ratings[end])
            {
                countBottom(begin,end-1);
                begin=end;
            }
            end++;
        };
        countBottom(begin,end-1);
        //将相邻位置rating相同的队列分割为子队列
        
        return count;
    }
    
    void countBottom(int i, int j)
    {
        if(i==j)
        {
            count+=1;
            return;
        }
        else if(i+1==j)
        {
            count+=3;
            return;
        }
        //数目小于2的情况,一定单调
        
        vector<int> bottom;
        
        for(int cur=i+1;cur<j;cur++)
        {
            if(cur == i+1&&ratings[cur-1]<ratings[cur])
            {
                bottom.push_back(cur-1);
            }
            else if(cur == i+1&&ratings[cur-1]>ratings[cur])
            {
                bottom.push_back(cur-2);
            }
            if(ratings[cur-1]>ratings[cur]&&ratings[cur]<ratings[cur+1])
            {
                bottom.push_back(cur);
            }
            if(cur == j-1&&ratings[cur]>ratings[cur+1])
            {
                bottom.push_back(cur+1);
            }
            else if(cur == j-1&&ratings[cur]<ratings[cur+1])
            {
                bottom.push_back(cur+2);
            }
        }
        //寻找队列中的最小值,特殊考虑开始与结束位置
        
        if(bottom.size()>0)
        {
            count+=bottom.size();
            if(bottom[0]==i-1)
            {
                count--;
            }
            if(bottom[bottom.size()-1]==j+1)
            {
                count--;
            }
            //开始与结束为止可能是个无效的位置
            
            for(int i=1;i<bottom.size();i++)
            {
                if(bottom[i-1]+1<=bottom[i]-1)
                {
                    int max=ratings[bottom[i-1]+1];
                    int index=bottom[i-1]+1;
                    for(int j=bottom[i-1]+1;j<bottom[i];j++)
                    {
                        if(ratings[j]>max)
                        {
                            max=ratings[j];
                            index=j;
                        }
                     }
                     //找到最大值的位置
                     count+=((index-(bottom[i-1]+1))<((bottom[i]-1)-index)?(((bottom[i]-1)-index)+2):((index-(bottom[i-1]+1))+2));
                     //最大值的取值
                     if(index>(bottom[i-1]+1))
                     {
                        count+=((index-(bottom[i-1]+1))*(index-(bottom[i-1]+1)+3)/2);
                     }
                     //最大值的左侧
                     if(index<(bottom[i]-1))
                     {
                         count+=(((bottom[i]-1)-index)*((bottom[i]-1)-index+3)/2);
                     }
                     //最大值的右侧
                }
            }    
        }
    }
};

思路2:
class Solution {
public:
    int* candies;
    int candy(vector<int> &ratings) {
        candies = new int[ratings.size()];
        for(int i = 0; i < ratings.size(); i++){
            candies[i] = 1;
        }
        
        for(int i = ratings.size() - 1; i > 0; i--){
            if(ratings[i] < ratings[i - 1]){
                candies[i - 1] = candies[i] + 1;
            }
        }
        
        for(int i = 0; i < ratings.size() - 1; i++){
            if(ratings[i] < ratings[i + 1]){
                int tmp = candies[i] + 1;
                if(candies[i + 1] < tmp){
                    candies[i + 1] = tmp;
                }
            }
        }
        
        int sum = 0;
        for(int i = 0; i < ratings.size(); i++){
            sum += candies[i];
        }
        
        return sum;
    }
};



  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值