参考 labuladong的算法小抄:贪心算法之区间调度问题 ,摘自原文的斜体标出,也可以看作是转载吧。
什么是贪心算法? 贪心算法可以认为是动态规划算法的一个特例,相比动态规划,使用贪心算法需要满足更多的条件(贪心选择性质),但是效率比动态规划要高。 比如说一个算法问题使用暴力解法需要指数级时间,如果能使用动态规划消除重叠子问题,就可以降到多项式级别的时间,如果满足贪心选择性质,那么可以进一步降低时间复杂度,达到线性级别的。 什么是贪心选择性质呢,简单说就是:每一步都做出一个局部最优的选择,最终的结果就是全局最优。注意哦,这是一种特殊性质,其实只有一部分问题拥有这个性质。 比如你面前放着 100 张人民币,你只能拿十张,怎么才能拿最多的面额?显然每次选择剩下钞票中面值最大的一张,最后你的选择一定是最优的。 然而,大部分问题明显不具有贪心选择性质。比如打斗地主,对手出对儿三,按照贪心策略,你应该出尽可能小的牌刚好压制住对方,但现实情况我们甚至可能会出王炸。这种情况就不能用贪心算法,而得使用动态规划解决。
1 2 3 4 5 描述:给定一个区间的集合,找到需要移除区间的最小数量,使剩余区间互不重叠。 输入: [ [1,2], [2,3], [3,4], [1,3] ] 输出: 1 解释: 移除 [1,3] 后,剩下的区间没有重叠。
解题思路:
处理数据,将每组按数据的最早结束 进行从小到大排序
从区间集合 intvs 中选择一个区间 x,这个 x 是在当前所有区间中结束最早的(end 最小)。
把所有与 x 区间相交的区间从区间集合 intvs 中删除。
重复步骤 1 和 2,直到 intvs 为空为止。之前选出的那些 x 就是最大不相交子集。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public int EraseOverlapIntervals (int [][] intervals ){ if (intervals.Length == 0 ) return 0 ; Array.Sort(intervals, (a, b) => { if (a[1 ] > b[1 ]) return 1 ; else if (a[1 ] < b[1 ]) return -1 ; return 0 ; }); int result = 1 ; int x_end = intervals[0 ][1 ]; foreach (var item in intervals) { if (item[0 ] >= x_end) { ++result; x_end = item[1 ]; } } return intervals.Length- result; }
1 2 3 4 5 6 7 8 9 10 描述: 在二维空间中有许多球形的气球。对于每个气球,提供的输入是水平方向上,气球直径的开始和结束坐标。由于它是水平的,所以纵坐标并不重要,因此只要知道开始和结束的横坐标就足够了。开始坐标总是小于结束坐标。 一支弓箭可以沿着 x 轴从不同点完全垂直地射出。在坐标 x 处射出一支箭,若有一个气球的直径的开始和结束坐标为 xstart,xend, 且满足 xstart ≤ x ≤ xend,则该气球会被引爆。可以射出的弓箭的数量没有限制。 弓箭一旦被射出之后,可以无限地前进。我们想找到使得所有气球全部被引爆,所需的弓箭的最小数量。 给你一个数组 points ,其中 points [i] = [xstart,xend] ,返回引爆所有气球所必须射出的最小弓箭数。 输入:points = [[10,16],[2,8],[1,6],[7,12]] 输出:2 解释:对于该样例,x = 6 可以射爆 [2,8],[1,6] 两个气球,以及 x = 11 射爆另外两个气球
解题思路与上面相似,只是这里要计算的是用最少的箭打破所有气球,对于那些有重叠部分的只需要1箭即可,具体代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public int FindMinArrowShots (int [][] points ){ if (points.Length == 0 ) return 0 ; Array.Sort(points, (a, b) => { if (a[1 ] > b[1 ]) return 1 ; else if (a[1 ] < b[1 ]) return -1 ; return 0 ; }); int result = 1 ; int x_end = points[0 ][1 ]; foreach (var item in points) { if (item[0 ] <= x_end) continue ; ++result; x_end = item[1 ]; } return result; }