1. 程式人生 > >354. Russian Doll Envelopes

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

中的元素都初始化為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)

  1. 如果envelopes中沒有出現first相同的狀況,暫時假設排好序後,後面的信封總能將前面的信封裝下,那麼顯然最終的結果是envelopes.size()。在下面的程式碼中,則是每遇見一個新元素,都會將這個新元素的second 裝進LIS中。

  2. 如果envelopes中沒有出現first相同的狀況,但是出現了後一個的second小於前面的某一個信封的second的狀況,那麼在遇到這種元素之前,遇到的每一個信封的second都被裝進了LIS中,當前能得到的最大巢狀數就是LISsize(),然後就碰到了上面所說的那種元素,這種元素的second因為小於前面某個信封的second,所以這個元素無法將前面所有的信封都裝進自己裡面,利用lower_bound找到當前元素的secondLIS中應該插入的位置it, 因為遍歷陣列的順序是從小到大,所以可以肯定it之前的元素的widthheight肯定沒有當前元素的width以及height 大,也就是說當前元素可以把it之前所有的元素都裝進自己裡面。但是當前能得到的巢狀數仍是LISsize()。此時LIS並不是一個巢狀序列,而從0到it的元素們是一個巢狀序列。

  3. 如果如果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();
}