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顆糖果,優先級高的孩子比前一孩子多發一顆糖果。而對於遞減序列,從右往前處理便是遞增序列,使用同樣的處理方式便能計算得到每個孩子應發的糖數。最後將其全部加起來便能得到想要的結果了。

參考代碼如下:

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;
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章