基本思想:
300. 最长上升子序列 M
给定一个无序的整数数组,找到其中最长上升子序列的长度。
通用方法:
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int n = nums.size();
if (n == 0) return 0;
vector<int> dp(n,1);
for(int i = 0; i < n; i++){
for(int j = 0; j < i; j++)
if(nums[i] > nums[j])
dp[i] = max(dp[i],dp[j]+1);
}
return *max_element(dp.begin(),dp.end());
}
};
用二分查找,可以将复杂度下降到 NlogN
定义一个 tails 数组,其中 tails[i] 存储长度为 i + 1 的最长递增子序列的最后一个元素。对于一个元素 x,
- 如果它大于 tails 数组所有的值,那么把它添加到 tails 后面,表示最长递增子序列长度加 1;
- 如果 tails[i-1] < x <= tails[i],那么更新 tails[i] = x。
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int n = nums.size();
if (n == 0) return 0;
vector<int> tail(n);
int len = 0;
for(int i = 0; i < n; i++){
int l = 0,r = len;
while(l < r){
int m = l + (r-l)/2; // nums[i]插入左边
if(tail[m] >= nums[i])
r = m; // nums[i]插入右边
else l = m+1;
}
tail[l] = nums[i]; //如果大于所有的数
if(l == len) len++;
}
return len;
}
};
673. 最长递增子序列的个数
给定一个未排序的整数数组,找到最长递增子序列的个数。
在上一题的基础上增加一个记录数组:
class Solution {
public:
int findNumberOfLIS(vector<int>& nums) {
int n = nums.size();
if(n == 0) return 0;
vector<int> dp(n,1),p(n,1);//注意初始化为1
for(int i = 0; i < n; i++)
for(int j = 0; j <i; j++){
if(nums[i] > nums[j])//判断条件
if(dp[i] < dp[j]+1){
dp[i] = dp[j]+1;
p[i] = p[j];
}
else if(dp[i] == dp[j]+1)//相等等于两个支路相加
p[i]+=p[j];
}
int mm = *max_element(dp.begin(),dp.end());
int res = 0;
for(int i = 0; i < n; i++)
if(dp[i] == mm) res+= p[i];
return res;
}
};
646. 最长数对链
给出 n 个数对。 在每一个数对中,第一个数字总是比第二个数字小。
现在,我们定义一种跟随关系,当且仅当 b < c 时,数对(c, d) 才可以跟在 (a, b) 后面。我们用这种形式来构造一个数对链。
给定一个对数集合,找出能够形成的最长数对链的长度。你不需要用到所有的数对,你可以以任何顺序选择其中的一些数对来构造。
通用方法:
class Solution {
public:
int findLongestChain(vector<vector<int>>& pairs) {
sort(pairs.begin(),pairs.end());
int n = pairs.size();
vector<int> dp(n,1);
for(int i = 0; i <n; i++)
for(int j = 0; j < i; j++)
if(pairs[i][0] > pairs[j][1])
dp[i] = max(dp[i],dp[j]+1);
return *max_element(dp.begin(),dp.end());
}
};
376. 摆动序列
如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为摆动序列。第一个差(如果存在的话)可能是正数或负数。少于两个元素的序列也是摆动序列。
通用方法:
class Solution {
public:
int wiggleMaxLength(vector<int>& nums) {
int n = nums.size();
if(n == 0) return 0;
if( n <= 2) return 1;
vector<int> up(n,1),down(n,1);
for(int i = 1; i <n; i++){
for(int j = 0;j < i; j++)
if(nums[i] > nums[j])
up[i] = max(up[i],down[j]+1);
else if(nums[i] < nums[j])
down[i] = max(down[i],up[j]+1);
}
return max(up[n-1],down[n-1]);
}
};
354. 俄罗斯套娃信封问题
给定一些标记了宽度和高度的信封,宽度和高度以整数对形式 (w, h) 出现。当另一个信封的宽度和高度都比这个信封大的时候,这个信封就可以放进另一个信封里,如同俄罗斯套娃一样。
请计算最多能有多少个信封能组成一组“俄罗斯套娃”信封(即可以把一个信封放到另一个信封里面)。
通用方法:
class Solution {
public:
int maxEnvelopes(vector<vector<int>>& envelopes) {
int n = envelopes.size();
if( n== 0) return 0;
sort(envelopes.begin(),envelopes.end());
vector<int> dp(n,1);
for(int i = 0; i < n; i++)
for(int j = 0; j < i; j++){
if(envelopes[i][0] > envelopes[j][0] && envelopes[i][1] > envelopes[j][1])
dp[i] = max(dp[i],dp[j]+1);
}
return *max_element(dp.begin(),dp.end());
}
};
来源:https://www.cnblogs.com/Aliencxl/p/12313478.html
