分发糖果、根据身高重建队列——贪心算法


刚放假回家,做了两道贪心题,记录一下。

一、分发糖果

原题目:
n 个孩子站成一排。给你一个整数数组 ratings 表示每个孩子的评分。
你需要按照以下要求,给这些孩子分发糖果:
每个孩子至少分配到 1 个糖果。
相邻两个孩子评分更高的孩子会获得更多的糖果。
请你给每个孩子分发糖果,计算并返回需要准备的 最少糖果数目 。

解答过程:
本题可以使用贪心算法求解,题目中两个要求:每个孩子的评分若大于其左边孩子,则比左孩子分到更多的糖果,若大于其右边孩子,则比右孩子分到
更多的糖果。因此,可以使用贪心算法进行两边遍历。第一遍遍历时要保证每个孩子与其左孩子糖果的关系,第二遍遍历要保证每个孩子与其右孩子糖果的关系。
第一遍遍历:

for(int i=1;i<ratings.size();++i)
        {
            //贪心:保证比左边孩子糖果多
            if(ratings[i]>ratings[i-1])
                candyVec.push_back(candyVec.back()+1);
            else
                candyVec.push_back(1);
        }

第二遍遍历:这里必须从后往前遍历,因为在保证与右孩子的糖果的关系过程中,要使用到右边遍历的结果。如果从前往后遍历,右孩子还是第一次遍历的值。

for(int i=ratings.size()-2;i>=0;--i)
        {
            //贪心:保证比右边孩子糖果多
            if(ratings[i]>ratings[i+1])
                candyVec[i]=max(candyVec[i+1]+1,candyVec[i]);
        }

完整代码:

class Solution {
private:
    vector<int>candyVec;
public:
    int candy(vector<int>& ratings) {
        candyVec.push_back(1);
        for(int i=1;i<ratings.size();++i)
        {
            //贪心:保证比左边孩子糖果多
            if(ratings[i]>ratings[i-1])
                candyVec.push_back(candyVec.back()+1);
            else
                candyVec.push_back(1);
        }
        for(int i=ratings.size()-2;i>=0;--i)
        {
            //贪心:保证比右边孩子糖果多
            if(ratings[i]>ratings[i+1])
                candyVec[i]=max(candyVec[i+1]+1,candyVec[i]);
        }
        int result=0;
        for(int i=0;i<candyVec.size();++i)
            result+=candyVec[i];
        return result;
    }
};

二、根据身高重建队列

原题目:
假设有打乱顺序的一群人站成一个队列,数组 people 表示队列中一些人的属性(不一定按顺序)。每个 people[i] = [hi, ki] 表示第 i 个人的身高为 hi ,前面 正好 有 ki 个身高大于或等于 hi 的人。

请你重新构造并返回输入数组 people 所表示的队列。返回的队列应该格式化为数组 queue ,其中 queue[j] = [hj, kj] 是队列中第 j 个人的属性(queue[0] 是排在队列前面的人)。

这个题目与分发糖果有类似之处,分发糖果是要求左右孩子,而这个题是要求身高和个数。因此,我们在解答这类题目时简单的方法就是要先满足其中一个条件然后再满足另一个条件。
本题如果先对k进行排列,那么排序之后h和k都不满足要求;因此先对身高进行排序,可以从低到高或者从高到低。
从低到高进行排列:

class Solution {
     static bool cmp(vector<int>&a,vector<int>&b)
        {
            if(a[0]>b[0]||(a[0]==b[0]&&a[1]<b[1]))
                return true;
            else
                return false;
        }
public:
    vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {
       sort(people.begin(),people.end(),cmp);
       list<vector<int>>ret;
       //再依据k进行排序
       int k=0;
        for(int i=0;i<people.size();++i)
        {
        		//k代表people[i]实际在第k个位置,如果存在k相同的身高,则在第k个位置直接插入(身高已排好序)
            k=people[i][1];
            auto iter=ret.begin();
            while(k--)
            {
                ++iter;
            }
            ret.insert(iter,people[i]);
        }
        return vector<vector<int>>(ret.begin(),ret.end());
    }
};

这里我第一次编写cmp函数时没有声明为static的,而导致了如下错误:
reference to non-static member function must be called!
问题在于类中non-static函数都有一个隐式的参数this指针,而sort函数中调用cmp函数时输入了两个需要比较的实参,因此出现了参数不匹配的现象。(静态成员为所有对象共享,是独一份的,在对象创建之前就存在的。)

从高到低进行排列:

class Solution {
     static bool cmp(vector<int>&a,vector<int>&b)
        {
            if(a[0]<b[0]||(a[0]==b[0]&&a[1]>b[1]))
                return true;
            else
                return false;
        }
public:
    vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {
       sort(people.begin(),people.end(),cmp);
       int n=people.size();
       vector<vector<int>>ret(n);
       for(int i=0;i<n;++i)
       {
           int position=people[i][1]+1;
           for(int j=0;j<n;++j)
           {
               if(ret[j].empty())
               {
                   --position;
                   if(!position)
                   {
                       ret[j]=people[i];
                       break;
                   }
               }
           }
       }
       return ret;
    }
};

在身高相同时我们要按照k降序的方式进行排列,原因如下:
(4,4)、(5、0)、(5,2)、(6,1)、(7,0)、(7,1)
归位时:
()、()、()、()、(4,4)、()
(5,0)、()、()、()、(4,4)、()
(5,0)、()、()、(5,2)、(4,4)、()
此时就已经出现了错误。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值