题目
方法一
分析:
本题可转换为: 一个二维数组中,互不重叠的区间最多有几个?
方法一 动态规划法
1.按照数组区间的端点排序;
2.排序后的结果为[l0, r0],[l1, ri],...,[ln-1, rn-1]
3.假设以第i个数组区间作为最后一个区间,最大的无重叠数目,记作f(i)
3.1 f(0)即以[l0, r0]为最后一个区间的最大的无重叠数据f(0)=1
3.2 f(1),如果r0≤l1(0的右端点小于1的左端点),则f(1)=2; 否则f(1)=1
3.3 f(2)是以[l2, r2]为最后一个节点的最大无重叠区间数目
(1)取值为3, f(1)=2 且 r1≤l2
(2)取值为2,
f(1)=2, 且 r1 > l2
f(0)=1且f(1)=1, r1 ≤ l2
f(0)=1且f(1)=1, r0 ≤ l2
(3)取值为1
f(0)=1,且f(1)=1,r1 > l2 且 r0 > l2
4.如果需要f(i)最大,可以看出需要几个条件:
(1)对于j<i中的所有j, rj <= li(j的右端点小于等于i的左端点)
(2)对于每个符合(1)中条件的j, f(j)表示以j为最后区间的最大无重叠数,f(i)=f(j)+1表示那j个区间再加上i区间
..., [lj, rj],[li, ri]的个数为f(j)+1
从这里边选一个最大的就是f(i)的结果
代码如下
class Solution {
public:
int eraseOverlapIntervals(vector<vector<int>>& intervals) {
if(intervals.empty()) return 0;
sort(intervals.begin(), intervals.end(), [](const auto&x, const auto& y) {
return x[0] < y[0];
});
int n = intervals.size();
vector<int> f(n, 1); //创建n个全为1的一维数组
for(int i = 1; i < n; i++) {
for(int j = 0; j < i; j++) {
if(intervals[j][1] <= intervals[i][0]) {
f[i] = max(f[i], f[j] + 1);
}
}
}
return n - *max_element(f.begin(), f.end());
}
};
知识点
1.algorithm + 谓词的使用
转载:谓词详解
//写法一
// [capture list] (parameter list) -> return type { function body }
sort(intervals.begin(), intervals.end(), [](const auto& u, const auto& v) {
return u[0] < v[0];
});
//写法二
struct cmp {
bool operator()(const auto& x, const auto& y) {
return x[0] < y[0];
}
}
sort(intervals.begin(), intervals.end, cmp);
2.max_element(f.begin(), f.end());
*max_element(f.begin(), f.end()) 输出的是最大值;
max_element(f.begin(), f.end()) 输出的是数组中的最大地址的指针(迭代器)
int a[] = {1, 2, 3, 4};
max_element(a, a + 4) - a 就是元素4的下标
3.循环比较
for i in 1:loop:
for j in 0:i:
f[i] = max(f[i], f[j] + 1);
每一个i都要经过和每个j的比较,记录; f[i]在这个过程中像一个缓存器
复杂度
时间复杂度:
排序sort()函数[不稳定的,稳定排序有stable_sort()函数]
1.关系型容器底层是RB-Tree,不需要排序;能够使用sort函数的只有vector,deque
2.sort内含四种排序算法:
(1)数据量过小(16): 使用插入排序
(2)递归过深: 堆排序
(3)数据量大且本来就顺序性不好时, 使用快排
所以sort的时间复杂度可能为O(nlogn)
有双层的for循环, 上层是1->n, 下层是0->i
所以是 O(n^2), 所以最终的时间复杂度为O(n^2);
空间复杂度:
额外使用了一个vector数组,所以O(n)
方法二
1.将区间按照右端点排序
2.在[0, n - 1]个区间中找出最左边的区间
3.在[1, n - 1]个区间中找出最左边的区间,且该区间的左端点大于0区间的右端点, 假设找到了第p个区间
4.在[p, n - 1]个区间中找到最左边的区间,且该区间的左端点大于1区间的右端点
5.循环上过程,直到m = n
class Solution {
public:
int n;
int eraseOverlapIntervals(vector<vector<int>>& intervals) {
this->n = intervals.size();
sort(intervals.begin(), intervals.end(), [](const auto& u, const auto& v) {
return u[1] < v[1];
});
stack<vector<int>> ret;
//ret推入了第一个
ret.push(intervals[0]);
int startIndex = 1;
while(startIndex < n) {
//栈内推进了一个vector, top()[1]是上个没有重叠的区间的右端点, startIndex是当前待比较区间的左端点
if(ret.top()[1] <= intervals[startIndex][0]) {
ret.push(intervals[startIndex]);
}
startIndex += 1;
}
return n - ret.size();
}
};