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:
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]).

我的思路:和最长递增子序列是一个思路。先把信封按照一条边从小到大排序。然后按照最长递增子序列的递归思路做。注意要同时比较长和宽。

class Solution {
public:
    int maxEnvelopes(vector<pair<int, int>>& envelopes) {
        sort(envelopes.begin(),envelopes.end());
        int n=envelopes.size();
        if(n<=1) return n;
        vector<int> dp(n,1);
        int res=0;
        for(int i=1;i<n;i++)
        {
           for(int j=i-1;j>=0;j--)
            {
                if(envelopes[i].first>envelopes[j].first&&envelopes[i].second>envelopes[j].second)
                    dp[i]=max(dp[i],dp[j]+1);
            } 
            res=max(res,dp[i]);
        }
        return res;
            
    }
};

上题是n方解法的,通过二分查找形式的动态规划可以实现nlogn。但是这种方法的实现实现复杂度降低的原理是在已有长度的信封嵌套中保存一个最后信封最小的那个。

比如【2,2】【3,4】【3,3】【4,4】,长度为2的最小信封结尾应该是【3,3】而不是【3,4】,最长序列应该是3,但是如果只更新到【4,4】不能容纳【3,4】,结果不正确。

另一个例子:

【2,3】【3,4】【3,3】【4,4】  ,【3,4】可以容纳【2,3】,但是【3,3】不能容纳【2,3】,结果是最长为2.

解决的办法是:

自定义排序规则。使得长小的排在前边。长大的排在后边,如果长相同,宽大的排在前面宽小的排在后边。二分查找的时候只比较信封的宽度。。,dp数组只保存宽度。

比如已经排好序的【2,2】【3,4】【3,3】【4,4】,当遍历到【3,3】时,【3,3】应该排在【3,4】的前边,因为第二个数小,所以返回【3,4】的位置,替换【3,4】

比如:【2,3】【3,4】【3,3】【4,4】 ,遍历到【3,3】时,找到的位置是【2,3】,这个时候改变成【3,3】【3,4】,虽然【3,3】扩大了,但是后面的数如果可能构成更长的序列,长肯定要比3大才行,所以不影响最后的长度。长度为3的子序列是跟【3,4】比较的。

使用神奇的lambda表达式:

注意,当lambda表达式的函数体除了return语句之外还有其他语句,必须制定返回类型。

class Solution {
public:
    int maxEnvelopes(vector<pair<int, int>>& envelopes) {
        sort(envelopes.begin(),envelopes.end(),
             [](const pair<int,int>& a,const pair<int,int>& b)->bool{if(a.first==b.first) return a.second>b.second;
        else
            return a.first<b.first;});//使用lambda表达式
        vector<int> dp;
        for(int i=0;i<envelopes.size();i++)
        {
            auto it=std::lower_bound(dp.begin(),dp.end(),envelopes[i].second);
            if(it!=dp.end()) 
                *it=envelopes[i].second;
            else
                dp.push_back(envelopes[i].second);
        }
        return dp.size();
    }
};
使用函数对象:注意函数对象后面需要加括号

class Solution {
public:
    int maxEnvelopes(vector<pair<int, int>>& envelopes) {
        sort(envelopes.begin(),envelopes.end(),comp());
        vector<int> dp;
        for(int i=0;i<envelopes.size();i++)
        {
            auto it=std::lower_bound(dp.begin(),dp.end(),envelopes[i].second);
            if(it!=dp.end()) 
                *it=envelopes[i].second;
            else
                dp.push_back(envelopes[i].second);
        }
        return dp.size();
    }
    struct comp{
    bool operator()(const pair<int,int>& a,const pair<int,int>& b)
    {
             if(a.first==b.first) return a.second>b.second;
        else
            return a.first<b.first;
    }
    };

};








  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值