力扣435-无重叠区间

98 阅读2分钟

活动安排.png

题目描述

给定一个区间的集合 intervalsintervals ,其中 intervals[i]=[starti,endi]intervals[i] = [starti, endi] 。返回 需要移除区间的最小数量,使剩余区间互不重叠

用例

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

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

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

题目分析

这就是经典的活动选择类问题,活动选择问题是给定一堆活动,让你进行选择,约束是一个活动结束了才能参加下一个活动(即下一个活动开始时间不小于上一个活动结束时间),问最多参与多少个活动。要想尽可能多参加活动,直观的策略是参加活动时长短的活动,但是这个贪心策略容易找到反例,即活动时长短的活动可能卡住两个不重合的长活动。理想贪心策略是优先参加活动结束时间早的活动。

简单用数学归纳法说明贪心策略的正确性。
我们对算法的步骤进行归纳证明。
归纳基础,你用结束时间最早的活动替换最优解的第一个活动,得到的解显然仍然是最优解,即存在包括最早结束时间的活动的最优活动安排。
归纳假设,存在最优活动安排包含算法第kk步得到的活动。
归纳步骤,存在最优活动安排Acti1,Acti2,...,Actik1,Actik,...,ActinAct_{i_1},Act_{i_2},...,Act_{i_{k-1}},Act_{i_{k}},...,Act_{i_{n}},其中Acti1,Acti2,...,Actik1,ActikAct_{i_1},Act_{i_2},...,Act_{i_{k-1}},Act_{i_{k}}是按算法11 to kk步所得。首先,我们用算法第k+1k+1步得到的活动替换Actik+1Act_{i_{k+1}}并没有破坏活动之间的约束,同时,经过替换后得到的活动序列的长度并没有变少,故而它也是最优活动安排。

回到无重叠区间问题,那么解法就简单了。第一步,我们对各个区间按区间后边界进行升序排序;第二步,我们按照贪心策略遍历各个区间,如果该区间前边界小于上一选定的区间后边界,则删除数累加,否则更新上一选定区间;最后,返回累加数。

代码

class Solution {
public:
    int eraseOverlapIntervals(vector<vector<int>>& intervals) {
		int del_num= 0;
		// sort
		sort(intervals.begin(), intervals.end(), [](vector<int> a, vector<int> b){
			return a[1]< b[1];
		});
		// count
		for(int i= 1, k= 0; i< intervals.size(); i++){
			if(intervals[i][0]< intervals[k][1]){del_num+= 1;}
			else{k= i;}
		}
		return del_num;
    }
};

其中,时间复杂度T(n)=O(nlogn)T(n)=O(nlogn).