646. 最长数对链
435. 无重叠区间
(上面两道题类似,都是安排教室使用类的问题,在给定的一些时间间隔中选取不会发生冲突的最大活动安排数量)
动态规划【时间复杂度$O(n^2)$】
定义
dp[i]
为以pairs[i]
(第i项活动) 为结尾的最多能容纳活动的数量则在
pairs[i][0] > pairs[j][1]
,即第i项活动开始晚于第j项活动结束(j<i
)的前提下,状态转移方程为dp[i] = max(dp[i], dp[j] + 1);
要注意
- dp数组初始化为全1
- 共两层循环,所以时间复杂度$O(n^2)$
- 要预先对pairs中的所有活动按照开始时间从早到晚进行排序,这样计算dp[i] 时,所有潜在的dp[j] 已经计算完成
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16class Solution {
public:
int findLongestChain(vector<vector<int>>& pairs) {
int n = pairs.size();
sort(pairs.begin(), pairs.end());
vector<int> dp(n, 1);
for (int i = 0; i < n; i++) {
for (int j = 0; j < i; j++) {
if (pairs[i][0] > pairs[j][1]) {
dp[i] = max(dp[i], dp[j] + 1);
}
}
}
return dp[n - 1];
}
};贪心+二分查找【时间复杂度:$O(n \log n)$】
改造上面的dp方法,使用二分查找新的活动可以插入的位置,如果满足条件就插入
同样要求预先对pairs中的所有活动按照开始时间从早到晚进行排序
用一个数组arr 来记录当前最优情况,arr[i] 就表示长度为 i+1 的数对链的末尾可以取得的最小值,遇到一个新数对时,先用二分查找得到这个数对可以放置的位置,再更新arr。
代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17class Solution {
public:
int findLongestChain(vector<vector<int>>& pairs) {
sort(pairs.begin(), pairs.end());
vector<int> arr;
for (auto p : pairs) {
int x = p[0], y = p[1];
if (arr.size() == 0 || x > arr.back()) {
arr.emplace_back(y);
} else {
int idx = lower_bound(arr.begin(), arr.end(), x) - arr.begin();
arr[idx] = min(arr[idx], y);
}
}
return arr.size();
}
};单纯贪心【时间复杂度:$O(n \log n)$】
【算法课上讲过这种方法】
将所有活动按照结束时间从早到晚进行排序,结束时间越早,留给后面活动的时间就越多,应用了贪心的思想
排序时使用自定义的sort函数,其中记得使用引用传参,减少时间开销
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16class Solution {
public:
int findLongestChain(vector<vector<int>>& pairs) {
int curr = INT_MIN, res = 0;
sort(pairs.begin(), pairs.end(), [](const vector<int> &a, const vector<int> &b) {
return a[1] < b[1];
});
for (auto &p : pairs) {
if (curr < p[0]) {
curr = p[1];
res++;
}
}
return res;
}
};
- 本文链接:https://wan-nan.github.io/2022/09/03/646-%E6%9C%80%E9%95%BF%E6%95%B0%E5%AF%B9%E9%93%BE/
- 版权声明:本博客所有文章除特别声明外,均默认采用 许可协议。