资讯专栏INFORMATION COLUMN

算法学习:1-1 贪心算法

vvpale / 2305人阅读

摘要:所谓贪心算法,就是每次操作保证都是局部最优解,以至于最终的结果是全局最优解。分发饼干使用贪心算法,关键在于找到贪心策略,即每一步操作都是局部最优解。

所谓贪心算法,就是每次操作保证都是局部最优解,以至于最终的结果是全局最优解。


455.分发饼干

使用贪心算法,关键在于找到贪心策略,即每一步操作都是局部最优解。

本题贪心策略
由题可知,要尽可能满足多的孩子,只要给胃口值最小的孩子分配能让他满足的最小尺寸的饼干,这就是本题的贪心策略。

class Solution {public:    int findContentChildren(vector<int>& g, vector<int>& s) {        if(g.size()==0||s.size()==0) return 0;  //考虑特殊情况        sort(g.begin(),g.end());  //按升序排序        sort(s.begin(),s.end());        int cnt=0;        int j=0;        for(int i=0;i<g.size();){            if(s[j]>=g[i]){                //假如饼干尺寸大于等于胃口值                ++i;                ++cnt;            }            ++j;            if(j==s.size()) break;        }        return cnt;    }};
class Solution {public:    int findContentChildren(vector<int>& g, vector<int>& s) {        sort(g.begin(),g.end());  //按升序排序        sort(s.begin(),s.end());        int child=0,cookie=0;        while(child<g.size()&&cookie<s.size()){            if(g[child]<=s[cookie])++child;            ++cookie;        }        return child;    }};

135.分发糖果

本题贪心策略
我们可以将相邻的孩子中,评分高的孩子必须获得更多的糖果,这句话拆分为两个规则,分别处理。
左规则:当ratings[i-1] 右规则:当rating[i]>rating[i+1]时,i号学生的糖果数量将比i+1的糖果数量多。

解题思路
1 从左到右走一遍,记录当前点最少需要多少个糖果;
2 从右到左走一遍,记录当前点最少需要多少个糖果;
3 取每个点的最大值,求和就是结果。

class Solution {public:    int candy(vector<int>& ratings) {        int n=ratings.size();        vector<int>vec(n,0);        int left=0;        for(int i=0;i<n;++i){            if(i>0&&ratings[i]>ratings[i-1]){                vec[i]=++left;            }            else{                left=1;                vec[i]=left;            }        }        int right=0,ret=0;        for(int i=n-1;i>=0;--i){            if(i<n-1&&ratings[i]>ratings[i+1]){                ++right;            }else{                right=1;            }            ret+=max(right,vec[i]);        }        return ret;    }};

452.用最少数量的箭引爆气球

本题贪心策略
先将所有气球,右界按升序排列,那么每次射击右界最小的那个气球就可以了。左界在前面那个右界的右边的气球不会爆,其他都已经爆了,然后再选择没有爆的气球中右界最小的那个。以此类推,就是解决这个问题的最优解。

class Solution {public:    int findMinArrowShots(vector<vector<int>>& points) {        int n=points.size();        //按右界由小到大排列        sort(points.begin(),points.end(),        [](const vector<int>&a,const vector<int>& b){            return a[1]<b[1];        });        int cnt=1;        int prev=points[0][1];        for(int i=1;i<n;++i){            if(points[i][0]>prev){                ++cnt;                prev=points[i][1];            }        }        return cnt;    }};

763.划分字母区间

本题贪心策略
记录所有字符的第一次出现时间first,和最后一次出现时间end;
按左界从小到大排序;
left记录当前片段的左界;
pos记录当前片段的右界;

left设置为第一个区间的左界,肯定是0;
pos设置为第一个区间的右界;
进入循环,从第一个区间的下一个区间开始;
假如下一个区间的左界小于pos,那么说明这应该被分在一个片段里,因此更新pos为当前pos和这个区间右界的较大值;
假如下一个区间的右界大于pos,那么说明[left,pos]是一个片段,记录片段长度;更新left为当前区间的左界,pos为当前区间的右界。

class Solution {public:    vector<int> partitionLabels(string s) {        int n = s.size();        vector<vector<int>>position(26,vector<int>(2,-1));        unordered_map<char, int>ch_cnt;        //position记录字符第一次和最后一次出现的下标        for (int i = 0;i < n;++i) {            if (ch_cnt[s[i]] == 0)                position[s[i] - "a"][0] = i;            position[s[i] - "a"][1] = i;            ++ch_cnt[s[i]];        }        //排序,将每个字符出现的区间排序,按左界从小到大排序        sort(position.begin(), position.end(),            [](const vector<int>& a, const vector<int>& b) {                return a[0] < b[0];            });        //没出现过的不管        int i = 0;        while (i < 26 && position[i][0] == -1)            ++i;        vector<int>ret;  //存放结果        int left = 0;        int pos = position[i][1]; //记录右界        for (i = i + 1;i < 26;++i) {            if (i == 25) {                if(position[i][0]>pos){                    ret.push_back(pos - left + 1);                    ret.push_back(position[i][1]-position[i][0]+1);                    break;                }else{                    pos = max(position[i][1], pos);                    ret.push_back(pos-left+1);                }              }            if (position[i][0] < pos) {                //假如有重合部分                //更新pos,选取较大的                pos = max(position[i][1], pos);            }            else {                //没有重合部分                ret.push_back(pos - left + 1);                left = position[i][0];                pos = position[i][1];            }        }        return ret;    }};

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/121503.html

相关文章

