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;
}
};
给你 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;
}
};