二元组最长递增子序列 -- leetcode 354. Russian Doll Envelopes

本文地址:http://blog.csdn.net/qq_26437925/article/details/52228515


leetcode 354. Russian Doll Envelopes题目地址:
https://leetcode.com/problems/russian-doll-envelopes/

AC代码

class Solution {
public:
    int maxEnvelopes(vector<pair<int, int>>& envelopes) {
        int n = envelopes.size();
        if (n <= 1)
            return n;
        // sort by p1.first < p2.first, if equal, then p1.second > p2.second
        sort(envelopes.begin(), envelopes.end(), 
            [](pair<int, int> p1, pair<int, int> p2){
                if (p1.first < p2.first)
                    return true;
                if (p1.first == p2.first)
                    return p1.second > p2.second;
                return false;
            }
        );

        vector<int> h(n); 
        int hlen = 0;   // number of elements in array h
        h[0] = envelopes[0].second;

        for (int i = 1; i < n; i++) 
        {
            int right = hlen;
            int left = 0;
            while (left <= right) {     //  binary search
                int mid = (left + right) / 2;
                if (h[mid] < envelopes[i].second) {
                    left = mid + 1;
                }
                else {
                    right = mid - 1;
                }
            }
            hlen = max(hlen, left);     // hlen max(hlen, left)
            h[left] = envelopes[i].second;
        }
        return hlen + 1;
    }
};

时间复杂度 O(nlogn) (n为所求二元组的长度)
其中:排序nlog(n), 求最长递增子序列也是O(nlogn)
空间复杂度O(n), 即构造的h数组

解题思路

对比一元最长递增子序列求解方法(时间复杂度:O(nlog(n)))
h[i] 的意义:仍然是遍历到某个数时,长度为i+1的最小末尾

例如 数组 2 1 6 4 5 2 7 4
hi
最终的h 1 3 4 7
即长度为 0+1 = 1 时 ,最小某尾数字是 1
长度为 1+1 = 2 时 ,最小某尾数字是 3
长度为 2+1 = 3 时 ,最小某尾数字是 4
长度为 3+1 = 4 时 ,最小某尾数字是 7

总之,在遍历到某个数时,长度为所有的的 最小末尾 都知道,这样最长的也就知道,可以参考牛客网左程云的算法视频讲解和图书


只是在二元组中,需要先对first从小到大排序,在对second从大到小排序,然后对second 按照一元最长递增子序列的求解方法求解即可。

例如 envelopes = [[6,7],[4,5],[4,3],[5,4],[1,2]]

按照上述排序方法,排序后如下

first14456
second25347

这样比较seconde值时,后面的小数可以替换前面的大数
即最后能够得到 [1,2] => [4,3] => [5,4] => [6,7]

倘若排序时 first second 都按从小到大

first14456
second23547

则得到 [1,2] => [4,5] => [6,7]

参考:
https://discuss.leetcode.com/topic/47469/java-nlogn-solution-with-explanation


马戏团

搜狐员工小王最近利用假期在外地旅游,在某个小镇碰到一个马戏团表演,精彩的表演结束后发现团长正和大伙在帐篷前激烈讨论,小王打听了下了解到, 马戏团正打算出一个新节目“最高罗汉塔”,即马戏团员叠罗汉表演。考虑到安全因素,要求叠罗汉过程中,站在某个人肩上的人应该既比自己矮又比自己瘦,或相等。 团长想要本次节目中的罗汉塔叠的最高,由于人数众多,正在头疼如何安排人员的问题。小王觉得这个问题很简单,于是统计了参与最高罗汉塔表演的所有团员的身高体重,并且很快找到叠最高罗汉塔的人员序列。 现在你手上也拿到了这样一份身高体重表,请找出可以叠出的最高罗汉塔的高度,这份表中马戏团员依次编号为1到N。

输入描述:
首先一个正整数N,表示人员个数。
之后N行,每行三个数,分别对应马戏团员编号,体重和身高。

输出描述:
正整数m,表示罗汉塔的高度。

输入例子:
6
1 65 100
2 75 80
3 80 100
4 60 95
5 82 101
6 81 70

输出例子:
4

http://www.nowcoder.com/practice/c2afcd7353f84690bb73aa6123548770?tpId=49&tqId=29326&rp=3&ru=/ta/2016test&qru=/ta/2016test/question-ranking

最终的意思是:
a1 > a2 && b1 >= b2 或者 a1 == a2 && b1 == b2
那么 [a2,b2] => [a1,b1]

这题采用动归求解

#include <cstdio> 
#include <cstdlib>
#include <vector> 
#include <algorithm> 
#include <iostream>

using namespace std;

typedef struct node
{
    int no;
    int w;
    int h;
}Per;

int main()
{
    //freopen("in.txt", "r", stdin);
    int n;
    while (scanf("%d", &n) != EOF)
    {
        vector<Per> vp;
        Per tmp;
        for (int i = 0; i < n; i++)
        {
            scanf("%d%d%d", &tmp.no, &tmp.w, &tmp.h);
            vp.push_back(tmp);
        }
        sort(vp.begin(), vp.end(),
            [](Per p1, Per p2){
                if (p1.w < p2.w) //体重一定要小
                    return true;
                if (p1.w == p2.w) // 体重相等时,身高一定要小
                    return p1.h < p2.h;
                return false;
            }
        );

        vector<int> dp(n,1);
        int maxL = 1;
        for (int i = 1; i < n; i++)
        {
            for (int j = 0; j < i; j++)
            {
                if (vp[i].w == vp[j].w && vp[i].h == vp[j].h)
                    dp[i] = max(dp[i], dp[j] + 1);
                if (vp[i].w > vp[j].w && vp[i].h >= vp[j].h)
                    dp[i] = max(dp[i], dp[j] + 1);
            }
            maxL = max(maxL, dp[i]);
        }

        printf("%d\n", maxL);

    }// end while
    return 0;
}

与二元组最长递增子序列很类似,不过条件不一样,无法套用


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值