【LeetCode】【贪心】435. 无重叠区间

【贪心】435. 无重叠区间

知识点:贪心;

题目描述

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

注意:

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

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

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

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

解法一:贪心

贪心其实是动态规划的一个特例,贪心算法需要满足更多的条件,但是只要满足条件,贪心算法要更快;

贪心是什么呢,简单来说就是每一步我们都选择在此时的最优解,也就是当前的局部最优解,最终的结果就是全局最优了。它所做的只是当前来看最好的选择,而并不管全局。比如说如果想从一堆人民币里拿10张怎么拿能拿的最多,很显然每次都从剩下的钱里拿最大的就可以了,那最后一定是最多的。

贪心问题的关键就是要选择贪心策略,对于一个问题可以有很多贪心策略,但是很多策略都不能够得到正确答案。如何能得到一个正确的贪心策略没有固定的模板,需要的是经验。


我们把这道题目转化一下思路:移除最小数量,然后区间互不重叠,那反过来,其实就是在求这个区间最多有几个互不相交的空间,得到这个结果之后,拿总个数减去就是需要移除的最小个数了。

像这个问题还有很多,可以把其统一称为:区间调度问题。基本上就是给很多个区间,找出这个区间内最多有多少个不重叠的。比如此题,再比如说在一天内有很多活动。每个活动有自己的时间段,问一天最多能参加几个活动呢。这也是求区间内最多有几个不相交的空间。关键就是要去找一种调度策略。

我们怎么来计算一个区间内最多有几个不相交的空间呢,怎么选择贪心策略呢,比如我们可以选择区间开始最早的那个,但是一想又不行,万一这个是开始的早,但是它维持时间长呢;那我们选择区间时间最短的? 其实也不行,想一下比如有个区间很短,但是呢它正好和前后两个长的都有交集,所以一旦选择这个短的,那我们长的就不能选了,很显然也错误。

正确的贪心策略:

我们从所有区间里选择结束时间最早的,也就是右区间最小的,然后把与其相交的就不要了,接着选择这个区间走完之后下一个的。(就是想让一个区间早点结束开始下一个)
这道题目贪心贪的就是谁先结束
流程:
1.按结束时间排序;
2.如果此区间与上一区间不重叠,那可以安排;
3.直到遍历完所有区间;

其实是一种最自然朴素的贪心法,我们看哪件事情能最早结束,就先去做它,也就是把结束早的都依次做了,那最后就是做的最多的。数学上也是可以证明的,但是在做题时不必纠结这个问题。重要的是一种经验的积累。

class Solution {
    public int eraseOverlapIntervals(int[][] intervals) {
        if(intervals.length == 0) return 0;
        Arrays.sort(intervals, new Comparator<int[]>(){
            public int compare(int[] a, int[] b){
                return a[1]-b[1];  //按end的升序排序;
            }
        });
        int end = intervals[0][1]; //初始化结尾;
        int count = 1;
        for(int[] inter : intervals){
            int start = inter[0]; //区间的开始;
            if(start >= end){
                count++; //找到了互补重叠的区间;
                end = inter[1]; //更新end;
            }
        }
        return intervals.length-count;
    }
}

体会

  • 要学会重写Comparator接口,可以按照自己的意愿就行排序;
Collections.sort(list, new Comparator<Node>() {
    /**o1-o2为升序序排列,o2-o1为降序排列,若具体到某一字段,则根据该字段进行排列*/
    @Override
    public int compare(Node o1, Node o2) {
        if (o1.x==o2.x) //若x属性相等,根据y来升序
            return o1.y-o2.y;
            return o1.x-o2.x;//x属性不相等,根据x来升序排列
    }
}); 
  • 涉及到数对的,一般都会对数对中的某一个维度进行排序,或者两个维度都排序,比如说区间调度按照结尾排序,比如说重建队列按照身高降序,按照k升序;所以一定要会重写比较器接口;

相关题目

455. 分发饼干

452. 用最少数量的箭引爆气球

376. 摆动序列

860. 柠檬水找零

122. 买卖股票的最佳时机 II

134. 加油站

406. 根据身高重建队列

56. 合并区间

738. 单调递增的数字

posted @ 2021-08-12 15:25  Curryxin  阅读(157)  评论(0编辑  收藏  举报
Live2D