Every day a Leetcode
题目来源:354. 俄罗斯套娃信封问题
解法1:动态规划
我们必须要保证对于每一种 w 值,我们最多只能选择 1 个信封。
首先我们将所有的信封按照 w 值第一关键字升序、h 值第二关键字降序进行排序;
随后我们就可以忽略 w 维度,求出 h 维度的最长严格递增子序列,其长度即为答案。
代码:
/*
* @lc app=leetcode.cn id=354 lang=cpp
*
* [354] 俄罗斯套娃信封问题
*/
// @lc code=start
class Solution
{
public:
int maxEnvelopes(vector<vector<int>> &envelopes)
{
// 特判
if (envelopes.empty())
return 0;
int n = envelopes.size();
sort(envelopes.begin(), envelopes.end(),
[&](const auto &e1, const auto &e2)
{
return e1[0] < e2[0] || (e1[0] == e2[0] && e1[1] > e2[1]);
});
// dp[i]: 前 i 个元素能组成的最长严格递增子序列的长度
vector<int> dp(n, 1);
for (int i = 1; i < n; i++)
for (int j = 0; j < i; j++)
if (envelopes[j][1] < envelopes[i][1])
dp[i] = max(dp[i], dp[j] + 1);
return *max_element(dp.begin(), dp.end());
}
};
// @lc code=end
结果:
复杂度分析:
时间复杂度:O(n2),其中 n 是数组 envelopes 的长度。
空间复杂度:O(n),其中 n 是数组 envelopes 的长度。
解法2:基于二分查找的动态规划
代码:
/*
* @lc app=leetcode.cn id=354 lang=cpp
*
* [354] 俄罗斯套娃信封问题
*/
// @lc code=start
class Solution
{
public:
int maxEnvelopes(vector<vector<int>> &envelopes)
{
// 特判
if (envelopes.empty())
return 0;
int n = envelopes.size();
sort(envelopes.begin(), envelopes.end(),
[&](const auto &e1, const auto &e2)
{
return e1[0] < e2[0] || (e1[0] == e2[0] && e1[1] > e2[1]);
});
// dp[i]: 前 i 个元素能组成的最长严格递增子序列的长度
// vector<int> dp(n, 1);
// for (int i = 1; i < n; i++)
// for (int j = 0; j < i; j++)
// if (envelopes[j][1] < envelopes[i][1])
// dp[i] = max(dp[i], dp[j] + 1);
// return *max_element(dp.begin(), dp.end());
vector<int> f = {envelopes[0][1]};
for (int i = 1; i < n; ++i)
{
if (int num = envelopes[i][1]; num > f.back())
f.push_back(num);
else
{
auto it = lower_bound(f.begin(), f.end(), num);
*it = num;
}
}
return f.size();
}
};
// @lc code=end
结果:
复杂度分析:
时间复杂度:O(nlogn),其中 n 是数组 envelopes 的长度。
空间复杂度:O(n),其中 n 是数组 envelopes 的长度。