这个题目,很纠结。。。我不管咋优化都无法优化都无法过测试。提示超时。。。。
先把思路说一下把!。
第一排序,先按照高度排序,然后剩下的就是宽度了。
再按照leetcode300的算法,固定i后就从0到i-1 去找那个能让dp[j]+1 最大的序列。当然条件就是
dp[i][0] > dp[j][0] && dp[i][1] > dp[j][1] 这样俄罗斯套信封才能装进去。
找到后就再遍历下dp的数值,找最大的那个dp数值。就是答案了。
看上去不难。难的是优化。。。咋优化那。
觉得leetcode套路太多了。
优化的办法是用一个特别的数组---递增数组。
当要加入的元素大于递增数组最后一个元素的时候,直接push进去。
当要加入的元素小于递增数组最后一个元素的时候,找比他搭的元素里最小的那个替换。
为啥要替换那?就是为了给后来人腾地方。
数越小,以后能接上的数就越多,答案就越长。
下面就是答案了。。。
代码里有个cmp排序。为啥要做这个那?
为了是让相同高度,但是宽度不相同的元素被过滤掉一些。这样就能只考虑第二个元素宽度了。
如果直接不考虑第一个元素高度,只考虑宽度。那下面的就被误认为可以套娃了。毕竟3 < 6.
比如{4, 3}, {4, 6}
如果按照倒序排序 {4,6}, {4,3}。 在维护递增队列的时候,3就会被插入到递增队列里替代比他打的数。为后人做贡献。
哎 算法题真难。也真的很绕。
class Solution {
static bool cmp(vector<int> a, vector<int> b){
if(a[0] == b[0]){
return a[1]>b[1];
}
else
return a[0]<b[0];
}
public:
int maxEnvelopes(vector<vector<int>>& envelopes) {
int n = envelopes.size();
sort(envelopes.begin(), envelopes.end(), cmp);
vector<int> q;
for(auto envelop: envelopes){
if(q.empty() || envelop[1] > q.back())
q.push_back(envelop[1]);
else{
auto it = lower_bound(q.begin(), q.end(), envelop[1]);
*it = envelop[1];
}
}
return q.size();
}
};
方法二:
#if 0
int maxEnvelopes(vector<vector<int>>& envelopes) {
//https://www.youtube.com/watch?v=B1d2wV6mfzA
//看完guan神的代码觉得真的很漂亮。
// 这道题目和leetcode 300 一样,都是LSI,最长上升子序列。
// 我们把信封的width排序好以后,就生下了高度了。
// 比如example 1,排序以后就是
// [2, 3], [5,4] [6,4], [6,7]
// 要找最后一个信封所能套的最多信封数目,就得从第一个信封开始看。
// [2,3] 可以,因为2 < 6, 3 < 7
// [5, 4] 可以,因为5 < 6, 4 <7
// 6, 4 不可以,因为6 = 6
//于是就有两个信封可以被风道[6,7]里。如果能计算出[2,3],[5,4] 套住的信封,就好做了。
//那就用DP把,可以算出来之前[2,3]能套住的信封数
//max number of evnelopes can russian doll
int n = envelopes.size();
vector<int> dp(n, 1);
sort(envelopes.begin(), envelopes.end(), cmp);
for(int i=1;i < n; i++){
for(int j = 0; j < i;j++){
if(envelopes[i][0] > envelopes[j][0] && envelopes[i][1] > envelopes[j][1])
dp[i] = max(dp[i], dp[j]+1);
}
}
int ret = 0;
for(int i = 0;i < n;i++){
ret = max(ret, dp[i]);
}
return ret;
#endif