435.无重叠区间

题目

在这里插入图片描述

方法一
分析:
本题可转换为: 一个二维数组中,互不重叠的区间最多有几个?

方法一 动态规划法
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)=1f(1)=1, r1 ≤ l2
			f(0)=1f(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();
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值