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)

示例:
Given envelopes = [[5,4],[6,4],[6,7],[2,3]], the maximum number of envelopes you can Russian doll is 3 ([2,3] => [5,4] => [6,7]).

题解:

  • 该题的目标是在这些套娃中找到最大的子集,使得套娃之间能够从小到大的套起来
  • 经分析,该题目其实可以规约成一个最长递增子序列的问题
  • 基本思路:将套娃们从小到大排列起来,其中如果套娃a的高度和宽度都比b的高度和宽度都要低,那a就排在b的前面,然后对排序后的序列求最长递增子序列即可
  • 但是在排序的过程中,我遇到了这样的问题,如果将比较函数设为:
static bool cmp(const pair<int,int> &a, const pair<int,int> &b)
{
     if (a.first < b.first && a.second < b.second)
         return true;
    else return false;
}

会出现排序出错的问题(存在小的套娃最终排在大的套娃后面),原因未知。于是我需要改变排序的方式。实际上,如果只根据a.first与b.first进行排序,其实对最小递增子序列的求解不会产生影响(因为已经保证一端是顺序的,那么这一端必然符合递增的原则)。于是,我们可以通过以下的比较函数来对套娃进行排序:

static bool cmp(const pair<int,int> &a, const pair<int,int> &b)
{
     if (a.first < b.first)
         return true;
    else return false;
}
    排序后,就可以通过求取排序后的递增子序列(LIS)来解出答案,而常见的求解LIS的方法有两种(假设原序列为a):
    1. 记dp[i]为以a[i]结尾的LIS长度:    
    • 对于在a[i]前面的元素a[j],如果a[i]比a[j]大,说明a[i]能够接到以a[j]结尾的序列上,因此dp[i]可能的取值为dp[j]+1
    • 因为要求的是最长的子序列,所以,dp[i]的最终取值为所有可能取值的最大值
    • 如果a[i]比前面的元素都要小,那dp[i] = 1

    2. 记dp[i]为长度为i的递增子序列中,排在最后一个元素的大小:

    • 对于a[i],先在dp中找a[i]的下界
    • 如果找不到,说明dp为空,或者可以形成更长的递增子序列,因此,将a[i]插入到dp末尾
    • 如果找到的话,意味着存在两个元素,他们都能得到长度为i的递增子序列,但实际上,无论他们两个元素的相对大小,排在前面的元素已经没有用了,因此dp[i] = a[i]

代码:

  • 第一种方法:
class Solution {
public:
    static bool cmp(const pair<int,int> &a, const pair<int,int> &b)
    {
        if (a.first < b.first)
            return true;
        else return false;
    }
    
    int maxEnvelopes(vector<pair<int, int>>& envelopes) 
    {
        if(envelopes.size()==0) return 0;
        sort(envelopes.begin(),envelopes.end(),cmp);
        int n = envelopes.size();
        vector<int> dp(n);
        dp[0] = 1;
        int maxnum = dp[0];
        // for(int i = 0 ; i < n; i++)
        //     cout << envelopes[i].first << " " << envelopes[i].second << endl;
        
        for(int i = 1; i < n;i++)
        {
            int curr = 1;
            for(int j = 0; j < i ;j++)
            {
                if(envelopes[j].first < envelopes[i].first && 
                envelopes[j].second < envelopes[i].second)
                    curr = max(dp[j]+1,curr);
            }
            dp[i] = curr;
            maxnum = max(curr,maxnum);
        }
        // for(int i = 0; i < n ; i++)
        //     cout << dp[i] << " ";
        // cout << endl;
        return maxnum;
    }
};
  • 第二种方法:
  • class Solution {
    public:
        static bool cmp(const pair<int,int> &a, const pair<int,int> &b)
        {
            if (a.first < b.first || (a.first == b.first && a.second > b.second))
                return true;
            else 
                return false;
        }
        
        int maxEnvelopes(vector<pair<int, int>>& envelopes) 
        {
            if(envelopes.size()==0) return 0;
            sort(envelopes.begin(),envelopes.end(),cmp);
            int n = envelopes.size();
            vector<int> dp;
            
            for (auto e : envelopes) {
                auto it = lower_bound(dp.begin(), dp.end(), e.second);
                if (it == dp.end()) dp.push_back(e.second);
                else *it = e.second;
            }
            return dp.size();
        }
    };

     

 
posted @ 2017-05-19 11:19  MT.Queen  阅读(167)  评论(0编辑  收藏  举报