LeetCode 435:无重叠区间 (贪心)

红太狼 2024-04-07 13:20 188阅读 0赞

链接

题目
在这里插入图片描述

方法一:贪心

什么是贪心算法 ?
贪心算法可以认为是动态规划算法的一个特例,相比动态规划,使用贪心算法需要满足更多的条件(贪心选择性质),但是效率比动态规划要高。

比如说一个算法问题使用暴力解法需要指数级时间,如果能使用动态规划消除重叠子问题,就可以降到多项式级别的时间,如果满足贪心选择性质,那么可以进一步降低时间复杂度,达到线性级别的;

什么是贪心选择性质?
简单说就是:每一步都做出一个局部最优的选择,最终的结果就是全局最优

注意:这是一种特殊性质,其实只有一部分问题拥有这个性质;

比如你面前放着 100 张人民币,你只能拿十张,怎么才能拿最多的面额?显然每次选择剩下钞票中面值最大的一张,最后你的选择一定是最优的;

思路:

  1. 先以区间 end 为基准从小到大排序,然后从区间集合 intvs 中选择一个区间 x,这个 x 是在当前所有区间中结束最早的(end 最小)。
  2. 如果下一个区间的start >= 上一个区间的x_end,才不重叠,可以放入x,count++, !
  3. 重复步骤 1 和 2,直到 intvs 为空为止,不重叠的就是所有x;

【排完序以后】,所有与 x 相交的区间必然会与 x 的 end 相交如果一个区间不想与 x 的 end 相交,它的 start 必须要 >= x 的 end !
在这里插入图片描述

基本代码
每一轮两个变量: x_end和下一个区间k的start ; 结尾更新 x_end即为当前k的end;

  1. public int intervalSchedule(int[][] intvs) {
  2. if (intvs.length == 0) return 0;
  3. // 按 end 升序排序
  4. Arrays.sort(intvs, new Comparator<int[]>() {
  5. public int compare(int[] a, int[] b) {
  6. return a[1] - b[1];
  7. }
  8. });
  9. // 至少有一个区间不相交
  10. int count = 1;
  11. // 排序后,第一个区间就是 x
  12. int x_end = intvs[0][1];
  13. for (int[] interval : intvs) {
  14. int start = interval[0];
  15. if (start >= x_end) {
  16. // 找到下一个选择的区间了
  17. count++;
  18. x_end = interval[1];
  19. }
  20. }
  21. return count;
  22. }

注意: 使用 for-each 循环,第一次会判断第一个区间的end和自己的start,由于不满足不重叠条件,所以count不会++;

即只统计不重叠的情况!最简单 !
针对此题,先算出不重叠的x个数,再用总的个数减去x个数即为要删除的!

Java实现:

  1. class Solution {
  2. public int eraseOverlapIntervals(int[][] intervals) {
  3. // 贪心
  4. // 排序
  5. Arrays.sort(intervals,new Comparator<int[]>(){
  6. @Override
  7. public int compare(int[] a,int[] b){
  8. //比较的是intervals的元素即一维数组
  9. return a[1]-b[1]; // 以end来排序
  10. }
  11. });
  12. //
  13. int n=intervals.length;
  14. int count=1; // 不重叠的区间 x个数
  15. int x_end=intervals[0][1]; // 第一个区间的end
  16. for(int i=1;i<n;i++){
  17. // 逐个判断
  18. int start=intervals[i][0]; // x_end的下一个区间的start
  19. if(start >= x_end){
  20. // 下一个start >=上一个的end,才不重叠,放入x
  21. count++;
  22. x_end=intervals[i][1];
  23. }
  24. }
  25. return n-count; // 总的减去不重叠的x的个数即要删除的
  26. }
  27. }

注意: 这里用for 循环从1开始,跳过了第一个,从0开始也可以,自己的 start一定小于end ,所以会跳过执行下一次循环,不影响结果;

或使用for-each

  1. class Solution {
  2. public int eraseOverlapIntervals(int[][] intervals) {
  3. // 贪心
  4. // 排序
  5. Arrays.sort(intervals,new Comparator<int[]>(){
  6. @Override
  7. public int compare(int[] a,int[] b){
  8. //比较的是intervals的元素即一维数组
  9. return a[1]-b[1]; // 以end来排序
  10. }
  11. });
  12. //
  13. int n=intervals.length;
  14. int count=1; // 不重叠的区间 x个数
  15. int x_end=intervals[0][1]; // 第一个区间的end
  16. for(int[] k:intervals){
  17. // 逐个判断
  18. int start=k[0]; // x_end的下一个区间的start
  19. if(start >= x_end){
  20. // 下一个start >=上一个的end,才不重叠,放入x
  21. count++;
  22. x_end=k[1];
  23. }
  24. }
  25. return n-count; //
  26. }
  27. }

发表评论

表情:
评论列表 (有 0 条评论,188人围观)

还没有评论,来说两句吧...

相关阅读

    相关 leetcode 435.重叠区间(java 贪心

    d先根据各区间尾节点进行从小到大排序,然后依次判断下一个区间的开始节点是否大于上一个区间的结束节点,若大于,可留住,若是小于,则发生重叠,删去。这样就能保证尾节点小的留住,为后

    相关 leetcode435重叠空间

    给定一个区间的集合,找到需要移除区间的最小数量,使剩余区间互不重叠。 注意: 可以认为区间的终点总是大于它的起点。 区间 \[1,2\] 和 \[2,3\] 的边界相互