为了账号安全,请及时绑定邮箱和手机立即绑定

leetcode题解(贪心算法)

leetcode题解(贪心算法)

文章地址:吴军旗---原文地址

定义

贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。 也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解。

通常贪心算法的代码会非常短而且思路也非常的简单,但贪心算法真正的难点在于确定我们当前的问题确实可以使用贪心算法。

leetcode 455. 分发饼干


https://img1.sycdn.imooc.com//5b45b3760001ee7609580655.jpg


解题思路

这是一道简单的贪心算法问题。我们尝试将最大的饼干给最贪心的小朋友,如果可以满足最贪心的小朋友,我们留给下一个次贪心的小朋友的饼干也是当前看来最大的。如果最大的饼干都无法满足最贪心的小朋友,那么就表明无法满足这个小朋友。

    class Solution {     public:         int findContentChildren(vector<int>& g, vector<int>& s) {                  sort(g.begin(), g.end(), greater<int>());             sort(s.begin(), s.end(), greater<int>());                  int gi = 0, si = 0;             int res = 0;             while( gi < g.size() && si < s.size() ){                      if( s[si] >= g[gi] ){                     res ++;                     si ++;                     gi ++;                 } else {                     gi ++;                 }             }                  return res;         }     };      复制代码

贪心算法通常和排序是分不开的,如果题目给出数组没有排序,我们就需要自己进行排序。


贪心算法与动态规划的关系


https://img1.sycdn.imooc.com//5b45b3860001706f09590663.jpg


动态规划方法

解题思路

我们可以首先想一下暴力解法:找出所有子区间的组合,之后判断它是否重叠。O((2^n)*n)
先要排序,方便判断不重叠。

这道题很像最长上升子序列我们首先使用动态规划解决这道题:

实现

              // Definition for an interval.     struct Interval {         int start;         int end;         Interval() : start(0), end(0) {}         Interval(int s, int e) : start(s), end(e) {}     };          bool compare(const Interval &a, const Interval &b){              if( a.start != b.start )             return a.start < b.start;         return a.end < b.end;     }          // 动态规划     class Solution {     public:         int eraseOverlapIntervals(vector<Interval>& intervals) {                  if( intervals.size() == 0 ) {                 return 0;             }                  sort(intervals.begin(), intervals.end(), compare);                  // memo[i]表示以intervals[i]为结尾的区间能构成的最长不重叠区间序列             vector<int> memo( intervals.size() , 1 );             for( int i = 1 ; i < intervals.size() ; i ++ ) {                 // memo[i]                 for( int j = 0 ; j < i ; j ++ ) {                     if( intervals[i].start >= intervals[j].end ) {                         memo[i] = max( memo[i] , 1 + memo[j] );                     }                 }             }                  int res = 0;             for( int i = 0 ; i < memo.size() ; i ++ ) {                 res = max( res , memo[i] );             }                  return intervals.size() - res;         }     };      复制代码

贪心算法解决

解题思路

注意:每次选择中,每个区间的结尾很重要。
结尾越小,留给了后面越大的空间,后面越有可能容纳更多区间。
贪心算法:按照区间的结尾排序,每次选择结尾最早的,且和前一个区间不重叠的区间。

实现

     // Definition for an interval.     struct Interval {         int start;         int end;         Interval() : start(0), end(0) {}         Interval(int s, int e) : start(s), end(e) {}     };          bool compare(const Interval &a, const Interval &b){         if( a.end != b.end )             return a.end < b.end;         return a.start < b.start;     }          // 贪心算法     class Solution {     public:         int eraseOverlapIntervals(vector<Interval>& intervals) {                  if( intervals.size() == 0 ) {                 return 0;             }                  sort(intervals.begin(), intervals.end(), compare);                  int res = 1;             int pre = 0;             for( int i = 1 ; i < intervals.size() ; i ++ ) {                 if( intervals[i].start >= intervals[pre].end ){                     res ++;                     pre = i;                 }             }                  return intervals.size() -  res;         }     };      复制代码

贪心选择性质的证明

  • 贪心算法为A;最优算法为O;发现A完全能替代O,且不影响求出最优解。

  • 如果无法使用贪心算法,举出反例即可


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消