← 返回题目列表

最长湍流子数组怎么用双指针维护交替大小关系?

中等 第 27 / 27 题 更新于 2026/07/31
双指针滑动窗口状态维护

简化版

湍流子数组要求相邻比较符号交替,比如 ><><

可以用双指针维护当前合法窗口:比较 arr[i-1]arr[i] 的符号,如果和上一段符号相反,窗口继续;否则重置左边界。

遇到相等时,湍流被打断,窗口要从当前元素重新开始。

详细版

湍流的本质是相邻差值符号交替。

遍历数组时,计算当前比较结果 cmp = sign(arr[i] - arr[i-1])

  • 如果 cmp == 0,相等不能构成湍流,left = i
  • 如果当前符号和上一个非零符号相反,窗口继续;
  • 如果符号相同,说明交替断了,新的窗口从 i - 1 开始。

每次根据当前窗口长度更新答案。

时间复杂度 O(n),空间复杂度 O(1)

完整版教学

一、什么是湍流关系

湍流子数组要求相邻元素的大小关系不断交替。例如 [9,4,2,10,7] 的比较符号是 > > < >,其中从 4,2,10,7 开始是 > < >,满足交替。重点不是数值本身,而是相邻比较结果的变化。

记忆钩子:湍流看的是比较符号在跳舞,不是元素值在变大或变小。

二、为什么相等会打断窗口

如果 arr[i] == arr[i-1],相邻比较既不是 < 也不是 >,无法加入湍流关系。包含这对相等元素的任何长度大于 1 的窗口都不合法。因此遇到相等时,左边界必须重置到当前下标 i,从当前元素重新开始。

比较结果是否可延续湍流处理方式
当前和上一个相反可以延长窗口
当前和上一个相同不可以i-1 重开
当前为相等不可以i 重开

这个分类能覆盖所有情况。

三、为什么符号相同要从 i-1 重开

如果当前比较和上一次比较方向相同,例如 arr[i-2] < arr[i-1] < arr[i],三者不能同时属于一个湍流窗口。但最后两个元素 arr[i-1]arr[i] 仍然可以作为新窗口的开始,因为它们之间存在有效大小关系。所以左边界设为 i - 1,而不是 i

1 < 3 < 5
窗口 [1,3,5] 不湍流
但 [3,5] 可以作为长度 2 的新窗口

这也是本题最容易偏一位的地方。

四、代码模板

可以这样写:

function maxTurbulenceSize(arr) {
  if (arr.length <= 1) return arr.length
  let left = 0
  let ans = 1
  let prev = 0
  for (let i = 1; i < arr.length; i++) {
    const cmp = Math.sign(arr[i] - arr[i - 1])
    if (cmp === 0) {
      left = i
    } else if (prev !== 0 && cmp === prev) {
      left = i - 1
    }
    ans = Math.max(ans, i - left + 1)
    prev = cmp
  }
  return ans
}

prev 记录上一段比较符号。相等时 prev 会变成 0,下一段非零比较可以重新开始。

五、带数字推演

数组 [9,4,2,10,7,8]

9 > 4:窗口长度 2
4 > 2:符号相同,从 4,2 重开,长度 2
2 < 10:符号相反,长度 3
10 > 7:符号相反,长度 4
7 < 8:符号相反,长度 5

最长湍流长度是 5,对应 [4,2,10,7,8]

六、常见误区与追问

  • 误区:把湍流当成单调递增或递减。 湍流要求比较方向交替,不是一直变大或一直变小。
  • 误区:符号相同时把 left 设为 i。 最后两个元素仍可组成长度 2 的新窗口,应该从 i-1 开始。
  • 误区:相等时没有重置 prev。 相等会切断关系,后续比较不能和相等前的符号相连。
  • 追问:能不能用动态规划? 可以维护以当前位置结尾的上升/下降长度,双指针写法更贴近窗口断点。
  • 追问:长度为 1 怎么处理? 单个元素默认是合法湍流子数组,答案至少为 1。

这些点说明本题考的不是模板,而是状态转移边界。

七、加强记忆

最长湍流子数组记成“比较符号要交替”。相等时彻底断开,从当前元素重开;符号连续相同时,三元素不合法,但最后两个还能作新起点,所以从 i-1 重开。每一步更新窗口长度,最终得到最长交替大小关系区间。