腾讯 wxg 测开一面
给你一个二维整数数组 envelopes
,其中 envelopes[i] = [wi, hi]
,表示第 i
个信封的宽度和高度。
当另一个信封的宽度和高度都比这个信封大的时候,这个信封就可以放进另一个信封里,如同俄罗斯套娃一样。
请计算 最多能有多少个 信封能组成一组“俄罗斯套娃”信封(即可以把一个信封放到另一个信封里面)。
注意:不允许旋转信封。
示例 1:
1 2 3
| 输入:envelopes = [[5,4],[6,4],[6,7],[2,3]] 输出:3 解释:最多信封的个数为 3, 组合为: [2,3] => [5,4] => [6,7]。
|
示例 2:
1 2
| 输入:envelopes = [[1,1],[1,1],[1,1]] 输出:1
|
提示:
1 <= envelopes.length <= 10^5
envelopes[i].length == 2
1 <= wi, hi <= 10^5
0️⃣ 前置题目
✅ 300. 最长递增子序列 |DP / 二分
1️⃣ LIS · 动态规划(超时 TLE)
时间复杂度 $O(n^2)$
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class Solution { public: int maxEnvelopes(vector<vector<int>>& envelopes) { int n = envelopes.size(); vector<pair<int, int>> arr(n); for (int i = 0; i < n; i++) arr[i] = {envelopes[i][0], envelopes[i][1]}; ranges::sort(arr);
vector<int> f(n, 1); for (int i = 0; i < n; i++) { for (int j = 0; j < i; j++) { if (arr[i].first > arr[j].first && arr[i].second > arr[j].second) { f[i] = max(f[i], f[j] + 1); } } } return ranges::max(f); } };
|
2️⃣ 贪心 + 二分查找
时间复杂度:$O(n·logn)$
先排序,再按照 LIS 二分贪心模板求最长递增子序列。因为二者都必须是递增的,所以第二维度需要逆序排序,使得第一维度相同的多个数,最后一个插入的一定是最小值,这样能嵌套的信封最多。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| class Solution { public: int maxEnvelopes(vector<vector<int>>& envelopes) { sort(envelopes.begin(), envelopes.end(), [](auto& a, auto& b) { return a[0] < b[0] || (a[0] == b[0] && a[1] > b[1]); }); vector<int> g; for (auto& e : envelopes) { auto it = lower_bound(g.begin(), g.end(), e[1]); if (it == g.end()) { g.push_back(e[1]); } else { *it = e[1]; } } return g.size(); } };
|