Problem: 376. 摆动序列
1. 状态表示
这里我们选择比较常用的方式,以某个位置为结尾,结合题目要求,定义一个状态表示:
dp[i]表示:以 i 位置为结尾的最长摆动序列的长度
但是,问题来了,如果状态表示这样定义的话,以 i
位置为结尾的最⻓摆动序列的⻓度我们没法从之前的状态推导出来。因为我们不知道前⼀个最长摆动序列的结尾处是递增的,还是递减的。因此,我们需要状态表⽰能表⽰多⼀点的信息:要能让我们知道这⼀个最⻓摆动序列的结尾是递增的还是递减的。
解决办法:搞两个 dp
表
f[i]
表⽰:以 i
位置元素为结尾的所有的子序列中,最后⼀个位置呈现「上升趋势」的最长摆动序列的长度;
g[i]
表⽰:以 i
位置元素为结尾的所有的子序列中,最后⼀个位置呈现「下降趋势」的最长摆动序列的长度。
2. 状态转移方程
由于子序列的构成比较特殊, i
位置为结尾的子序列,前一个位置可以是 [0, i - 1]
的任意位置,因此设 j
为 [0, i - 1]
区间内的某一个位置。
对于 f[i] ,我们可以根据「子序列的构成方式」,进⾏分类讨论:
1. 子序列长度为 1: 只能自己和自己玩了,此时 f[i] = 1;
2. 子序列长度大于 1:因为结尾要呈现上升趋势,因此需要 nums[j] < nums[i]。在满足这个条件下 j 结尾需要呈现下降状态,最长摆动序列就是 g[j] + 1
因此,我们要找出所有满足条件下的最大的 g[j] + 1。
综上所述,f[i] = max(g[j] + 1, f[i])
对于 g[i] ,我们可以根据「子序列的构成方式」,进⾏分类讨论:
1. 子序列长度为 1: 只能自己和自己玩了,此时 g[i] = 1;
2. 子序列长度大于 1:因为结尾要呈现下降趋势,因此需要 nums[j] > nums[i]。在满足这个条件下 j 结尾需要呈现上升状态,最长摆动序列就是 f[j] + 1
因此,我们要找出所有满足条件下的最大的 f[j] + 1。
综上所述,g[i] = max(f[j] + 1, g[i])
3. 初始化
所有的元素「单独」都能构成⼀个摆动序列,因此可以将 dp 表内所有元素初始化为 1 。
4. 填表顺序
毫无疑问「从左往右」
。
5. 返回结果
应该返回「两个dp
表⾥⾯的最⼤值」,我们可以在填表的时候,顺便更新⼀个「最⼤值」。
6. 复杂度分析
时间复杂度上,嵌套了两层循环,所以时间复杂度是 O ( n 2 ) O(n^2) O(n2)
空间复杂度上,用了两个额外的 dp 表,所以空间复杂度是 O ( n ) O(n) O(n)
7. Code
7.1 C++代码
class Solution {
public:
int wiggleMaxLength(vector<int>& nums) {
// 1. 创建 dp 表
// 2. 初始化
// 3. 填表
// 4. 返回结果
// f[i]: 表示以 i 位置为结尾的所有子序列中,最后一个位置呈现 "上升" 趋势的最长摆动序列的长度
// g[i]: 表示以 i 位置为结尾的所有子序列中,最后一个位置呈现 "下降" 趋势的最长摆动序列的长度
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[j] < nums[i]) f[i] = max(g[j] + 1, f[i]);
else if(nums[j] > nums[i]) g[i] = max(f[j] + 1, g[i]);
}
ret = max(ret, max(f[i], g[i]));
}
return ret;
}
};
7.2 java代码
class Solution {
public int wiggleMaxLength(int[] nums) {
// 1. 创建 dp 表
// 2. 初始化
// 3. 填表
// 4. 返回值
int n = nums.length;
int[] f = new int[n];
int[] g = new int[n];
for (int i = 0; i < n; i++)
g[i] = f[i] = 1;
int ret = 1;
for (int i = 1; i < n; i++) {
for (int j = 0; j < i; j++) {
if (nums[j] < nums[i])
f[i] = Math.max(g[j] + 1, f[i]);
else if (nums[j] > nums[i])
g[i] = Math.max(f[j] + 1, g[i]);
}
ret = Math.max(ret, Math.max(f[i], g[i]));
}
return ret;
}
}