区间动态规划例题:最长湍流子数组问题
字数 2380 2025-10-26 09:00:43

区间动态规划例题:最长湍流子数组问题

题目描述
给定一个整数数组 arr,如果某个子数组中元素的比较符号在相邻元素之间来回翻转(即 arr[i] > arr[i+1] < arr[i+2] > ...arr[i] < arr[i+1] > arr[i+2] < ...),则称该子数组为湍流子数组。要求返回 arr 中最长湍流子数组的长度。

例如:

  • 输入:arr = [9,4,2,10,7,8,8,1,9]
    输出:5
    解释:最长湍流子数组为 [4,2,10,7,8],对应比较符号为 < > < >
  • 输入:arr = [4,8,12,16]
    输出:2
    解释:相邻元素比较符号相同(均为 <),因此最长湍流子数组长度为 2(例如 [4,8])。

解题思路
本题可通过区间动态规划状态机动态规划求解。这里采用区间动态规划的思路,定义 dp[i][j] 表示子数组 arr[i...j] 是否为湍流子数组,但直接二维 DP 会超时。更高效的方法是线性 DP,记录以每个位置结尾的最长湍流子数组长度。

步骤分解

  1. 状态定义
    up[i] 表示以 i 结尾且最后一段比较为 arr[i-1] < arr[i] 的最长湍流子数组长度。
    down[i] 表示以 i 结尾且最后一段比较为 arr[i-1] > arr[i] 的最长湍流子数组长度。

  2. 状态转移

    • arr[i-1] < arr[i]
      • up[i] = down[i-1] + 1(前一段必须是下降趋势,现在转为上升)
      • down[i] = 1(下降趋势中断,重新开始)
    • arr[i-1] > arr[i]
      • down[i] = up[i-1] + 1(前一段必须是上升趋势,现在转为下降)
      • up[i] = 1(上升趋势中断,重新开始)
    • arr[i-1] == arr[i]
      • up[i] = down[i] = 1(相等时趋势中断,长度重置为 1)
  3. 初始化
    所有位置初始长度均为 1(单个元素可视为湍流子数组)。

  4. 结果计算
    遍历过程中记录 max(up[i], down[i]) 的最大值。


示例推导
arr = [9,4,2,10,7,8,8,1,9] 为例:

i arr[i] up[i] down[i] 说明
0 9 1 1 初始化
1 4 1 2 9>4,下降趋势延续(down[1]=up[0]+1=2)
2 2 1 3 4>2,下降趋势延续(down[2]=up[1]+1=2?注意:连续下降不符合交替,应重置?)

修正:需严格交替,因此:

  • arr[i-1] > arr[i] 时,若前一段是下降趋势(即 arr[i-2] > arr[i-1]),则不能直接延续,而应重置为 2。但通过 up[i]down[i] 的定义可自动处理:
    • down[i] 依赖 up[i-1],即前一段必须是上升趋势才能延续。

正确推导:

i arr[i] 比较关系 up[i] down[i] 解释
0 9 - 1 1 初始化
1 4 9>4 (>) 1 2 down[1]=up[0]+1=2
2 2 4>2 (>) 1 1 前一段是下降,当前仍下降,重置 down[2]=1
3 10 2<10 (<) 2 1 up[3]=down[2]+1=2
4 7 10>7 (>) 1 3 down[4]=up[3]+1=3
5 8 7<8 (<) 4 1 up[5]=down[4]+1=4
6 8 8=8 (=) 1 1 相等重置
7 1 8>1 (>) 1 2 down[7]=up[6]+1=2
8 9 1<9 (<) 3 1 up[8]=down[7]+1=3

最大值在 i=5 时取得 max(4,1)=5(实际长度为 5,对应子数组 [4,2,10,7,8],索引 1~5)。


复杂度分析

  • 时间复杂度:O(n),遍历一次数组。
  • 空间复杂度:O(n),可优化至 O(1)(仅需保存前一个状态)。

代码实现(Python)

def maxTurbulenceSize(arr):
    n = len(arr)
    up, down = 1, 1
    res = 1
    for i in range(1, n):
        if arr[i] > arr[i-1]:
            up = down + 1
            down = 1
        elif arr[i] < arr[i-1]:
            down = up + 1
            up = 1
        else:
            up = down = 1
        res = max(res, up, down)
    return res

总结
本题通过定义 updown 状态,利用动态规划记录以每个位置结尾的最长湍流子数组长度,通过比较相邻元素的大小关系切换状态,最终得到全局最大值。

