LeetCode 978中等动态规划
最长湍流子数组 图解题解
这道题到底在问什么
给定整数数组 arr,返回最长湍流子数组的长度。湍流子数组指的是:它内部每相邻一对的比较符号都和前一对相反,严格地一升一降交替。
- 输入
- arr=[9,4,2,10,7,8,8,1,9]
- 输出
- 5 (4 大 2 小 10 大 7 小 8,比较符交替)
- 输入
- arr=[4,8,12,16]
- 输出
- 2 (一路上升不翻转,最多取相邻两个)
- 输入
- arr=[100]
- 输出
- 1 (单个元素自成一段)
最优解:一步一步想明白
- 3记住这套「升就 up 接旧 down、降就 down 接旧 up、相等全归 1,每步刷新答案」,下面每一帧都在套它。
- 4开局:第 0 个元素 9 自己就是一段长度 1 的湍流段(绿色)。up 和 down 都初始化成 1,从第 1 个起才有「前一个」可比。
- 5扫到第 1 个 4,和前一个 9 比。绿色是到上一个为止还在生长的湍流段(长度 1),此刻 up=1、down=1。看着是下降,下一帧看 down 怎么接。
- 64 比 9 小,这一步是下降。反过来,新的 down 接在「上一个结尾是上升」的段后面:down = 旧 up + 1 = 2;up 归 1。刷新答案 ans=2。
- 7扫到第 2 个 2,和前一个 4 比。绿色是到上一个为止还在生长的湍流段(长度 2),此刻 up=1、down=2。看着是下降,下一帧看 down 怎么接。
- 82 比 4 小,这一步是下降。反过来,新的 down 接在「上一个结尾是上升」的段后面:down = 旧 up + 1 = 2;up 归 1。还没超过 ans=2,答案不动。
- 9扫到第 3 个 10,和前一个 2 比。绿色是到上一个为止还在生长的湍流段(长度 2),此刻 up=1、down=2。看着是上升,下一帧看 up 怎么接。
- 1010 比 2 大,这一步是上升。湍流要交替,所以新的 up 接在「上一个结尾是下降」的段后面:up = 旧 down + 1 = 3;同向接不上的 down 归 1。这个 3 比旧答案大,刷新 ans=3。
- 11扫到第 4 个 7,和前一个 10 比。绿色是到上一个为止还在生长的湍流段(长度 3),此刻 up=3、down=1。看着是下降,下一帧看 down 怎么接。
- 127 比 10 小,这一步是下降。反过来,新的 down 接在「上一个结尾是上升」的段后面:down = 旧 up + 1 = 4;up 归 1。刷新答案 ans=4。
- 13扫到第 5 个 8,和前一个 7 比。绿色是到上一个为止还在生长的湍流段(长度 4),此刻 up=1、down=4。看着是上升,下一帧看 up 怎么接。
- 148 比 7 大,这一步是上升。湍流要交替,所以新的 up 接在「上一个结尾是下降」的段后面:up = 旧 down + 1 = 5;同向接不上的 down 归 1。这个 5 比旧答案大,刷新 ans=5。
- 15扫到第 6 个 8,和前一个 8 比。绿色是到上一个为止还在生长的湍流段(长度 5),此刻 up=5、down=1。两个数一样大,怕是要断,下一帧见分晓。
- 168 和 8 一样大,既不算上升也不算下降,湍流彻底断在这里。up 和 down 同时归 1,从第 6 个重新数。注意 ans 仍保留着 5,断开只清空当前段,绝不抹掉历史最长。
- 17扫到第 7 个 1,和前一个 8 比。绿色是到上一个为止还在生长的湍流段(长度 1),此刻 up=1、down=1。看着是下降,下一帧看 down 怎么接。
- 181 比 8 小,这一步是下降。反过来,新的 down 接在「上一个结尾是上升」的段后面:down = 旧 up + 1 = 2;up 归 1。还没超过 ans=5,答案不动。
- 19全部扫完。一路上 up 和 down 此消彼长,最长的一段湍流是高亮的这 5 个:4、2、10、7、8,比较符大、小、大、小完整交替。后面 8、8 相等把湍流打断,所以没能更长。答案 5。
- 20回放这段赢家,看比较符怎么一步步翻转。先单看第 1 个 4,长度 1。
- 214 到 2 是下降,比较符是「大」,和前一对正式开头,交替成立,长度到 2。
- 222 到 10 是上升,比较符是「小」,和前一对正好相反,交替成立,长度到 3。
- 2310 到 7 是下降,比较符是「大」,和前一对正好相反,交替成立,长度到 4。
- 247 到 8 是上升,比较符是「小」,和前一对正好相反,交替成立,长度到 5。比较符一路 大、小、大、小 交替,五个元素,答案就是 5。
⚠️ 容易写错的地方
✗ 错:相等也想往下接
✓ 对:相等时 up、down 同时归 1
湍流要严格升降交替,8、8 相等直接打断,接不上
✗ 错:方向接反:上升去接旧 up
✓ 对:上升接旧 down,下降接旧 up
要交替,所以上升必须续在「上一步是下降」的段后面,接反就不是湍流了
✗ 错:ans 初值写成 0
✓ 对:ans 初值是 1
单个元素本身就是长度 1 的湍流段,初值 0 会让单元素答案错成 0
完整代码(Python / C++ / Java)
Python
from __future__ import annotations
from typing import *
from collections import *
from functools import *
from itertools import *
from math import *
from heapq import *
from bisect import *
class Solution:
def maxTurbulenceSize(self, arr: List[int]) -> int:
ans = f = g = 1
for a, b in pairwise(arr):
ff = g + 1 if a < b else 1
gg = f + 1 if a > b else 1
f, g = ff, gg
ans = max(ans, f, g)
return ansC++
#include <algorithm>
#include <array>
#include <cctype>
#include <climits>
#include <cmath>
#include <deque>
#include <functional>
#include <iostream>
#include <limits>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
using namespace std;
class Solution {
public:
int maxTurbulenceSize(vector<int>& arr) {
int ans = 1, f = 1, g = 1;
for (int i = 1; i < arr.size(); ++i) {
int ff = arr[i - 1] < arr[i] ? g + 1 : 1;
int gg = arr[i - 1] > arr[i] ? f + 1 : 1;
f = ff;
g = gg;
ans = max({ans, f, g});
}
return ans;
}
};Java
import java.util.*;
class Solution {
public int maxTurbulenceSize(int[] arr) {
int ans = 1, f = 1, g = 1;
for (int i = 1; i < arr.length; ++i) {
int ff = arr[i - 1] < arr[i] ? g + 1 : 1;
int gg = arr[i - 1] > arr[i] ? f + 1 : 1;
f = ff;
g = gg;
ans = Math.max(ans, Math.max(f, g));
}
return ans;
}
}复杂度
时间
O(n)
从头到尾扫一遍,每个元素只看一次
空间
O(1)
只用 up、down、ans 三个变量,状态滚动复用
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 最长湍流子数组 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
这题和「最长连续递增子数组」(LC674)有什么区别?+
LC674 只要一味变大就行,一个 cur 就够;本题要求比较符严格交替,光记长度不够,还得记住「上一步是升还是降」,所以拆成 up、down 两个状态。两题都是一遍扫描 O(n),难点在状态多了一维。
为什么非要两个状态,一个变量行不行?+
不行。下一步能不能接上,取决于上一步的方向:上升只能接在下降后面、下降只能接在上升后面。单个变量记不住方向,必须分别记「以上升结尾」和「以下降结尾」两种段的长度,转移时交叉引用。
想听吴师兄把这道题讲给你听?
文字版和动画都随便看。开通图解算法年卡,可以听吴师兄声线把 最长湍流子数组 一步步讲透(全站 0 节语音精讲,持续扩充), 卡住的地方还有 AI 私教小欧就着动画帮你拆到懂。
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。