leetcode-无重叠区间

546 阅读2分钟

「这是我参与2022首次更文挑战的第19天,活动详情查看:2022首次更文挑战」。

题目

给定一个区间的集合,找到需要移除区间的最小数量,使剩余区间互不重叠。
注意:

  1. 可以认为区间的终点总是大于它的起点。
  2. 区间 [1,2] 和 [2,3] 的边界相互“接触”,但没有相互重叠。

示例 1:
输入:[ [1,2], [2,3], [3,4], [1,3] ]
输出:1
解释:移除 [1,3] 后,剩下的区间没有重叠。

示例 2:
输入:[ [1,2], [1,2], [1,2] ]
输出:2
解释:你需要移除两个 [1,2] 来使剩下的区间没有重叠。

示例 3:
输入:[ [1,2], [2,3] ]
输出:0
解释:你不需要移除任何区间,因为它们已经是无重叠的了。

思路

这题之前在另外的OJ上做过,我记得题目是尽量看多个电视节目,给出了每个节目的时间段。
题目要求出的是移除区间的最小数量,我们转换成,求解当前集合最多可以包含多少个互不覆盖的线段,然后用总数再来减,就好理解很多。虽然归类在动态规划里面,但是这题明显是可以贪心的。我们可以证明当前最优解一定包含终点最小的一个线段,全局最优解和局部最优解是重合的。
那怎么证明呢?我们这里可以采取反证法:假设所有的最优解集合不包含原始集包终点最小的线段(xk,yk),那么假设当前最优解集合中,终点最小线段为(xm,ym),终点第二小的线段为(xn,yn),那么此时必然有

ym <= xn 而由于(xk,yk)是原始集包终点最小的线段,所以必然有 yk <= ym 联立上面2个不等式,可以推断出 yk <= ym <= xn 此时,用(xk,yk)去替代(xm,ym),与最优解剩下的线段之间肯定也不会有覆盖,所以假设不成立,至少有一个最优解集合可以包含(xk,yk)。 根据上面的思路,我们可以在原始集合中去掉(xm,ym),然后再去证明至少有一个最优解必然包含还剩余线段中,终点最小的线段,所以,我们只要对原始集合的终点进行从小到大排序,然后依次取不覆盖的线段,那么这些组成的,至少是最优解之一,也可能是唯一最优解。

Java版本代码

class Solution {
    public int eraseOverlapIntervals(int[][] intervals) {
        Arrays.sort(intervals, new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                if (o1[1] == o2[1]) {
                    return o1[0] - o2[0];
                }
                return o1[1] - o2[1];
            }
        });
        int ans = 0;
        int end = intervals[0][1];
        for (int i = 1; i < intervals.length; i++) {
            if (intervals[i][0] >= end) {
                end = intervals[i][1];
            } else {
                ans++;
            }
        }
        return ans;
    }
}