300.最长递增子序列 | 354.俄罗斯套娃信封问题 | 1691. 堆叠长方体的最大高度

300.最长递增子序列

给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。

子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。


示例 1:

输入:nums = [10,9,2,5,3,7,101,18]
输出:4
解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。
示例 2:

输入:nums = [0,1,0,3,2,3]
输出:4
示例 3:

输入:nums = [7,7,7,7,7,7,7]
输出:1

思路:动态规划,dp数组 

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) 
    {
        //dp数组定义:dp[i]代表以nums[i]结尾的最长递增子序列的长度
        vector<int> dp(nums.size(),1);//base case:全部初始化为1
        for(int i=0;i<nums.size();i++)
        {
            for(int j=0;j<i;j++)//寻找nums数组中,在num[i]前面且比nums[i]小的元素
            {
                //把nums[i]接在它后面,即可形成长度为dp[j]+1且以nums[i]为结尾的递增子序列
                if(nums[i]>nums[j])
                    dp[i]=max(dp[i],dp[j]+1);
            }
        }
        int res=0;
        for(int i:dp)//找到最大递增子序列
        {
            res=max(res,i);
        }
        return res;
    }
};

 354.俄罗斯套娃信封问题

给你一个二维整数数组 envelopes ,其中 envelopes[i] = [wi, hi] ,表示第 i 个信封的宽度和高度。

当另一个信封的宽度和高度都比这个信封大的时候,这个信封就可以放进另一个信封里,如同俄罗斯套娃一样。

请计算 最多能有多少个 信封能组成一组“俄罗斯套娃”信封(即可以把一个信封放到另一个信封里面)。

注意:不允许旋转信封


示例 1:

输入:envelopes = [[5,4],[6,4],[6,7],[2,3]]
输出:3
解释:最多信封的个数为 3, 组合为: [2,3] => [5,4] => [6,7]。
示例 2:

输入:envelopes = [[1,1],[1,1],[1,1]]
输出:1

思路:二维的最长递增子序列

信封有长宽两个维度,首先以信封的第一条边升序排序,保证可以嵌套,解决第一个维度。

然后在第二条边上,求最长递增子序列,解决第二个维度!

//本题要求不能旋转,所以按如下解法
//如果可以旋转,需要先旋转使每一封信的宽小于高(或者高小于宽),再按如下解法做
//可以旋转之后,其实就类似于摞书,需要先把书都转成一个方向,再从大到小往上摞 
class Solution
{
public:
    static bool cmp(vector<int> a,vector<int> b)
    {
        if(a[0]<b[0])//按width升序排,保证了宽度这个维度上可以互相嵌套
        return true;
        //因为两个w相同的信封不能嵌套
        //所以对于宽度相同的信封,对高度进行降序排序
        //保证最长递增子序列中不存在多个宽度相同的信封
        else if(a[0]==b[0])
        return a[1]>b[1];
        else
        return false;
    }
    int maxEnvelopes(vector<vector<int>>& envelopes) 
    {
        sort(envelopes.begin(),envelopes.end(),cmp);
        int res=0;
        vector<int> dp(envelopes.size(),1);
        for(int i=0;i<envelopes.size();i++)//对高度数组寻找最长递增子序列
        {
            for(int j=0;j<i;j++)
            {
                if(envelopes[i][1]>envelopes[j][1])
                    dp[i]=max(dp[i],dp[j]+1);
            }
        } 
        for(int i:dp)
        {
            res=max(res,i);
        }
        return res;
    }
};

1691. 堆叠长方体的最大高度

给你 n 个长方体 cuboids ,其中第 i 个长方体的长宽高表示为 cuboids[i] = [widthi, lengthi, heighti]下标从 0 开始)。请你从 cuboids 选出一个 子集 ,并将它们堆叠起来。

如果 widthi <= widthj 且 lengthi <= lengthj 且 heighti <= heightj ,你就可以将长方体 i 堆叠在长方体 j 上。你可以通过旋转把长方体的长宽高重新排列,以将它放在另一个长方体上。

返回 堆叠长方体 cuboids 可以得到的 最大高度 。

示例 1:

输入:cuboids = [[50,45,20],[95,37,53],[45,23,12]]
输出:190
解释:
第 1 个长方体放在底部,53x37 的一面朝下,高度为 95 。
第 0 个长方体放在中间,45x20 的一面朝下,高度为 50 。
第 2 个长方体放在上面,23x12 的一面朝下,高度为 45 。
总高度是 95 + 50 + 45 = 190 。

示例 2:

输入:cuboids = [[38,25,45],[76,35,3]]
输出:76
解释:
无法将任何长方体放在另一个上面。
选择第 1 个长方体然后旋转它,使 35x3 的一面朝下,其高度为 76 。

示例 3:

输入:cuboids = [[7,11,17],[7,17,11],[11,7,17],[11,17,7],[17,7,11],[17,11,7]]
输出:102
解释:
重新排列长方体后,可以看到所有长方体的尺寸都相同。
你可以把 11x7 的一面朝下,这样它们的高度就是 17 。
堆叠长方体的最大高度为 6 * 17 = 102 。

提示:

  • n == cuboids.length
  • 1 <= n <= 100
  • 1 <= widthi, lengthi, heighti <= 100

 思路:三维的最长递增子序列问题。

要求最大高度,所以将三条边中最长的那条当高,运用贪心思想,解决一个维度;

将所有长方体以第一条边为准,从小到大排序,保证可以堆叠,解决第二个维度;

最后在所有长方体的第二条边上求最长递增子序列,解决第三个维度!

class Solution {
public:
    int maxHeight(vector<vector<int>>& cuboids) {
        int n = cuboids.size();
        //这里允许旋转,所以应该让长方体的长和宽保证cuboids[i][0]<cuboid[i][1](转到同一个方向)
        for (auto & v : cuboids)//给每一个长方体的三条边排序,将最长的那条边放在最后面当高(贪心) 
        {
            sort(v.begin(), v.end());
        }
        //按cuboid[i][0]排好序,让长方体的第一条边单调递增,保证在此方向上允许堆叠
        //默认的sort,以第一列进行排序,若相同,则以第二列升序排序,以此类推
        sort(cuboids.begin(),cuboids.end());
        int ans = 0;
        vector<int> dp(n);
        for(int i=0;i<n;i++)
        {
            dp[i]=cuboids[i][2];//base case 只有自己当底,没人堆叠上去
        }
        for (int i = 0; i < n; i++)//最长递增子序列(cuboid[i][1]) 
        {
            for (int j = 0; j < i; j++)//在[0,i]上寻找dp[i-1]的终点 
            {
                if (cuboids[j][1] <= cuboids[i][1]&&cuboids[j][2] <= cuboids[i][2]) 
                {
                    dp[i] = max(dp[i], dp[j] + cuboids[i][2]);
                }
            }
        }
        for(int x:dp)
        {
            ans=max(ans,x);
        }
        return ans;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值