  • 【LeetCode】贪心算法--买卖股票的最佳时机 II(122)

    摘要:贪心算法每一步必须满足一下条件可行的即它必须满足问题的约束。四题目分析贪心算法,总是做出在当前看来是最好的选择,不从整体最优上加以考虑,也就是说,只关心当前最优解,按照贪心策略,不关心以后,我们只关心当前利益。 一、写在前面 为什么要在LeetCode刷题?大家都知道不管是校招还是社招算法题是必考题,而这一部分恰巧是大多数人的短板,所以刷题首先是为了提高自身的编程能力,能够在算法面试中...

    xbynet 评论0 收藏0
  • “365算法每日学计划”:03打卡-贪心算法

    摘要:贪心算法一基本概念所谓贪心算法是指,在对问题求解时,总是做出在当前看来是最好的选择。实际上,贪心算法适用的情况很少。值得注意的是,贪心算法并不是完全不可以使用,贪心策略一旦经过证明成立后,它就是一种高效的算法。 自从开始做公众号开始,就一直在思考,怎么把算法的训练做好,因为思海同学在算法这方面的掌握确实还不够。因此,我现在想做一个365算法每日学计划。 计划的主要目的: 1、想通过这...

    isaced 评论0 收藏0
  • 【LeetCode】贪心算法--划分字母区间(763)

    摘要:写在前面今天这篇文章是贪心算法系列的第三篇划分字母区间。前文回顾贪心算法分发糖果刷题汇总汇总贴今日题目字符串由小写字母组成。返回一个表示每个字符串片段的长度的列表。示例输入输出解释划分结果为。每个字母最多出现在一个片段中。 写在前面 今天这篇文章是贪心算法系列的第三篇--划分字母区间。 前文回顾: 【LeetCode】贪心算法--分发糖果(135) 刷题汇总: 【LeetCode】汇总...

    honhon 评论0 收藏0
  • 贪心算法

    摘要:贪心算法与动态规划算法的差异贪心算法和动态规划算法都要求问题具有最优子结构性质,这是类算法的一个共同点。 贪心算法的基本要素对于一个具体的问题,怎么知道是否可用贪心算法解此问题,以及能否得到问题的最优解呢?这个问题很难给予肯定的回答。但是,从许多可以用贪心算法求解的问题中看到这类问题一般具有2个重要的性质:贪心选择性质和最优子结构性质。 1、贪心选择性质所谓贪心选择性质是指所求问题的整...

    missonce 评论0 收藏0
  • 基本算法思想:递归+分治+动态规划+贪心+回溯+分支限界

    摘要:代码实现见下面评论对应代码动态规划基本思想和分治法基本思想有共同的地方,不同的是子问题往往不是独立的,有事母问题要借助子问题的解来判断,因此把已经计算好的问题记录在表格中,后续如果需要查询一下,可以避免重复计算,这是动态规划的基本思想。 作者:心叶时间:2018-05-01 19:28 本文对应github地址:https://github.com/yelloxing/... 以上实现...

    EscapedDog 评论0 收藏0

发表评论

0条评论

vvpale

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<