LeetCode435. 无重叠区间

方法1:动态规划。类似于最长上升子序列问题。 时间复杂度为O(n^2), 空间复杂度:O(n)

    先将所有的 n 个区间按照左端点从小到大进行排序,随后使用动态规划的方法求出区间数量的最大值。

☆☆☆☆方法2【最优解】:贪心算法。时间复杂度:O(nlogn), 空间复杂度:O(logn)

    每次选择中,前一个区间的结尾越小,后面越有可能容纳更多区间。

    两种思路,可以对区间尾进行排序,也可以对区间头排序。

代码1:

class Solution {
    public int eraseOverlapIntervals(int[][] intervals) {
        if (intervals.length == 0) {
            return 0;
        }
        // 对每个区间排序,以区间头的大小为参考
//        Arrays.sort(intervals, new Comparator<int[]>() {
//            @Override
//            public int compare(int[] o1, int[] o2) {
//                return o1[0] - o2[0]; // 如果返回正数,说明o1[0] > o2[0],不符合升序,正数类比为true,表示需要调整顺序。
//            }
//        });
        Arrays.sort(intervals, (o1, o2) -> o1[0] - o2[0]);
        // 状态的定义: dp[i]表示 从区间0开始,以区间i为最后一个区间,可以选出的区间数量的最大值。
        //      初始化:把区间i单独拿出来就是1个互不重叠的区间,因此初始化为1
        int[] dp = new int[intervals.length];
        Arrays.fill(dp, 1);
        int res = 1;
        for (int i = 1; i < intervals.length; i++) {
            for (int j = 0; j < i; j++) {
                // 说明区间i可以跟在区间i后面
                if (intervals[i][0] >= intervals[j][1]) {
                    dp[i] = Math.max(dp[i], 1 + dp[j]);
                }
            }
            res = Math.max(res, dp[i]); // 所有dp[i]里取最大的
        }
        return intervals.length - res;
    }
}

代码2:

class Solution {
    public int eraseOverlapIntervals(int[][] intervals) {
        if (intervals.length == 0) {
            return 0;
        }
        /**
         * 方法1:按照区间头来排序,记录移除的次数
         *      如果遇到覆盖,那么就需要删除一个区间,因为需要尽可能不与后面的区间产生重叠,
         *      应该让现有区间越短越好,因此需要移除尾部较大的,保留区间结尾较小的。
         */
        Arrays.sort(intervals, (o1, o2) -> o1[0] - o2[0]);
        int count = 0; // 移除的次数
        int pre = 0; // 前一个区间的索引
        for (int i = 1; i < intervals.length; i++) {
            // 如果发生重叠
            if (intervals[i][0] < intervals[pre][1]) {
                count ++;
                // 更新保留的区间索引,保留尾部较小的那个
                pre = intervals[pre][1] < intervals[i][1] ? pre : i;
            }else {
                pre = i;
            }
        }
        return count;
        /**
         * 方法2:按照区间尾来排序,记录选择区间的个数
         *      每次选择结尾最早的,且和前一个区间不重叠的区间
         */
        /*
        Arrays.sort(intervals, (o1, o2) -> o1[1] - o2[1]);
        int res = 1; // 选择区间的个数
        int pre = 0;
        for (int i = 1; i < intervals.length; i++) {
            if (intervals[i][0] >= intervals[pre][1]) {
                res ++;
                pre = i;
            }
        }
        return intervals.length - res;
        */
    }
}

【知识点补充】如何自定义排序规则为 升序 还是 降序

  设o1表示位于前面的元素,o2表示后面的元素。

  如果想升序,对于o1-o2,如果结果为负数,说明o1 < o2,符合升序要求,负数类比为false,表示不需要调整顺序。

               如果结果为正数,说明o1 > o2,不符合升序要求,正数类比为true,表示需要调整顺序。

  如果想降序,对于o2-o1,如果结果为负数,说明o2 < o1,符合降序要求,负数类比为false,表示不需要调整顺序。

               如果结果为正数,说明o2 > o1,不符合降序要求,正数类比为true,表示需要调整顺序。

原文地址:https://www.cnblogs.com/HuangYJ/p/14232874.html