给你一个二维整数数组 envelopes
,其中 envelopes[i] = [wi, hi]
,表示第 i
个信封的宽度和高度。
当另一个信封的宽度和高度都比这个信封大的时候,这个信封就可以放进另一个信封里,如同俄罗斯套娃一样。
请计算 最多能有多少个 信封能组成一组“俄罗斯套娃”信封(即可以把一个信封放到另一个信封里面)。
注意:不允许旋转信封。
思路:
首先,需要同时有宽和高都大于才能包含,因此同一时间需要比较两方面的数字,因此需要先固定其中一种数字,这样只需要对另一种数字进行比较,这里选择按照宽度由小到大排列,这样对于i位置和i+1位置,只要i+1位置高度大于i位置高度,则两者一定可以包含在一起。
其次,此时在宽度排序的情况下,就是寻找按照顺序递增顺序所能包含的最大的数,即从中按照顺序选择一些数,使得满足递增排序。但是有一点不同的是,可能有宽度一样的存在,此时哪怕高度高也不能放到一块,因此宽度必须满足大于才行,因此对于宽度相同的数,如果按照高度递减排序,这样就一定不会出现宽度相同而高度由小到大的情况,在这种情况下直接找递增序列就可以了。
找递增序列的方法就是利用一个有序数组记录当前递增序列的一部分记录,对于进去的一个高度,如果比数组中最大的元素都大,说明一定可以包含进去,则数组尾插该高度。若不能比最大元素都大,则利用二分法找到一个位置i,满足i-1位置小于该高度,i位置大于等于该高度,然后更新i下标的数为该高度即可。
最后返回的就是有序数组的高度。
class Solution {
public:
int maxEnvelopes(vector<vector<int>>& envelopes) {
// //选择一种合适的顺序,将尽可能多的放在一块
// sort(envelopes.begin(),envelopes.end());
// int n=envelopes.size();
// vector<int>dp(n,1);
// for(int i=n-2;i>=0;i--)
// {
// //n的平方
// int m=1;
// for(int j=i+1;j<n;j++)
// {
// if(envelopes[i][0]<envelopes[j][0]&&envelopes[i][1]<envelopes[j][1])
// {
// m=max(dp[j]+1,m);
// }
// }
// dp[i]=m;
// }
// int ret=dp[0];
// for(auto e:dp)
// {
// ret=max(e,ret);
// }
// return ret; //最后超时的做法,原因是每次找高大于且数字大的需要n的时间
auto cmp=[&](vector<int>&p1,vector<int>&p2){ if(p1[0]<p2[0]) return true; else if(p1[0]>p2[0]) return false ;else return p1[1]>p2[1];
};
sort(envelopes.begin(),envelopes.end(),cmp);
int n=envelopes.size();
vector<int>count;
for(int i=0;i<envelopes.size();i++)
{
//二分查找对应位置
int l=0,r=count.size()-1;
if(count.size()==0||count.back()<envelopes[i][1])
count.push_back(envelopes[i][1]);
else
{
while(l<r)
{
int mid=(l+r)/2;
if(count[mid]>envelopes[i][1])
{
r=mid;
}
else if(count[mid]<envelopes[i][1])
{
l=mid+1;
}
else
{
l=mid;
break;
}
}
count[l]=envelopes[i][1];
}
}
return count.size();
}
};