LeetCode 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)

Note:
Rotation is not allowed.

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

 


 

二、题目分析

  根据题意,类似于俄罗斯套娃,我们需要计算出最大的信封层叠数。

  若我们将每一个信封的规格看作有向图的一个顶点,当且仅当一个信封能够被装入另一个信封时,才有从前者指向后者的边,那么这道题就是求图的最长路径长度。但构造这个有向图就需要 O ( N 2 ) O(N^2) O(N2) 的复杂度,所以应该简化一下流程。

  可知,有向图的每条边都表示了一个大小关系,故我们将原容器中的信封按宽度(第一个数据)从小到大排序,若遇到相等的情况,则按高度(第二个数据)从大到小排序(为了防止在后面的过程中出现在宽度相同的情况下高度大的能够装入高度小的信封的情况,即防止出现如 [3,7] => [3,9] 的情况)。
  排序后,我们就可以遍历所有信封来构建路径(以数组的形式)了。按照以上的排序规则,当遍历到一个信封——

  • 其高度(第二个数据)比当前路径的最后一个信封的高度大(即比路径上所有信封的高度大)时,路径长度就增加1,该信封作为路径的新的终点(插入到数组最后)。
  • 否则,找到路径中第一个高度 不小于 该信封高度的那一个信封,将其替换为遍历到的信封。
    • 这样做并不会改变当前路径的长度。
    • 当参与替换的两个信封的宽度相等时,被替换的信封必定是当前路径的终点,这相当于减小了终点信封的规格,这样使得装入终点信封的条件更容易满足了。
    • 当参与替换的两个信封的宽度不相等时,相当于从被替换的那个信封处开了一条分支路径,若最后从那里开始的分支的长度大于之前的路径,那么之前的路径会被覆盖掉(不断地被替换),路径长度就增长了。

  完成遍历后,我们返回路径数组的元素个数作为最长路径长度。

 


 

三、具体实现

  根据以上分析,排序的复杂度为 O ( N l o g N ) O(NlogN) O(NlogN) ,总的查找的复杂度为 O ( N l o g N ) O(NlogN) O(NlogN) ,故算法的复杂度为 O ( N l o g N ) O(NlogN) O(NlogN)
  由于遍历时参与比较的都是高度(第二个数据),故我们只需维护高度的数组就可以表示路径了。

class Solution
{
  public:
    int maxEnvelopes( vector<pair<int, int>> &envelopes )
    {
        if ( envelopes.empty() )
            return 0;

        sort( envelopes.begin(), envelopes.end(), 
            []( pair<int, int> &a, pair<int, int> &b )
            { return a.first < b.first || ( a.first == b.first && a.second > b.second ); } );

        vector<int> res( 1, envelopes.front().second );
        for ( auto p : envelopes ) {

            if ( p.second > res.back() ) {
                res.push_back( p.second );
            } else {
                *lower_bound( res.begin(), res.end(), p.second ) = p.second;
            }

        }

        return res.size();
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值