LeetCode 978. 最长湍流子数组
题目描述


题意分析
找到最长的连续子数组,使相邻大小关系严格交替:上升后必须下降,下降后必须上升。不能跳过元素;相等会中断交替。单个元素没有比较关系,也视为长度 1 的合法子数组。
解法:末步方向动态规划
核心思路
[!blue]
能否把当前元素接到前面的湍流段,只取决于前一段最后一次比较的方向。用
up、down分别记录以当前位置结尾、最后一步上升或下降的最长长度。长度 1 没有方向,作为两种状态共同的起点。若
arr[i] > arr[i - 1],最后一步上升,只能接在上一个位置的下降状态后,得到up = 旧 down + 1;以当前位置结尾且长度至少为 2 的子数组不可能最后一步下降,所以down重置为 1。连续两次上升时,旧down正好为 1,自然只保留当前相邻两项组成的长度 2。若当前值更小,则对称地得到
down = 旧 up + 1,并将up重置为 1。若两值相等,任何包含这条相邻边的子数组都不合法,两个状态只能从当前单个元素重新开始,均设为 1。对同一结尾和同一方向,较长的状态一定更有利,因为它与较短状态的后续扩展条件相同。因此每个方向只保留最长长度即可。每轮还要更新全局
answer,避免之后的重置覆盖已经在前面结束的最长段。
解题步骤
- 题目保证数组非空,令
up = down = answer = 1。- 从第二项开始比较相邻元素。上升时先计算
up = down + 1,再令down = 1。- 下降时先计算
down = up + 1,再令up = 1;相等时两者都重置为 1。- 用当前
up、down更新全局最大长度。- 扫描结束返回
answer。单元素数组不进入循环,结果就是 1。
代码实现
class Solution {
public int maxTurbulenceSize(int[] arr) {
// up/down:以当前位置结尾、最后一步为升/降的最长湍流长度。
int up = 1;
int down = 1;
int answer = 1;
for (int i = 1; i < arr.length; i++) {
if (arr[i] > arr[i - 1]) {
// 本步上升,只能接在「上一步下降」的段后面。
up = down + 1;
down = 1;
} else if (arr[i] < arr[i - 1]) {
down = up + 1;
up = 1;
} else {
// 相等切断交替,两个状态都从单元素重新开始。
up = 1;
down = 1;
}
answer = Math.max(answer, Math.max(up, down));
}
return answer;
}
}
func maxTurbulenceSize(arr []int) int {
// up/down:以当前位置结尾、最后一步为升/降的最长湍流长度。
up, down := 1, 1
answer := 1
for i := 1; i < len(arr); i++ {
if arr[i] > arr[i-1] {
// 本步上升,只能接在「上一步下降」的段后面。
up = down + 1
down = 1
} else if arr[i] < arr[i-1] {
down = up + 1
up = 1
} else {
// 相等切断交替,两个状态都从单元素重新开始。
up, down = 1, 1
}
answer = max(answer, max(up, down))
}
return answer
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
复杂度分析
- 时间复杂度:$O(n)$,每对相邻元素只比较一次,每次更新常数个状态。
- 空间复杂度:$O(1)$,只保留两个结尾状态和一个全局答案。
关键点总结
[!green]
- 状态按结尾与最后方向区分,转移必须从相反方向接上。
- 长度 1 是无方向的共同起点,让新的相邻不等元素可以组成长度 2。
- 结尾状态可能缩短或重置,全局答案需要单独保存。
易错点总结
[!yellow]
- 上升继续累加旧
up,会把连续同向的比较误当成交替。- 必须先读取旧的相反方向状态,再重置它,否则会丢掉可延长的长度。
- 相等时不重置,会让子数组跨过不合法的相邻关系。
- 重置为 0 会漏算当前元素,使下一次有效比较得到的长度少一。
- 只返回最后位置的状态,会漏掉此前已经结束的更长湍流段。
相似题目
| 题目 | 难度 | 关联与区别 |
|---|---|---|
| 376. 摆动序列 | 中等 | 原题允许跳过元素形成摆动子序列,本题必须连续,比较方向不交替时要重置当前段。 |
| 674. 最长连续递增序列 | 简单 | 同样线性维护连续趋势长度,原题只接受上升,本题要求升降交替。 |
转载与许可
许可
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!