前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >程序员面试金典 - 面试题 17.08. 马戏团人塔(最长上升子序 DP/二分查找)

程序员面试金典 - 面试题 17.08. 马戏团人塔(最长上升子序 DP/二分查找)

作者头像
Michael阿明
发布2020-07-13 15:41:46
6630
发布2020-07-13 15:41:46
举报

1. 题目

有个马戏团正在设计叠罗汉的表演节目,一个人要站在另一人的肩膀上。出于实际和美观的考虑,在上面的人要比下面的人矮一点且轻一点

已知马戏团每个人的身高和体重,请编写代码计算叠罗汉最多能叠几个人

代码语言:javascript
复制
示例:
输入:height = [65,70,56,75,60,68] weight = [100,150,90,190,95,110]
输出:6
解释:从上往下数,叠罗汉最多能叠 6 层:(56,90), (60,95), (65,100), (68,110), (70,150), (75,190)

提示:
height.length == weight.length <= 10000

来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/circus-tower-lcci

著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

2. 解题

类似题目:

LeetCode 354. 俄罗斯套娃信封问题(最长上升子序 DP/二分查找)

程序员面试金典 - 面试题 08.13. 堆箱子(DP)

2.1 超时解

  • 类似于最大上升子序
  • 采用DP解法,时间复杂度 O(n2)O(n^2)O(n2),看上面数据规模,超时妥妥的 ( 23 / 43 个通过测试用例 )
代码语言:javascript
复制
class Solution {
public:
    int bestSeqAtIndex(vector<int>& height, vector<int>& weight) {
    	int i, j, n = height.size(),maxP = 1;
    	vector<vector<int>> p(n);
    	for(i = 0; i < n; ++i)
    		p[i] = {height[i], weight[i]};
    	sort(p.begin(),p.end());//按身高升序
    	vector<int> dp(n,1);
    	for(i = 1; i < n; ++i)
    	{
    		for(j = i-1; j >= 0; --j)
    		{
    			if(p[i][1] > p[j][1])
    			{
    				dp[i] = max(dp[i], 1+dp[j]);
    				maxP = max(maxP, dp[i]);
    			}
    		}
    	}
    	sort(p.begin(),p.end(),[&](auto a, auto b){
    		return a[1] < b[1];
    	});//按体重升序
    	vector<int> dp1(n,1);
    	for(i = 1; i < n; ++i)
    	{
    		for(j = i-1; j >= 0; --j)
    		{
    			if(p[i][0] > p[j][0])
    			{
    				dp1[i] = max(dp1[i], 1+dp1[j]);
    				maxP = max(maxP, dp1[i]);
    			}
    		}
    	}
    	return maxP;
    }
};

2.2 二分查找

  • 思路:对一个变量排序,第一个变量相等的时候,第二个变量降序排列(一会求第二个变量的最长上升子序,避免第一个变量相等也取进去)
  • 然后dp[i] 表示长度为 i 的上升子序的 序列最后一个数的最小值(采用二分查找,找到第一个大于等于 target 的)
代码语言:javascript
复制
class Solution {
public:
    int bestSeqAtIndex(vector<int>& height, vector<int>& weight) {
    	int i, idx=0, n = height.size();
    	vector<pair<int,int>> p(n);
    	for(i = 0; i < n; ++i)
    		p[i] = {height[i], weight[i]};
    	sort(p.begin(),p.end(),[](auto a, auto b){
            if(a.first==b.first)
                return a.second > b.second;
                //升高一样,降序,避免选择上升子序时把他们同时选上
            return a.first < b.first;
        });//按身高升序
    	vector<int> dp(n);
    	for(i = 0; i < n; ++i)
    	{
            auto it = lower_bound(dp.begin(),dp.begin()+idx,p[i].second);
            //二分查找求体重的最长上升子序
            *it = p[i].second;
            if(it-dp.begin()==idx)
                idx++;
    	}
    	return idx;
    }
};

404 ms 46.3 MB

  • 自己编写二分查找
代码语言:javascript
复制
class Solution {
public:
    int bestSeqAtIndex(vector<int>& height, vector<int>& weight) {
    	int i, j, len=1, n = height.size();
    	vector<pair<int,int>> p(n);
    	for(i = 0; i < n; ++i)
    		p[i] = {height[i], weight[i]};
    	sort(p.begin(),p.end(),[](auto a, auto b){
            if(a.first==b.first)
                return a.second > b.second;
                //升高一样,降序,避免选择上升子序时把他们同时选上
            return a.first < b.first;
        });//按身高升序
    	vector<int> dp(n);
        dp[0] = p[0].second;
    	for(i = 1; i < n; ++i)
    	{
            j = bs(dp,0,len-1,len,p[i].second);//二分查找求体重的最长上升子序
            dp[j] = p[i].second;
            if(j == len)
                len++;
    	}
    	return len;
    }
    int bs(vector<int>& dp, int l, int r, int len, int target)
    {   //第一个 大于等于 我的
        int mid;
        while(l <= r)
        {
            mid = l+((r-l)>>1);
            if(dp[mid] >= target)
            {
                if(mid==0 || dp[mid-1] < target)
                    return mid;
                else
                    r = mid-1;
            }
            else// if(dp[mid] < target)
                l = mid+1;
        }
        return len;//没有找打,说明它是最大的
    }
};

264 ms 46.5 MB

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-04-07 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 题目
  • 2. 解题
    • 2.1 超时解
      • 2.2 二分查找
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档