区间动态规划例题:最长湍流子数组问题 题目描述 给定一个整数数组 arr ,如果某个子数组中元素的比较符号在相邻元素之间来回翻转(即 arr[i] > arr[i+1] < arr[i+2] > ... 或 arr[i] < arr[i+1] > arr[i+2] < ... ),则称该子数组为 湍流子数组 。要求返回 arr 中最长湍流子数组的长度。 例如: 输入: arr = [9,4,2,10,7,8,8,1,9] 输出: 5 解释:最长湍流子数组为 [4,2,10,7,8] ,对应比较符号为 < > < > 。 输入: arr = [4,8,12,16] 输出: 2 解释:相邻元素比较符号相同(均为 < ),因此最长湍流子数组长度为 2 (例如 [4,8] )。 解题思路 本题可通过 区间动态规划 或 状态机动态规划 求解。这里采用区间动态规划的思路,定义 dp[i][j] 表示子数组 arr[i...j] 是否为湍流子数组,但直接二维 DP 会超时。更高效的方法是 线性 DP ,记录以每个位置结尾的最长湍流子数组长度。 步骤分解 状态定义 设 up[i] 表示以 i 结尾且最后一段比较为 arr[i-1] < arr[i] 的最长湍流子数组长度。 设 down[i] 表示以 i 结尾且最后一段比较为 arr[i-1] > arr[i] 的最长湍流子数组长度。 状态转移 若 arr[i-1] < arr[i] : up[i] = down[i-1] + 1 (前一段必须是下降趋势,现在转为上升) down[i] = 1 (下降趋势中断,重新开始) 若 arr[i-1] > arr[i] : down[i] = up[i-1] + 1 (前一段必须是上升趋势,现在转为下降) up[i] = 1 (上升趋势中断,重新开始) 若 arr[i-1] == arr[i] : up[i] = down[i] = 1 (相等时趋势中断,长度重置为 1) 初始化 所有位置初始长度均为 1 (单个元素可视为湍流子数组)。 结果计算 遍历过程中记录 max(up[i], down[i]) 的最大值。 示例推导 以 arr = [9,4,2,10,7,8,8,1,9] 为例: | i | arr[ i] | up[ i] | down[ i ] | 说明 | |---|--------|-------|---------|------| | 0 | 9 | 1 | 1 | 初始化 | | 1 | 4 | 1 | 2 | 9>4,下降趋势延续(down[ 1]=up[ 0 ]+1=2) | | 2 | 2 | 1 | 3 | 4>2,下降趋势延续(down[ 2]=up[ 1 ]+1=2?注意:连续下降不符合交替,应重置?) | 修正 :需严格交替,因此: 当 arr[i-1] > arr[i] 时,若前一段是下降趋势(即 arr[i-2] > arr[i-1] ),则不能直接延续,而应重置为 2 。但通过 up[i] 和 down[i] 的定义可自动处理: down[i] 依赖 up[i-1] ,即前一段必须是上升趋势才能延续。 正确推导: | i | arr[ i] | 比较关系 | up[ i] | down[ i ] | 解释 | |---|--------|--------------|-------|---------|------| | 0 | 9 | - | 1 | 1 | 初始化 | | 1 | 4 | 9>4 (>) | 1 | 2 | down[ 1]=up[ 0 ]+1=2 | | 2 | 2 | 4>2 (>) | 1 | 1 | 前一段是下降,当前仍下降,重置 down[ 2 ]=1 | | 3 | 10 | 2<10 (<) | 2 | 1 | up[ 3]=down[ 2 ]+1=2 | | 4 | 7 | 10>7 (>) | 1 | 3 | down[ 4]=up[ 3 ]+1=3 | | 5 | 8 | 7<8 (<) | 4 | 1 | up[ 5]=down[ 4 ]+1=4 | | 6 | 8 | 8=8 (=) | 1 | 1 | 相等重置 | | 7 | 1 | 8>1 (>) | 1 | 2 | down[ 7]=up[ 6 ]+1=2 | | 8 | 9 | 1<9 (<) | 3 | 1 | up[ 8]=down[ 7 ]+1=3 | 最大值在 i=5 时取得 max(4,1)=5 (实际长度为 5,对应子数组 [4,2,10,7,8] ,索引 1~5)。 复杂度分析 时间复杂度:O(n),遍历一次数组。 空间复杂度:O(n),可优化至 O(1)(仅需保存前一个状态)。 代码实现(Python) 总结 本题通过定义 up 和 down 状态,利用动态规划记录以每个位置结尾的最长湍流子数组长度,通过比较相邻元素的大小关系切换状态,最终得到全局最大值。