Leetcode P0135"Candy" 题解

2020/09/13 Leetcode

博文中会简要介绍Leetcode P0135题目分析及解题思路。

“Candy”这道题不算特别难,主要考察的是贪心算法。这道题利用贪心算法可以在O(n)的时间复杂度内得到结果。

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?

Example 1:

Input: [1,0,2]
Output: 5
Explanation: You can allocate to the first, second and third child with 2, 1, 2 candies respectively.

Example 2:

Input: [1,2,2]
Output: 4
Explanation: You can allocate to the first, second and third child with 1, 2, 1 candies respectively.  
             The third child gets 1 candy because it satisfies the above two conditions.

这道题贪心算法的思路其实很简单,围绕的核心是尽可能给指定的孩子最少的糖。有如下三种情况,

首先第一个孩子至少要拿到1个糖果,所以先给candies[0]赋值为1,

  1. 若当前rating和上一个rating一样,则根据贪心算法原则,尽可能给最少的糖果,则给1个糖果。

  2. 若当前rating比上一个大,则根据贪心算法的原则,只给出比上一个孩子多1个的糖果。

  3. 若当前rating比上一个小(核心情况),此时我们需要记录当前单调递减序列的长度,根据贪心的原则,我们将会在持有最小rating的孩子那里给出1个糖果,那么当我们知道完整的递减序列后,就可以逆向得到这个递减序列上的每个人最少应持有的糖果个数。

    一旦递减序列长度不为零,但是遇到了前两种情况或者遍历结束,我们则开始计算这个递减序列所需要的最少糖果个数。首先是判断递减序列的最左起点的糖果数目是否满足要求,若低于最少糖果需求,则补足,否则不变,然后计算剩余递减序列的最少糖果需求即可。

以下是Java的题解代码实现。

class Solution {
    public int candy(int[] ratings) {
        int N = ratings.length;
        if (N == 0)
            return 0;
        
        int total = 1, decreasingLen = 0;
        int[] candies = new int[N];
        candies[0] = 1;
        for (int itr=1; itr<N; ++itr) {
            if (ratings[itr] == ratings[itr-1]) {
                candies[itr] = 1;
                
                // Calculate the addition to the former decreasing sequence
                if (decreasingLen > 0) {
                    total += this.calculate(decreasingLen, candies, itr);
                    decreasingLen = 0;
                }
                
                total += candies[itr];
            }
            else if (ratings[itr] > ratings[itr-1]) {
                candies[itr] = candies[itr-1]+1;
                
                // Calculate the addition to the former decreasing sequence
                if (decreasingLen > 0) {
                    total += this.calculate(decreasingLen, candies, itr);
                    decreasingLen = 0;
                }
                
                total += candies[itr];
            }
            else {
                ++decreasingLen;
                candies[itr] = 1;
            }
        }
        
        // Calculate the addition to the former decreasing sequence
        if (decreasingLen > 0) {
            total += this.calculate(decreasingLen, candies, N);
            decreasingLen = 0;
        }
        return total;
    }
    
    private int calculate(int len, int[] candies, int itr) {
        int begin = 1+len, sum = 0;
        
        if (candies[itr-1-len] < begin)
            sum += (begin-candies[itr-len-1]);
        
        sum += (1+len)*len/2;
        return sum;
    }
}

以下是C++的题解代码实现。

class Solution {
public:
    int candy(vector<int>& ratings) {
        int N = ratings.size();
        if (N == 0)
            return 0;
        
        int total = 1, decreasing_len = 0;
        int *candies = new int[N];
        candies[0] = 1;
        for (int itr=1; itr<N; ++itr) {
            if (ratings[itr] == ratings[itr-1]) {
                candies[itr] = 1;
                
                // Calculate the addition to the former decreasing sequence
                if (decreasing_len > 0) {
                    total += _Calculate(decreasing_len, candies, itr);
                    decreasing_len = 0;
                }
                
                total += candies[itr];
            }
            else if (ratings[itr] > ratings[itr-1]) {
                candies[itr] = candies[itr-1]+1;
                
                // Calculate the addition to the former decreasing sequence
                if (decreasing_len > 0) {
                    total += _Calculate(decreasing_len, candies, itr);
                    decreasing_len = 0;
                }
    
                total += candies[itr];
            }
            else {
                ++decreasing_len;
                candies[itr] = 1;
            }
        }
        
        // Calculate the addition to the former decreasing sequence
        if (decreasing_len > 0) {
            total += _Calculate(decreasing_len, candies, N);
            decreasing_len = 0;
        }
        return total;
    }

private:
    int _Calculate(int len, int *&candies, int itr) {
        int begin = 1+len, sum = 0;
        
        if (candies[itr-1-len] < begin)
            sum += (begin-candies[itr-len-1]);
        
        sum += (1+len)*len/2;
        return sum;
    }
};

Search

    Table of Contents