区间动态规划例题:最长湍流子数组问题(最大长度)
字数 1672 2025-11-27 19:03:47

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

题目描述:
给定一个整数数组arr,如果连续子数组arr[i..j]满足:对于每个相邻元素对,比较符号在大于和小于之间交替出现,那么该子数组称为湍流子数组。更形式化地说,当索引k满足i ≤ k < j时:

  • 如果k是偶数,arr[k] > arr[k+1],且当k是奇数时,arr[k] < arr[k+1];或者
  • 如果k是偶数,arr[k] < arr[k+1],且当k是奇数时,arr[k] > arr[k+1]

请找出arr中最长湍流子数组的长度。

解题过程:

  1. 问题分析:
    湍流子数组要求相邻元素的比较关系交替变化。我们需要找到一个连续子数组,其中元素的大小关系按照"大-小-大-小..."或"小-大-小-大..."的模式交替排列。

  2. 状态定义:
    定义dp[i]表示以第i个元素结尾的最长湍流子数组的长度。但这样定义不够,因为我们还需要知道当前是处于上升趋势还是下降趋势。

更好的方法是定义两个状态数组:

  • up[i]: 以arr[i]结尾,且arr[i] > arr[i-1]的最长湍流子数组长度
  • down[i]: 以arr[i]结尾,且arr[i] < arr[i-1]的最长湍流子数组长度
  1. 状态转移方程:
    对于每个位置i(i ≥ 1):
  • 如果arr[i] > arr[i-1],说明当前是上升趋势:

    • up[i] = down[i-1] + 1 // 接在下降趋势后面
    • down[i] = 1 // 下降趋势重置为1(只包含当前元素)
  • 如果arr[i] < arr[i-1],说明当前是下降趋势:

    • down[i] = up[i-1] + 1 // 接在上升趋势后面
    • up[i] = 1 // 上升趋势重置为1
  • 如果arr[i] == arr[i-1],两个趋势都重置:

    • up[i] = 1
    • down[i] = 1
  1. 初始条件:
    对于第一个元素(i = 0):
  • up[0] = 1 // 单个元素可以看作长度为1的湍流子数组
  • down[0] = 1
  1. 计算过程示例:
    以arr = [9,4,2,10,7,8,8,1,9]为例:

i=0: up[0]=1, down[0]=1, max_len=1
i=1: 9>4? 否;9<4? 是 → down[1]=up[0]+1=2, up[1]=1, max_len=2
i=2: 4>2? 是 → up[2]=down[1]+1=3, down[2]=1, max_len=3
i=3: 2<10? 是 → down[3]=up[2]+1=4, up[3]=1, max_len=4
i=4: 10>7? 是 → up[4]=down[3]+1=5, down[4]=1, max_len=5
i=5: 7<8? 是 → down[5]=up[4]+1=6, up[5]=1, max_len=6
i=6: 8=8? 是 → up[6]=1, down[6]=1, max_len=6
i=7: 8>1? 是 → up[7]=down[6]+1=2, down[7]=1, max_len=6
i=8: 1<9? 是 → down[8]=up[7]+1=3, up[8]=1, max_len=6

  1. 空间优化:
    由于每个状态只依赖于前一个状态,我们可以用变量代替数组:
  • up_prev, down_prev: 前一个位置的up和down值
  • up_curr, down_curr: 当前位置的up和down值
  • max_len: 记录最大值
  1. 算法实现:
def maxTurbulenceSize(arr):
    n = len(arr)
    if n == 1:
        return 1
    
    up = down = 1
    max_len = 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
        
        max_len = max(max_len, up, down)
    
    return max_len
  1. 复杂度分析:
  • 时间复杂度:O(n),只需遍历数组一次
  • 空间复杂度:O(1),只使用了常数级别的额外空间

这个解法通过维护上升和下降两种状态,巧妙地捕捉了湍流子数组的交替特性,是区间动态规划思想的典型应用。

区间动态规划例题:最长湍流子数组问题(最大长度) 题目描述: 给定一个整数数组arr,如果连续子数组arr[ i..j]满足:对于每个相邻元素对,比较符号在大于和小于之间交替出现,那么该子数组称为湍流子数组。更形式化地说,当索引k满足i ≤ k < j时: 如果k是偶数,arr[ k] > arr[ k+1],且当k是奇数时,arr[ k] < arr[ k+1 ];或者 如果k是偶数,arr[ k] < arr[ k+1],且当k是奇数时,arr[ k] > arr[ k+1 ] 请找出arr中最长湍流子数组的长度。 解题过程: 问题分析: 湍流子数组要求相邻元素的比较关系交替变化。我们需要找到一个连续子数组,其中元素的大小关系按照"大-小-大-小..."或"小-大-小-大..."的模式交替排列。 状态定义: 定义dp[ i ]表示以第i个元素结尾的最长湍流子数组的长度。但这样定义不够,因为我们还需要知道当前是处于上升趋势还是下降趋势。 更好的方法是定义两个状态数组: up[ i]: 以arr[ i]结尾,且arr[ i] > arr[ i-1 ]的最长湍流子数组长度 down[ i]: 以arr[ i]结尾,且arr[ i] < arr[ i-1 ]的最长湍流子数组长度 状态转移方程: 对于每个位置i(i ≥ 1): 如果arr[ i] > arr[ i-1 ],说明当前是上升趋势: up[ i] = down[ i-1 ] + 1 // 接在下降趋势后面 down[ i ] = 1 // 下降趋势重置为1(只包含当前元素) 如果arr[ i] < arr[ i-1 ],说明当前是下降趋势: down[ i] = up[ i-1 ] + 1 // 接在上升趋势后面 up[ i ] = 1 // 上升趋势重置为1 如果arr[ i] == arr[ i-1 ],两个趋势都重置: up[ i ] = 1 down[ i ] = 1 初始条件: 对于第一个元素(i = 0): up[ 0 ] = 1 // 单个元素可以看作长度为1的湍流子数组 down[ 0 ] = 1 计算过程示例: 以arr = [ 9,4,2,10,7,8,8,1,9 ]为例: i=0: up[ 0]=1, down[ 0]=1, max_ len=1 i=1: 9>4? 否;9<4? 是 → down[ 1]=up[ 0]+1=2, up[ 1]=1, max_ len=2 i=2: 4>2? 是 → up[ 2]=down[ 1]+1=3, down[ 2]=1, max_ len=3 i=3: 2<10? 是 → down[ 3]=up[ 2]+1=4, up[ 3]=1, max_ len=4 i=4: 10>7? 是 → up[ 4]=down[ 3]+1=5, down[ 4]=1, max_ len=5 i=5: 7<8? 是 → down[ 5]=up[ 4]+1=6, up[ 5]=1, max_ len=6 i=6: 8=8? 是 → up[ 6]=1, down[ 6]=1, max_ len=6 i=7: 8>1? 是 → up[ 7]=down[ 6]+1=2, down[ 7]=1, max_ len=6 i=8: 1<9? 是 → down[ 8]=up[ 7]+1=3, up[ 8]=1, max_ len=6 空间优化: 由于每个状态只依赖于前一个状态,我们可以用变量代替数组: up_ prev, down_ prev: 前一个位置的up和down值 up_ curr, down_ curr: 当前位置的up和down值 max_ len: 记录最大值 算法实现: 复杂度分析: 时间复杂度:O(n),只需遍历数组一次 空间复杂度:O(1),只使用了常数级别的额外空间 这个解法通过维护上升和下降两种状态,巧妙地捕捉了湍流子数组的交替特性,是区间动态规划思想的典型应用。