354. Russian Doll Envelopes
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
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();
}