You have a number of envelopes with widths and heights given as a pair of integers (w, h). One envelope can fit into another if and only if both the width and height of one envelope is greater than the width and height of the other envelope.
What is the maximum number of envelopes can you Russian doll? (put one inside other)
Example:
Input: [[5,4],[6,4],[6,7],[2,3]]
Output: 3
Explanation: The maximum number of envelopes you can Russian doll is 3 ([2,3] => [5,4] => [6,7]).
Note:
Rotation is not allowed.
动态规划的方式,时间复杂度是O(n)
,首先调用头文件algorithm
中的sort
函数,按照pair.first
为主,pair.second
为辅从小到大排序。因为每个envelope
本身就是一个信封,所以dp
中的元素都初始化为1,遍历envelops
,找到坐标为i
的元素之前所有的可以被装进envelops[i]
中的信封envelops[j]
,查看envelops[i]
中最多可以装下多少个信封dp[j]
,找到最大的dp[j]
,那么坐标为i
的信封最多装下max(dp[j]) + 1
个信封(包括自己)。比较所有的信封能装下的最多的数量,最终得到结果。时间复杂度为O(n * n)
。
int maxEnvelopes(vector<pair<int, int>>& envelopes)
{
sort(envelopes.begin(), envelopes.end());
int maxlength = 0;
vector<int> dp(envelopes.size(), 1);
for(int i = 0; i < envelopes.size(); i++)
{
for(int j = 0; j < i; j++)
if(envelopes[i].first > envelopes[j].first && envelopes[i].second > envelopes[j].second)dp[i] = dp[i] > (dp[j] + 1) ? dp[i] : (dp[j] + 1);
maxlength = maxlength > dp[i] ? maxlength : dp[i];
}
return maxlength;
}
下面是另一种解法,排序的方式是pair.first
小的排在前面,如果pair.first
相同,则pair.second
大的排在前面。
并且维护一个数组LIS
,但是这个数组并不代表最长递增信封。遍历envelops
,如果LIS
的大小为0,那么直接将当前元素的second推入LIS
,否则的话,利用lower_bound
找到当前元素在LIS
中应该插入的位置it
,如果当前元素的second大于LIS 的最大值,那么将其推入LIS
中,否则将it
位置处的元素替换为second。最终得到的结构是LIS
的大小。时间复杂度为O(n)
。
如果
envelopes
中没有出现first
相同的状况,暂时假设排好序后,后面的信封总能将前面的信封装下,那么显然最终的结果是envelopes.size()
。在下面的代码中,则是每遇见一个新元素,都会将这个新元素的second
装进LIS
中。如果
envelopes
中没有出现first
相同的状况,但是出现了后一个的second
小于前面的某一个信封的second
的状况,那么在遇到这种元素之前,遇到的每一个信封的second
都被装进了LIS
中,当前能得到的最大嵌套数就是LIS
的size()
,然后就碰到了上面所说的那种元素,这种元素的second
因为小于前面某个信封的second
,所以这个元素无法将前面所有的信封都装进自己里面,利用lower_bound
找到当前元素的second
在LIS
中应该插入的位置it
, 因为遍历数组的顺序是从小到大,所以可以肯定it
之前的元素的width
和height
肯定没有当前元素的width
以及height
大,也就是说当前元素可以把it
之前所有的元素都装进自己里面。但是当前能得到的嵌套数仍是LIS
的size()
。此时LIS
并不是一个嵌套序列,而从0到it
的元素们是一个嵌套序列。- 如果如果
envelopes
中出现了first
相同的状况,那么按照上面所说的那种排序方式,如果first
相同,second
越大,排名越在前,这是因为在代码中往LIS
中添加元素或者更改元素的时候没有关心first
的大小,所以如果出现了例如[3,3], [6,5], [6,6]
这样的状况,那么最终得到的结果会是3,这显然是不正确的。所以如果两个信封的first
相同,就先用second
较大的信封去装,这样就能保证second
较小的信封不会把second
较大的元素也装进来。
bool mycomp(pair<int, int>& l, pair<int, int>& r)
{
return (l.first != r.first) ? (l.first < r.first) : (l.second > r.second);
}
int maxEnvelopes(vector<pair<int, int>>& envelopes)
{
sort(envelopes.begin(), envelopes.end(), mycomp);
vector<int> LIS;
for(int i = 0; i < envelopes.size(); i++)
{
if(LIS.size() == 0)
{
LIS.push_back(envelopes[i].second);
continue;
}
vector<int>::iterator it = lower_bound(LIS.begin(), LIS.end(), envelopes[i].second);
if(it == LIS.end())LIS.push_back(envelopes[i].second);
else (*it) = envelopes[i].second;
}
return LIS.size();
}