LeetCode刷题:贪心算法 [435.无重叠区间] - Java版本

贪心算法:区间问题

只是记录自己的刷题过程,答案参考过多种题解。

如有错误感谢指正!

参考:LeetCode 101: A LeetCode Grinding Guide (C++ Version) 作者:高畅 Chang Gao

题目来源:题库 - 力扣 (LeetCode) 全球极客挚爱的技术成长平台 (leetcode-cn.com)

435.无重叠区间 (Medium)

给定多个区间,计算让这些区间互不重叠所需要移除区间的最少个数。起止相连不算重叠。

A. 贪心思想

  • 选择的区间 结尾越小 ,余留给其它区间的空间就越大,就越能保留更多的区间。

  • 局部最优体现在,优先选右边界小的区间,所以从左向右遍历,留给下一个区间的空间就大一些。

  • 全局最优体现在,选取最多的非交叉区间,即最少的移除区间。

B. 具体实现

  • 按照右边界 从小到大 进行排序。

  • 按照右边界升序排序,就要 从左向右遍历 。因为右边界越小越好,只要右边界越小,留给下一个区间的空间就越大,所以从左向右遍历,优先选右边界小的。(也可按照左边界升序排序,就得从右往左遍历,因为左边界数值越大越好)

  • 每次选择结尾最小且和前一个选择的区间不交叉的区间。即当前组的左边界值大于等于上一组的右边界值,则把end值更新为当前组的右边界值。

  • 记录非交叉区间的个数, 区间个数 =(区间总数 - 非交叉区间的个数)

C. 思考

  • 如何判断区间不重复,采用了 判断边界值大小 的方式,涉及到判断大小最好先排序(升序或降序)。

  • 每次取非交叉区间的时候,都是由右边界最小的来做 分割点 ,这样留给其他区间的范围就越大,总体的数量就能更多。

  • 直接求交叉的区间是复杂的,转而求最大 非交叉 区间个数。

  • 排序后思考如何遍历,不同顺序和不同遍历会出现不同效果。

  • 每个小区间可以看作一个小整体,通过分配小整体的长度每个都最小,使得大整体的数量达到最多,这和分配问题相似。

D. 代码实现

public int eraseOverlapIntervals(int[][] intervals) {
    if (intervals.length < 2) {
        return 0; // 零组或一组区间,直接返回零
    }
    // 按照边界值排序
    Arrays.sort(intervals, new Comparator<int[]>() {
        @Override
        public int compare(int[] o1, int[] o2) {
            if (o1 != o2) {
                return Integer.compare(o1[1], o2[1]);
            } else {
                return Integer.compare(o1[0], o2[0]);
            }
        }
    });
    int end = intervals[0][1]; // 先取第一组的右边界值
    int count = 1; // 初始化非重复区间个数为1
    for (int i = 1; i < intervals.length; i++) { // 从第二组开始升序遍历,寻找不重复的区间
        if (end <= intervals[i][0]) { // 如果当前组的左边界值大于等于上一组的右边界值,则把end值更新为当前组的右边界值
            end = intervals[i][1];
            count++; // 非重复区间个数加一
        }
    }
    return intervals.length - count; // 重复区间数 = 区间总数 - 非重复区间数
}

猜你喜欢

转载自blog.csdn.net/weixin_51909882/article/details/122139769
今日推荐