LintCode 602: Russian Doll Envelopes (俄罗斯套娃,单调队列经典题)

602. Russian Doll Envelopes

Give 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.
Find the maximum number of nested layers of envelopes.

Example

Example 1:

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

Example 2:

Input:[[4,5],[4,6],[6,7],[2,3],[1,1]]
Output:4
Explanation:
the maximum number of envelopes you can Russian doll is 4 ([1,1] => [2,3] => [4,5] / [4,6] => [6,7]).

Input test data (one parameter per line)How to understand a testcase?

这题跟LintCode 1858: Set of boxes 很相似,1858那题比这题还要稍微难一点,因为还要根据x和y再排一下序,这道题不用,因为x就跟x相比,y就跟y相比。详见https://blog.csdn.net/roufoo/article/details/105097818

解法1:类似LIS,但超时。

注意:
1) 这里的sort是pair<int, int>的default版本。
2) 这里dp[]并不一定是从小到大排序,也就是说dp[n-1]不一定是最优解。

class Solution {
public:
    /*
     * @param envelopes: a number of envelopes with widths and heights
     * @return: the maximum number of envelopes
     */
    int maxEnvelopes(vector<pair<int, int>>& envelopes) {
        int n = envelopes.size();
        if (n == 0) return 0;
        sort(envelopes.begin(), envelopes.end());
        
        vector<int> dp(n, 1);
        int gMaxLevel = 0;
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < i; ++j) {
                if (envelopes[i].first > envelopes[j].first &&
                    envelopes[i].second > envelopes[j].second) {
                        dp[i] = max(dp[i], dp[j] + 1);
                    }
            }
            gMaxLevel = max(gMaxLevel, dp[i]);
        }
        
        for (int i = 0; i < n; ++i) cout<<dp[i]<<" ";
        cout<<endl;
        
        return gMaxLevel;
    }
};

解法2:单调递增队列

注意:
1) 排序的时候按第一维排序,若第一维相等则按第二维。
为什么呢?假设排序后队列如下:
(1,8)
(2,3)
(5,4)
(5,2)
(6,7)
(6,4)

为什么第2维要降序呢?因为看下面的例子,(5,4)排在(5,2)前面。单调递增队列轮到(5,2)的时候,binary search返回的序号就是(5,4)的序号(lower_bound,按y来搜索),所以它会踢掉(5,4)。如果第2维升序的话,那么(5,2)排在(5,4)前面,单调递增队列先把(5,2)放进来,再看(5,4)的时候因为4>2,所以(5,4)也会放进队列,这样队列里面有2个箱子第1维都是5,就不对了。
2) lower_bound是返回an iterator pointing to the first element in the range [first,last) which does not compare less than val, 所以不需要重新定义binary search函数了。
3) 不能直接重载bool operator < (const pair<int, int> & a, const pair <int, int> & b),
然后sort(envelops.begin(), envelops.end())。这样重载的operator < 根本没有调用到。原因应该是pair<int,int>是内置类型,不能重载操作符。应该加一个wrapper class。或者重新定义一个Node结构,重载bool operator<是可以的。

struct compare {
    bool operator () (const pair<int, int> & a, const pair<int, int> & b) {
        if (a.first == b.first) return a.second > b.second;
        return a.first < b.first;
    }
}cmp;

class Solution {
public:
    /*
     * @param envelopes: a number of envelopes with widths and heights
     * @return: the maximum number of envelopes
     */
    int maxEnvelopes(vector<pair<int, int>>& envelopes) {
        int n = envelopes.size();
        if (n == 0) return 0;
        sort(envelopes.begin(), envelopes.end(), cmp);
        
        vector<int> monoIncSeqs;
        for (int i = 0; i < n; ++i) {
            vector<int>::iterator it = lower_bound(monoIncSeqs.begin(), monoIncSeqs.end(), envelopes[i].second);
            if (it == monoIncSeqs.end()) {
                monoIncSeqs.push_back(envelopes[i].second);
            } else {
                *it = envelopes[i].second;
            }
            
        }
        
        return monoIncSeqs.size();
    }
};

也可以写成:
 

struct compare {
    bool operator () (const pair<int, int> & a, const pair<int, int> & b) {
        if (a.first == b.first) return a.second > b.second;
        return a.first < b.first;
    }
}cmp;

class Solution {
public:
    /*
     * @param envelopes: a number of envelopes with widths and heights
     * @return: the maximum number of envelopes
     */
    int maxEnvelopes(vector<pair<int, int>>& envelopes) {
        int n = envelopes.size();
        if (n == 0) return 0;
        sort(envelopes.begin(), envelopes.end(), cmp);
        
        vector<int> monoIncSeqs(n, INT_MAX);
        for (int i = 0; i < n; ++i) {
            vector<int>::iterator it = lower_bound(monoIncSeqs.begin(), monoIncSeqs.end(), envelopes[i].second);
            *it = envelopes[i].second;
        }
        
        for (int i = n - 1; i >= 0; --i) {
            if (monoIncSeqs[i] != INT_MAX) return i + 1;
        }
         
        return 0;      
    }
};

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值