最长递增子序列——系列题

最长子序列求解基础题

堆箱子

堆箱子。给你一堆n个箱子,箱子宽 wi、深 di、高 hi。箱子不能翻转,将箱子堆起来时,下面箱子的宽度、高度和深度必须大于上面的箱子。实现一种方法,搭出最高的一堆箱子。箱堆的高度为每个箱子高度的总和。输入使用数组[wi, di, hi]表示每个箱子。

题解:

本题本质上就是一个求最长递增子序列的问题,按照任意一维排序之后,进行"最长递增子序列求解"

排序帮助我们固定了位置,然后从中挑选,如果不排序直接采用当前位置,我们就丧失了调整箱子位置的机会,即丢失了部分可能的组合,比如有箱子arr2={2,3,4},arr1={1,2,3}如果直接采用当前的位置,最大高度是4,如果调整一下最大高度为4+3=7

class Solution {
public:
    struct Less
    {
        bool operator()(vector<int> x,vector<int> y) 
        {
            return x[0]<y[0];
        }
    };
    int pileBox(vector<vector<int>>& box) {
        //具有三个维度的递增的子序列
        //选择一个维度进行排序 -> 两个维度递增的子序列
        
        sort(box.begin(),box.end(),Less());
        vector<int>dp;//表示以i位置结尾时,最长递增子序列
        int max=0;
        
        for(int i=0;i<box.size();i++)
        {
            dp.push_back(box[i][2]);
            for(int j=i-1;j>=0;j--)
            {
            	//三者都大于前面,第三个条件是为了限制第一个维度相等
                if((box[i][2]>box[j][2])&&(box[i][1]>box[j][1])&&(box[i][0]>box[j][0]))
                    dp[i]=fmax(dp[i],box[i][2]+dp[j]);
            }
            max=fmax(max,dp[i]);
        }

        return max;
    }
};

马戏团人塔

有个马戏团正在设计叠罗汉的表演节目,一个人要站在另一人的肩膀上。出于实际和美观的考虑,在上面的人要比下面的人矮一点且轻一点。已知马戏团每个人的身高和体重,请编写代码计算叠罗汉最多能叠几个人。

题解

1.利用身高对数组进行排序,将元素的位置固定之后,将问题转化为以体重为数组元素,求最长递增子序列

2.这里和求最长递增子序列的模板一样,同样使用二分法进行优化处理

注意:

当身高相同的时候,体重有可能出现相同的情况 ->在排序时,身高相同的情况下,体重排降序

image-20210630202410718

class Solution {
public:
int BinarySerach(vector<int>&arr,int num)
    {
        int left=0;
        int right=arr.size()-1;
        while(left<=right)
        {
            int mid=left+(right-left)/2;
            if(arr[mid]==num)
                return mid;
            else if(arr[mid]<num)
                left=mid+1;
            else
                right=mid-1;
        }
        return left;
    }

    struct Less
    {
        bool operator()(vector<int>&x,vector<int>&y)//不传引用超时
        {
            if(x[0]==y[0])
                return x[1]>y[1];

            return x[0]<y[0];
        }
    };
    int bestSeqAtIndex(vector<int>& height, vector<int>& weight) {
        //先将身高和体重合在一起
        vector<vector<int>> arr(height.size(),vector<int>(2,0));
        unordered_set<int> removal;
        for(int i=0;i<height.size();i++)
        {
            arr[i][0]=height[i];
            arr[i][1]=weight[i];
        }

        //对身高进行排序
        sort(arr.begin(),arr.end(),Less());

        //转化为了递增子序列
        vector<int> people;
        for(int i=0;i<arr.size();i++)
        {
            if(people.size()==0||arr[i][1]>people.back())
                people.push_back(arr[i][1]);
            else
            {
                int sub=BinarySerach(people,arr[i][1]);
                people[sub]=arr[i][1];
            }
        }
        return people.size();
    }
};

俄罗斯套娃信封问题

给你一个二维整数数组 envelopes ,其中 envelopes[i] = [wi, hi] ,表示第 i 个信封的宽度和高度。当另一个信封的宽度和高度都比这个信封大的时候,这个信封就可以放进另一个信封里,如同俄罗斯套娃一样。请计算 最多能有多少个 信封能组成一组“俄罗斯套娃”信封(即可以把一个信封放到另一个信封里面)。

题解:

和上一题是一样的,只不过上一题需要自己将两个一维数组转化为二维数组

class Solution {
public:
    int BinarySearch(vector<int>&arr,int num)
    {
        int left=0;
        int right=arr.size()-1;
        while(left<=right)
        {
            int mid=left+(right-left)/2;
            if(arr[mid]==num)
                return mid;
            else if(arr[mid]<num)
                left=mid+1;
            else
                right=mid-1;
        }
        return left;
    }

    struct Less
    {
        bool operator()(vector<int>&x,vector<int>&y)
        {
            if(x[0]==y[0])
                return x[1]>y[1];

            return x[0]<y[0];
        }
    };
    int maxEnvelopes(vector<vector<int>>& envelopes) {
        sort(envelopes.begin(),envelopes.end(),Less());

        vector<int>arr;
        for(int i=0;i<envelopes.size();i++)
        {
            if(arr.size()==0||envelopes[i][1]>arr.back())
                arr.push_back(envelopes[i][1]);
            else
            {
                int sub=BinarySearch(arr,envelopes[i][1]);
                arr[sub]=envelopes[i][1];
            }
        }
        return arr.size();
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值