Lintcode 602. 俄罗斯套娃信封
题目描述:给一定数量的信封,带有整数对 (w, h) 分别代表信封宽度和高度。一个信封的宽高均大于另一个信封时可以放下另一个信封。求最大的信封嵌套层数。
这道题如果用最常规的想法(类似【动态规划——接龙型(一维坐标型)】Lintcode 76. 最长上升子序列)处理的话,因为有两层循环,时间复杂度会超时。需要将原来算法中的第二层循环通过一定的优化去掉。
这里先给出普通的方法(时间复杂度会超,无法AC),再给出优化之后的方法。
//1. 普通方法,时间复杂度会超
class Solution {
public:
/**
* @param envelopes: a number of envelopes with widths and heights
* @return: the maximum number of envelopes
*/
int maxEnvelopes(vector<vector<int>> &envelopes) {
if (0 == envelopes.size()) {
return 0;
}
//1. 按第一维排序
sort(envelopes.begin(), envelopes.end());
//2. 对第二维使用接龙型动态规划
//2.1 初始化
vector<int> f(envelopes.size(), 1);//任何一个位置都可能是起始位置
//2.2 状态转移
for (int i = 1; i < envelopes.size(); ++i) {
for (int j = 0; j < i; ++j) {
if (envelopes[j][1] < envelopes[i][1] &&
envelopes[j][0] < envelopes[i][0]) {
f[i] = max(f[i], f[j] + 1);
}
}
}
//2.3 答案
auto maxPlies = max_element(f.begin(), f.end());
return *maxPlies;
}
};
//2. 进行了优化,可以通过OJ
class Solution {
public:
/**
* @param envelopes: a number of envelopes with widths and heights
* @return: the maximum number of envelopes
*/
int maxEnvelopes(vector<vector<int>> &envelopes) {
if (envelopes.empty()) {
return 0;
}
sort(envelopes.begin(), envelopes.end(), cmp);
int n = envelopes.size();
vector<int> dp;
for (int i = 0; i < n; i++) {
auto it = lower_bound(dp.begin(), dp.end(), envelopes[i][1]);
if (it == dp.end()) {
dp.push_back(envelopes[i][1]);
}
else {
*it = envelopes[i][1];
}
}
return dp.size();
}
static bool cmp(vector<int> &a, vector<int> &b) {
if (a[0] == b[0]) {
return a[1] > b[1];
}
return a[0] < b[0];
}
};