354、俄罗斯套娃信封问题
一、问题描述:
给你一个二维整数数组 envelopes ,其中 envelopes[i] = [wi, hi] ,表示第 i 个信封的宽度和高度。当另一个信封的宽度和高度都比这个信封大的时候,这个信封就可以放进另一个信封里,如同俄罗斯套娃一样。请计算 最多能有多少个 信封能组成一组“俄罗斯套娃”信封(即可以把一个信封放到另一个信封里面)。注意:不允许旋转信封。
示例 1:
输入:envelopes = [[5,4],[6,4],[6,7],[2,3]] 输出:3
解释:最多信封的个数为 3, 组合为: [2,3] => [5,4] => [6,7]。
示例 2:输入:envelopes = [[1,1],[1,1],[1,1]] 输出:1
二、解题思路
- 思路和最长递增子序列类似,我们一开始肯定是要保证每一个vector的第一个元素是按照从小到大的顺序排列的,然后再看第二个元素,如果也是从小到大排列的,就满足条件,如果不是的话,我们就直接找出最长递增子序列,就会满足题意。
- 特别的要注意的是,如果第一个元素是相等的话,我们就需要将第二个元素按照从大到小的顺序排列,这是为了使他们不满足单调递增的状态。
三、Solution1:
//采用二分查找的方法,将dp数组里面的元素填满
class Solution {
public:
int maxEnvelopes(vector<vector<int>>& envelopes) {
if(envelopes.empty())
return 0;
int n = envelopes.size();
//sort的排序算法,end后面那一段是自己定义的cmp排序,return后面是不是true,指的是先将第一列按照从小到大的顺序排列,如果相等,则将第二列按照从大到小的顺序进行排列
sort(envelopes.begin(), envelopes.end(), [](const auto& e1, const auto& e2) {
return e1[0] < e2[0] || (e1[0] == e2[0] && e1[1] > e2[1]);
});
vector<int> dp(n,1);//是用来存储元素的,就是存储那个单调递增的
int res = 0;
for(int i = 0;i < n;i++){
int l = 0;
int r = res;
int mid;
while(l < r){
mid = (l+r)/2;
if(dp[l] < envelopes[i][1])
l = mid+1;
else
r = mid;
}
dp[l] = envelopes[i][1];
if(res == l) res++;
}
return res;
}
};
solution2:
//这种代码会超时,但是思路是一样的
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]);
});
vector<int> dp(n,1);
int res = 1;
for(int i = 1;i < envelopes.size();i++){
for(int j = 0;j < i;j++)
{
if(envelopes[j][1] < envelopes[i][1])
dp[i] = max(dp[i],dp[j]+1);
}
res = max(res,dp[i]);
}
return res;
}
};