要求
- 给定一组区间,最少删除多少个区间,可以让这些区间之间互相不重叠
- 给定区间的起始点永远小于终止点
示例
- [[1,2],[2,3],[3,4],[1,3]], 返回1
- [[1,2],[1,2],[1,2]], 返回2
思路
- 等价为最多保留多少个区间
- 暴力:找出所有子区间的组合,判断不重叠((2^n)*n)
- 先排序,方便判断不重叠
- 具体实现类似最长上升子序列
- 选择区间的结尾很重要,结尾越小,留给后面的空间越大
实现
- 动态规划(n^2)
- dp[i]:使用intervals[0...i]的区间所能构成的最长不重叠区间序列
1 class Solution { 2 public: 3 int eraseOverlapIntervals(vector<vector<int>>& intervals) { 4 5 if(intervals.size() == 0) 6 return 0; 7 8 sort(intervals.begin(), intervals.end(), [](const vector<int>& a, const vector<int>& b){ 9 if(a[0] != b[0]) return a[0] < b[0]; 10 return a[1] < b[1]; 11 }); 12 13 vector<int> dp(intervals.size(), 1); 14 for(int i = 1 ; i < intervals.size() ; i ++) 15 for(int j = 0 ; j < i ; j ++) 16 if(intervals[i][0] >= intervals[j][1]) 17 dp[i] = max(dp[i], 1 + dp[j]); 18 19 return intervals.size() - dp.back(); 20 } 21 };
- 贪心算法(n)
- 按照区间结尾排序,每次选择结尾最早的,且和前一个区间不重叠的区间
- 贪心选择性质:贪心算法为A,最优算法为O,A完全能替代O,且不影响求出最优解
- 若无法使用贪心算法,举出反例即可
- 证明正确性,可使用数学归纳法
- 某次选择的是[s(i),f(i)],其中f(i)是当前所有选择中结尾最早的
- 假设这个选择不是最优的,若最优解为k,则这个选择得到的解,最多为k-1
- 假设最优解在这一步选择[s(j),f(j)],其中f(j)>f(i)
- 显然可用[s(i),f(i)]替换[s(j),f(j)],而不影响后续的区间选择
- 即当选择[s(i),f(i)]时,也构成了大小为k的解,矛盾
- 此问题具有贪心选择性,可以用贪心算法得到最优解
1 class Solution { 2 3 public: 4 int eraseOverlapIntervals(vector<vector<int>>& intervals){ 5 6 if(intervals.size() == 0) 7 return 0; 8 9 sort(intervals.begin(), intervals.end(), [](const vector<int>& a, const vector<int>& b){ 10 if(a[0] != b[0]) return a[0] < b[0]; 11 return a[1] < b[1]; 12 }); 13 14 int res = 1; 15 int pre = 0; 16 for(int i = 1 ; i < intervals.size() ; i ++) 17 if(intervals[i][0] >= intervals[pre][1]){ 18 pre = i; 19 res ++; 20 } 21 else if(intervals[i][1] < intervals[pre][1]) 22 pre = i; 23 24 return intervals.size() - res; 25 } 26 };
应用
- 最小生成树
- 最短路径