动态规划题目中,常出现子序列相关问题,这里单独挑出来训练
注意:子序列与子数组不同,子数组要求的是原数组中连续的一部分,而子序列要的是原数组以原排列方式,抽取一部分
1.最长递增子序列
给你一个整数数组 nums
,找到其中最长严格递增子序列的长度。
子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7]
是数组 [0,3,1,6,2,2,7]
的子序列
1.状态表示:用dp[ i ]表示选到第i个元素的子序列的最长递增长度
2.状态转移方程:dp[ i ] = dp[ j ] + 1
3.初始化:全初始化为1
4.填表顺序:从左往右填
5.返回值:dp表中最大值
class Solution {
public:
int lengthOfLIS(vector<int>& nums)
{
int n = nums.size();
vector<int> dp(n, 1);
int ret = 1;
for(int i = 1; i < n; ++i)
{
for(int j = 0; j < i; ++j)
if(nums[i] > nums[j])
dp[i] = max(dp[i], dp[j] + 1);
ret = max(ret, dp[i]);
}
return ret;
}
};
这是ac代码
2.摆动序列
如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为 摆动序列 。第一个差(如果存在的话)可能是正数或负数。仅有一个元素或者含两个不等元素的序列也视作摆动序列
给你一个整数数组 nums
,返回 nums
中作为 摆动序列 的 最长子序列的长度
1.状态表示:用 f [ i ]表示选到第i个元素的子序列以大结尾的最长摆动序列长度
用 g [ i ]表示选到第i个元素的子序列以小结尾的最长摆动序列长度
2.状态转移方程:
f[ i ] = g [ j ] + 1
g[ i ] = f [ j ] + 1
3.初始化:全初始化为1
4.填表顺序:从左往右两个表一起填
5.返回值:两个表中的最大值
class Solution {
public:
int wiggleMaxLength(vector<int>& nums)
{
int n = nums.size();
vector<int> f(n, 1), g(n, 1);
int ret = 1;
for(int i = 1; i < n; ++i)
{
for(int j = 0; j < i; ++j)
{
if(nums[i] > nums[j])
f[i] = max(f[i], g[j] + 1);
if(nums[i] < nums[j])
g[i] = max(g[i], f[j] + 1);
}
ret = max(ret, max(f[i], g[i]));
}
return ret;
}
};
这是ac代码