码迷,mamicode.com
首页 > 其他好文 > 详细

[LeetCode] Candy

时间:2015-03-28 17:18:15      阅读:150      评论:0      收藏:0      [点我收藏+]

标签:c++   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?

解题思路:

贪心算法,能少给就少给。最初的想法是用一个数组记录每个小孩应该给的糖果数,从左往右依次扫描,若当前小孩比左边的小孩得分高,则比左边的小孩多拿一个糖,若得分低(或相等),则只分配一个糖。但是要考虑到若左边的小孩若比自己得分高,但只有一个糖,当前小孩若比其分配的少,那么只能分配一个糖了。故可以调整左边的小孩分的糖数。维持左边已经分配的小孩的糖果数目。于是版本一的代码如下:

class Solution {
public:
    int candy(vector<int> &ratings) {
        int number = ratings.size();
        if(number == 0){
            return 0;
        }
        int* d = new int[number];   //存储前i个已经分配的糖的数目
        
        d[0] = 1;   //贪心,给第一个小孩先给一个糖
        
        for (int i=1; i<number; i++){
            if(ratings[i]<ratings[i-1]){    //当前小孩得分比左边的少,只给他一个糖,但是得修正,防止左边的已经是一个糖了
                d[i] = 1;
                for(int j=i-1; j>=0; j--){
                    if(d[j] == d[j+1] && ratings[j]>ratings[j + 1]){    //左边的小孩得分高,却只得到相同的糖,他不干了,得给他加糖
                        d[j] = d[j]+1;
                    }else{
                        break;
                    }
                }
            }else if(ratings[i] == ratings[i-1]){   //当前小孩得分与左边的相同,给他左边小孩同样多的糖
                d[i] = 1;
            }else{          //当前小孩得分比左边多,给他比左边多一个糖
                d[i] = d[i-1] + 1;
            }
        }
        
        int result = 0;
        for(int i=0; i<number; i++){
            result += d[i];
        }
        delete[] d;
        return result;
    }
};
但是出现了执行时间超时的情况。因为该方法的时间复杂度为O(n2),特别是当小孩得分是逆序的情况,执行的最慢。

于是想其他办法。上网查了一下,终于得知,其实可以左右两边分别扫描,从左往右扫描,只需记录每个小孩相对于左边小孩所获得的糖果。从右往左扫描,只需记录每个小孩相对于右边小孩获得的糖果数,然后两个数组对应元素取较大值即为结果。下面是代码:

class Solution {
public:
    int candy(vector<int> &ratings) {
        int number = ratings.size();
        if(number == 0){
            return 0;
        }
        int* d = new int[number];   //存储前i个已经分配的糖的数目
        
        //两边扫,取较大的
        
        //从左往右扫
        d[0] = 1;   //贪心,第一个小孩先给一个糖
        for (int i=1; i<number; i++){
            if(ratings[i]<=ratings[i-1]){    //当前小孩得分比左边的少,只给他一个糖
                d[i] = 1;
            }else{          //当前小孩得分比左边多,给他比左边多一个糖
                d[i] = d[i-1] + 1;
            }
        }
        
        //从右往左扫
        int* r = new int[number];
        r[number - 1] = 1;
        for(int i = number-2; i>=0; i--){
            if(ratings[i]<=ratings[i+1]){    //当前小孩得分比右边的少,只给他一个糖
                r[i] = 1;
            }else{          //当前小孩得分比右边多,给他比右边多一个糖
                r[i] = r[i+1] + 1;
            }
        }
        
        int result = 0;
        for(int i=0; i<number; i++){
            result += (d[i]>r[i]?d[i]:r[i]);
        }
        delete[] r;
        delete[] d;
        return result;
    }
};
上述代码中,只扫描了两遍,所以时间复杂度为O(n),用的空间为2*n。可以优化一下代码,使得用的空间为n,如下所示:

class Solution {
public:
    int candy(vector<int> &ratings) {
        int number = ratings.size();
        if(number == 0){
            return 0;
        }
        int* d = new int[number];   //存储前i个已经分配的糖的数目
        
        //两边扫,取较大的
        
        //从左往右扫
        d[0] = 1;   //贪心,第一个小孩先给一个糖
        for (int i=1; i<number; i++){
            if(ratings[i]<=ratings[i-1]){    //当前小孩得分比左边的少,只给他一个糖
                d[i] = 1;
            }else{          //当前小孩得分比左边多,给他比左边多一个糖
                d[i] = d[i-1] + 1;
            }
        }
        
        int result = 0;
        int lastCandyNumber = 1;    //从右往左扫面上一个孩子的糖果数目
        result += (d[number-1]>lastCandyNumber?d[number-1]:lastCandyNumber);
        //从右往左扫
        for(int i = number-2; i>=0; i--){
            if(ratings[i]<=ratings[i+1]){    //当前小孩得分比右边的少,只给他一个糖
                lastCandyNumber = 1;
            }else{          //当前小孩得分比右边多,给他比右边多一个糖
                lastCandyNumber++;
            }
            result += (d[i]>lastCandyNumber?d[i]:lastCandyNumber);
        }
        
        delete[] d;
        return result;
    }
};
相关的若与左右两边有关的问题,都可以考虑两边扫的方法。

[LeetCode] Candy

标签:c++   leetcode   

原文地址:http://blog.csdn.net/kangrydotnet/article/details/44702593

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!