【LeetCode-435】435. 无重叠区间 (区间调度问题)

区间调度问题

参考

解决一个很经典的贪心算法问题 Interval Scheduling(区间调度问题)。给你很多形如 [start, end] 的闭区间,请你设计一个算法,算出这些区间中最多有几个互不相交的区间

int intervalSchedule(int[][] intvs) {}
举个例子,intvs = [[1,3], [2,4], [3,6]],这些区间最多有 2 个区间互不相交,即 [[1,3], [3,6]],你的算法应该返回 2。注意边界相同并不算相交。

这个问题在生活中的应用广泛,比如你今天有好几个活动,每个活动都可以用区间 [start, end] 表示开始和结束的时间,请问你今天最多能参加几个活动呢?显然你一个人不能同时参加两个活动,所以说这个问题就是求这些时间区间的最大不相交子集

435. 无重叠区间

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

注意:

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

【LeetCode-435】435. 无重叠区间 (区间调度问题)_第1张图片
【LeetCode-435】435. 无重叠区间 (区间调度问题)_第2张图片

解题方法:贪心法

思路:

可以分为以下三步:

  • 从区间集合 intvs 中选择一个区间 x,这个 x 是在当前所有区间中结束最早的(end 最小)。
  • 把所有与 x 区间相交的区间从区间集合 intvs 中删除。
  • 重复步骤 1 和 2,直到 intvs 为空为止。之前选出的那些 x 就是最大不相交子集。

把这个思路实现成算法的话,可以按每个区间的 end 数值升序排序,因为这样处理之后实现步骤 1 和步骤 2 都方便很多:

class Solution {
    public int eraseOverlapIntervals(int[][] intervals) {
        if(intervals.length == 0) {
            return 0;
        }
        // n - 最多有多少个区间不重叠 = 至少需要去除几个区间(需要移除区间的最小数量)
        return intervals.length - intervalSchedule(intervals);
    }

    //求最多有几个区间不会重叠
    public int intervalSchedule(int[][] intervals) {
        if(intervals.length == 0) {
            return 0;
        }
            
        // 按end升序排列
        Arrays.sort(intervals, new Comparator<int []>(){
            public int compare(int[] a, int[] b) {
                return a[1] - b[1];
            }
        });

        // 至少有一个区间不相交
        int count = 1;
        // 排序后,第一个区间就是x
        int x_end = intervals[0][1];
        for(int[] interval : intervals) {
            int start = interval[0];
            if(start >= x_end) {
                // 找到下一个选择的区间了
                count++;
                x_end = interval[1];
            }
        }   
        return count;
    }
}

你可能感兴趣的:(LeetCode)