135. Candy

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

已知我们有N个孩子,每个孩子有一个等级,我们给孩子们发糖果,每个孩子至少要发一颗糖果,等级高的孩子要比他的邻居有更多的糖果。求最少需要多少糖果。

这道题的一个重要约束条件是——等级高的孩子要比他的邻居发到更多的糖果,也就是说,对于等级为:低,高,低 的情况,假设给第一个孩子发了a颗糖果,等级最高的第二个孩子至少需要发a+1颗糖果,而第三个孩子只需要发1颗糖果(当然也可以发更多/更少的糖果,因为没有约束条件)。而同时,对于等级相同的孩纸——没有约束条件,也就是说等级相同的孩子,第二个孩子可以只发1颗糖果。

注意到以上点之后,最大的问题在于等级递减的情况了。假设对于低→高的情况我们严格地采取等级高的孩子多发一颗糖的,对于高→低的情况采取低的孩子只发一颗糖,同等级的孩子从第二个孩子开始只发一颗糖的策略。由于高→低的情况,低优先级的孩子最少只发1颗糖,但是若是这个孩子后面再跟了一个更低优先级的孩子,也就是高→中→低的情况,那么中间的那个孩子就不能只发一颗糖,而得多发一颗糖才能满足约束条件。那么这里就有两种情况:①等级高的孩子只比中等等级的孩子多发1颗糖。②等级高的孩子比中等等级的孩子多发不只1颗糖。对于第一种情况,那么不子中等等级的孩子需要多发1颗糖,而高等级的孩子也需要多发一颗糖,才能满足约束条件。对于第二中情况,等级高的孩子比中等等级的孩子多发了至少2颗糖,那么只需要给中等等级高的孩子多发1颗糖即可。以此类推,对于等级递减的情况,也就是高→中高→中→中低→……→低的情况,最低级不能发0颗糖,所以中间递减的部分每个孩子都要多发1颗糖。

所以我们需要记录递减序列的开始位置(s),他可以是递增序列的最后一位,也可以是同等级的最后一位,以及记录给这个孩子发了多少糖果。随后进入递减部分时,需要依此给中间的孩子补发1颗糖(设i为当前位置,也就是需要在总数补上i-s颗糖果),而如果给第s个孩子比第s+1个孩子多发了不止1颗糖,只需要补i-s-1颗糖,因为尽管给第s+1个孩子多发了1颗糖,但他还是比第s个孩子发的糖果少,保持了数量的优先顺序。

参考代码如下:

class Solution {
  public:
    int candy(vector<int>& ratings) {
        if(ratings.size() <= 1)
            return ratings.size();
        int result = 1;
        int candy = 1;
        int max = 0;
        int c = 1;
        for(int i = 1; i < ratings.size(); i++) {
            if(ratings[i] > ratings[i-1]) {
                candy++;
                max = i;
                c = candy;
            }
            else if(ratings[i] == ratings[i-1] ){
                candy = 1;
                max = i;
                c = candy;
            }
            else {
                if(candy == 1) {
                    if(c == 1)
                        result += i - max;
                    else {
                        c--;
                        if(c == 1)
                            result += i - max;
                        else
                            result += i - max - 1;
                    }
                }
                candy = 1;
            }
            result += candy;
        }
        return result;
    }
};

看了一下discuss,里面有一种更好理解的方法。首先设每个孩子发1颗糖果,优先级高的孩子比前一孩子多发一颗糖果。而对于递减序列,从右往前处理便是递增序列,使用同样的处理方式便能计算得到每个孩子应发的糖数。最后将其全部加起来便能得到想要的结果了。

参考代码如下:

扫描二维码关注公众号,回复: 1532916 查看本文章
class Solution {
  public:
    int candy(vector<int>& ratings) {
        if(ratings.size() <= 1)
            return ratings.size();
        int num[ratings.size()];
        int n = ratings.size();
        for(int i = 0; i < n; i++)
            num[i] = 1;
        for(int i = 1; i < n; i++) {
            if(ratings[i] > ratings[i-1])
                num[i] = num[i-1] + 1;
        }
        for(int i = n-1; i > 0; i--) {
            if(ratings[i-1] > ratings[i])
                num[i-1] = max(num[i-1], num[i]+1);
        }
        int result = 0;
        for(int i = 0; i < n; i++)
            result += num[i];
        return result;
    }
};

猜你喜欢

转载自blog.csdn.net/xiasilo/article/details/78703878