[leetcode] Candy


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?

tag: greedy

虽然说的是贪婪算法,但我第一个想到的是回溯和动态规划。其实我也不清楚三者的明确区别,不管怎样。能做出来就好。

基本思想,先给第一个孩子一块糖,然后尝试给第二个孩子一块糖,如果不满足条件,则向上层回溯。

暂时来不及写代码,先写到这。占个坑,稍后更新。

版本一,采用回溯算法,用一个stack记录当前状态,如果当前层没有满足条件的解,则返回上一层继续深搜。被Leetcode判为内存超出限额MEMORY LIMIT EXCEEDED。晕,考虑用时间换空间中。

//版本一,内存超出限制
class Solution {
public:
    stack<int> data;
    int candy(vector<int> &ratings) {
        /*mark backtracking*/
        _candy(ratings, 0);
        int sum = 0;
        while(data.empty() == false){
            sum += data.top();
            data.pop();
        }
        return sum;
    }
    bool _candy(vector<int> ratings, int start){
        if(start == 0){
            int i = 1;
            bool state;
            while(true){
                data.push(i);
                state = _candy(ratings, 1);
                if(state == true){
                    return true;
                }
                else{
                    data.pop();
                    i++;
                }
            }
        }
        else if(start == ratings.size()){
            return true;
        }
        else{
            int lastCandyNum = data.top();
            int min = -1;
            int max = -1;
            if (ratings[start - 1] > ratings[start]){
                max = lastCandyNum - 1;
                for(int i = 1; i <= max; i++){
                    data.push(i);
                    bool state = _candy(ratings, start + 1);
                    if(state == true){
                        return true;
                    }
                    else{
                        data.pop();
                    }
                }
                return false;
            }
            else{
                min = lastCandyNum + 1;
                while(true){
                    data.push(min);
                    bool state = _candy(ratings, start + 1);
                    if(state == true){
                        return true;
                    }
                    else{
                        data.pop();
                        min++;
                    }
                }
            }
        }
    }
    
};

更新:第二版删掉了stack。因为递归中已经隐性地用到stack了,只要在递归函数中多加一个参数便可实现stack的功能。但是,删掉stack后,仍然是内存超限。看来不能用递归了,尝试优化中。

class Solution {
public:
    int candy(vector<int> &ratings) {
        /*mark backtracking*/
        return _candy(ratings, 0, 0);
    }
    int _candy(vector<int> ratings, int start, int lastCandy){
        if(start == 0){
            int i = 1;
            while(true){
                int sum = _candy(ratings, 1, i);
                if(sum >= 0){
                    return sum + i;
                }
                else{
                    i++;
                }
            }
        }
        else if(start == ratings.size()){
            return 0;
        }
        else{
            int min;
            int max;
            if (ratings[start - 1] > ratings[start]){
                max = lastCandy - 1;
                for(int i = 1; i <= max; i++){
                    int sum = _candy(ratings, start + 1, i);
                    if(sum >= 0){
                        return sum + i;
                    }
                }
                return -1;
            }
            else{
                min = lastCandy + 1;
                while(true){
                    int sum = _candy(ratings, start + 1, min);
                    if(sum >= 0){
                        return sum + min;
                    }
                    else{
                        min++;
                    }
                }
            }
        }
    }
    
};

更新:

版本三:AC

贪心算法,每次尝试放入最小的糖果数。空间复杂度O(1),时间复杂度O(N)。

该题需要分多种情况讨论:

记第i人的rating值为rating[i],给第i人的糖果数为candy[i]。

则:

如果rating[i]处于上升阶段(rating[i – 1] < rating[i] < rating[i + 1]),则candy[i] = candy[i – 1] + 1.

如果rating[i]处于下降阶段(rating[i – 1] >rating[i] > rating[i + 1]),则此时candy[i]不能确定,需要记录下该下降阶段的总长度,最后用calculateDescendSum()一起求出。

如果rating[i]处于极大值,处于极小值,或rating[i]与相邻的某一元素相等,都要分情况讨论。

calcuateDescendSum()需要借助minPeakVal成员变量。因为peak的值必须比它前一个值大,这个最小值记录在minPeakVal中。

感觉,根据一个序列的大小变化来求某一相关的值(比如此题,或何时卖股票收益最大问题等等),都可以用贪心或动态规划来实现。并不一定非要用到stack。以减少空间。

class Solution {
public:
    int minPeakVal = 0; 
    int candy(vector<int> &ratings) {
        /*greedy algorithm... I think it is.*/
        if(ratings.size() == 1){
            return 1;
        }
        else{
            int descendLength = 0;
            int sum = 0;
            int lastCandyNum = 0;
            for(int i = 0; i < ratings.size(); i++){
                if(i == 0){//start
                    if(ratings[i + 1] >= ratings[i]){//ascending or stable
                        lastCandyNum = 1;
                        sum += lastCandyNum;
                    }
                    else{//descending
                        descendLength = 1;
                        minPeakVal = 0;
                    }
                }
                else if(i == ratings.size() - 1){//end
                    if(ratings[i - 1] > ratings[i]){//descending
                        descendLength++;
                        sum += calculateDescendSum(descendLength);
                        descendLength = 0;
                    }
                    else if(ratings[i - 1] < ratings[i]){//ascending
                        lastCandyNum++;
                        sum += lastCandyNum;
                    }
                    else{//stable
                        lastCandyNum = 1;
                        sum += 1;
                    }
                }
                else{//non-boundary case
                    int a = ratings[i - 1];
                    int b = ratings[i];
                    int c = ratings[i + 1];
                    if(b > a && b > c){//peak
                        minPeakVal = lastCandyNum + 1;
                        descendLength = 1;
                    }
                    else if(b < a && b < c){//bottom
                            descendLength++;
                            sum += calculateDescendSum(descendLength);
                            descendLength = 0;
                            lastCandyNum = 1;
                    }
                    else if(a < b && b < c){//ascending
                        lastCandyNum++;
                        sum += lastCandyNum;
                    }
                    else if(a > b && b > c){//descending
                        descendLength++;
                    }
                    else{//stable related scenarios 
                        if(a > b){ //a > b && b == c
                            descendLength++;
                            sum += calculateDescendSum(descendLength);
                            descendLength = 0;
                            lastCandyNum = 1;
                        }
                        else if(a < b){//a < b && b == c
                            lastCandyNum++;
                            sum += lastCandyNum;
                        }
                        else{
                            if(b < c){//a == b && b < c
                                lastCandyNum = 1;
                                sum += lastCandyNum;
                            }
                            else if(b > c){//a == b && b > c
                                minPeakVal = 0;
                                descendLength = 1;
                            }
                            else{//a == b && b == c
                                lastCandyNum = 1;
                                sum += lastCandyNum;
                            }
                        }
                    }
                }
            }
            return sum;
        }
    }
    int calculateDescendSum(int num){
        int sum = 0;
        for(int i = 1; i < num; i++){
            sum += i;
        }
        sum += max(num, minPeakVal);
        return sum;
    }
};

Untitled

 

 

 

 

 

Leave a comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.