最长递增子序列——系列题
Posted ych9527
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最长递增子序列——系列题相关的知识,希望对你有一定的参考价值。
最长子序列求解基础题
堆箱子
堆箱子。给你一堆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.这里和求最长递增子序列的模板一样,同样使用二分法进行优化处理
注意:
当身高相同的时候,体重有可能出现相同的情况 ->在排序时,身高相同的情况下,体重排降序
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();
}
};
以上是关于最长递增子序列——系列题的主要内容,如果未能解决你的问题,请参考以下文章