线性动态规划:最长湍流子数组的变种——最多允许翻转一个子数组的最长湍流子数组
字数 2477 2025-11-08 20:56:05

线性动态规划:最长湍流子数组的变种——最多允许翻转一个子数组的最长湍流子数组

题目描述
给定一个整数数组 arr,我们可以选择翻转数组中的任意一个连续子数组(即反转该子数组的元素顺序),然后找出翻转后可能得到的最长湍流子数组的长度。湍流子数组的定义是:相邻元素的比较符号在子数组中交替变化(例如,arr[i] > arr[i+1] < arr[i+2] > ...arr[i] < arr[i+1] > arr[i+2] < ...)。注意:翻转操作只能执行一次,且翻转后整个数组被视为新数组。

解题过程

  1. 问题分析
    首先,在不允许翻转的情况下,最长湍流子数组可以通过动态规划求解:定义 up[i] 表示以 i 结尾且最后一段是上升(即 arr[i] > arr[i-1])的湍流子数组长度,down[i] 表示以 i 结尾且最后一段是下降(即 arr[i] < arr[i-1])的湍流子数组长度。状态转移方程为:

    • arr[i] > arr[i-1],则 up[i] = down[i-1] + 1down[i] = 1(因为不符合下降趋势,重置为1)。
    • arr[i] < arr[i-1],则 down[i] = up[i-1] + 1up[i] = 1
    • 若相等,则 up[i] = down[i] = 1

    现在允许翻转一个子数组,我们需要考虑翻转后可能连接原本不兼容的湍流段。例如,翻转可以使得两个原本独立的湍流段在连接处满足交替条件。

  2. 关键思路

    • 翻转一个子数组相当于改变局部顺序,可能将翻转区间左侧的湍流段与右侧的湍流段通过翻转后的连接点平滑衔接。
    • 考虑翻转区间 [L, R],翻转后原数组分为三部分:[0, L-1]、翻转后的 [L, R][R+1, n-1]。湍流子数组可能跨越这三部分,但核心是翻转区间两端与外部区域的连接点(即 L-1L 的新位置、RR+1 的新位置)必须满足大小关系交替。
    • 一种高效方法是预处理左右方向的湍流数组,然后枚举所有可能的连接点,检查翻转后是否可连接。
  3. 预处理数组

    • 定义 left_up[i]:从左边开始到 i,以 i 结尾且最后为上升的湍流长度。
    • 定义 left_down[i]:类似,但最后为下降。
    • 定义 right_up[i]:从右边开始到 i,以 i 开头且开头为上升的湍流长度。
    • 定义 right_down[i]:类似,但开头为下降。
      这些数组可通过左右各遍历一次数组得到,规则与原湍流DP类似。
  4. 枚举连接点
    考虑翻转区间 [L, R] 后,可能的最长湍流子数组由以下部分组成:

    • 翻转区间内部的湍流段(翻转后需重新计算,但可直接取区间长度若满足交替)。
    • 更实用的简化:枚举所有可能的分界点 i,考虑翻转区间恰好以 i 为边界的情况。例如,假设在 i 处翻转,使得 i 左侧的段与右侧的段通过翻转后的新相邻点连接。
    • 具体地,对于每个索引 i(0 ≤ i ≤ n-2),检查两种情况:
      • 情况1:翻转区间 [i, j] 使得 i-1j(翻转后原 i 位置的新值)满足关系,且 i(翻转后原 j 位置的新值)与 i+1 满足关系。但直接枚举所有 i, j 会 O(n²),需优化。
    • 优化:实际上只需考虑翻转区间长度为2或以上的影响,但可通过预处理避免枚举所有区间。更简单的方法是,对于每个 i,计算翻转 [i, i+1][i-1, i+1] 等短区间的影响,因为长翻转可视为短翻转的扩展。
  5. 状态合并与结果计算

    • 对于每个位置 i,计算不翻转时的湍流长度 max(left_up[i], left_down[i])
    • 考虑翻转 [i, i+1] 的影响:翻转后,i 的新邻居是 i+1i-1。检查 arr[i+1]arr[i-1] 的大小关系是否可与 left_up[i-1]left_down[i-1] 衔接,同时 arr[i]arr[i+2] 是否可与 right_up[i+2]right_down[i+2] 衔接。连接后的长度为 left_segment + 2 + right_segment(其中2来自翻转的相邻对)。
    • 类似地,可考虑翻转更长区间,但核心是连接点关系。为简化,我们可枚举所有可能的分界点 i,尝试将左侧湍流段与右侧湍流段通过翻转一个区间连接,并取最大值。
  6. 算法步骤
    a. 预处理 left_upleft_downright_upright_down 数组。
    b. 初始化答案 ans 为不翻转时的最大湍流长度。
    c. 对于每个索引 i 从 1 到 n-2:

    • 检查翻转 [i, i+1]:若 i-1i+1 存在且大小关系可与左侧段衔接,且 ii+2 存在且大小关系可与右侧段衔接,则更新 ans
    • 例如,若 arr[i-1] > arr[i+1],且左侧段以下降结尾(即 left_down[i-1] 有效),且 arr[i] < arr[i+2] 且右侧段以上升开头(即 right_up[i+2] 有效),则连接后长度为 left_down[i-1] + 2 + right_up[i+2]
      d. 考虑边界情况(如翻转区间在数组两端)。
      e. 返回 ans
  7. 复杂度分析
    预处理和枚举均需 O(n) 时间,空间复杂度 O(n)。该方法覆盖了翻转操作的主要受益情况,通过连接预处理段最大化长度。

总结
本题通过预处理左右方向的湍流数组,枚举可能的翻转连接点,利用动态规划思想避免直接枚举所有翻转区间,高效求解允许一次翻转后的最长湍流子数组。

线性动态规划:最长湍流子数组的变种——最多允许翻转一个子数组的最长湍流子数组 题目描述 给定一个整数数组 arr ,我们可以选择翻转数组中的任意一个连续子数组(即反转该子数组的元素顺序),然后找出翻转后可能得到的最长湍流子数组的长度。湍流子数组的定义是:相邻元素的比较符号在子数组中交替变化(例如, arr[i] > arr[i+1] < arr[i+2] > ... 或 arr[i] < arr[i+1] > arr[i+2] < ... )。注意:翻转操作只能执行一次,且翻转后整个数组被视为新数组。 解题过程 问题分析 首先,在不允许翻转的情况下,最长湍流子数组可以通过动态规划求解:定义 up[i] 表示以 i 结尾且最后一段是上升(即 arr[i] > arr[i-1] )的湍流子数组长度, down[i] 表示以 i 结尾且最后一段是下降(即 arr[i] < arr[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 。 若相等,则 up[i] = down[i] = 1 。 现在允许翻转一个子数组,我们需要考虑翻转后可能连接原本不兼容的湍流段。例如,翻转可以使得两个原本独立的湍流段在连接处满足交替条件。 关键思路 翻转一个子数组相当于改变局部顺序,可能将翻转区间左侧的湍流段与右侧的湍流段通过翻转后的连接点平滑衔接。 考虑翻转区间 [L, R] ,翻转后原数组分为三部分: [0, L-1] 、翻转后的 [L, R] 、 [R+1, n-1] 。湍流子数组可能跨越这三部分,但核心是翻转区间两端与外部区域的连接点(即 L-1 与 L 的新位置、 R 与 R+1 的新位置)必须满足大小关系交替。 一种高效方法是预处理左右方向的湍流数组,然后枚举所有可能的连接点,检查翻转后是否可连接。 预处理数组 定义 left_up[i] :从左边开始到 i ,以 i 结尾且最后为上升的湍流长度。 定义 left_down[i] :类似,但最后为下降。 定义 right_up[i] :从右边开始到 i ,以 i 开头且开头为上升的湍流长度。 定义 right_down[i] :类似,但开头为下降。 这些数组可通过左右各遍历一次数组得到,规则与原湍流DP类似。 枚举连接点 考虑翻转区间 [L, R] 后,可能的最长湍流子数组由以下部分组成: 翻转区间内部的湍流段(翻转后需重新计算,但可直接取区间长度若满足交替)。 更实用的简化:枚举所有可能的分界点 i ,考虑翻转区间恰好以 i 为边界的情况。例如,假设在 i 处翻转,使得 i 左侧的段与右侧的段通过翻转后的新相邻点连接。 具体地,对于每个索引 i (0 ≤ i ≤ n-2),检查两种情况: 情况1 :翻转区间 [i, j] 使得 i-1 与 j (翻转后原 i 位置的新值)满足关系,且 i (翻转后原 j 位置的新值)与 i+1 满足关系。但直接枚举所有 i, j 会 O(n²),需优化。 优化:实际上只需考虑翻转区间长度为2或以上的影响,但可通过预处理避免枚举所有区间。更简单的方法是,对于每个 i ,计算翻转 [i, i+1] 或 [i-1, i+1] 等短区间的影响,因为长翻转可视为短翻转的扩展。 状态合并与结果计算 对于每个位置 i ,计算不翻转时的湍流长度 max(left_up[i], left_down[i]) 。 考虑翻转 [i, i+1] 的影响:翻转后, i 的新邻居是 i+1 和 i-1 。检查 arr[i+1] 与 arr[i-1] 的大小关系是否可与 left_up[i-1] 或 left_down[i-1] 衔接,同时 arr[i] 与 arr[i+2] 是否可与 right_up[i+2] 或 right_down[i+2] 衔接。连接后的长度为 left_segment + 2 + right_segment (其中2来自翻转的相邻对)。 类似地,可考虑翻转更长区间,但核心是连接点关系。为简化,我们可枚举所有可能的分界点 i ,尝试将左侧湍流段与右侧湍流段通过翻转一个区间连接,并取最大值。 算法步骤 a. 预处理 left_up 、 left_down 、 right_up 、 right_down 数组。 b. 初始化答案 ans 为不翻转时的最大湍流长度。 c. 对于每个索引 i 从 1 到 n-2: 检查翻转 [i, i+1] :若 i-1 和 i+1 存在且大小关系可与左侧段衔接,且 i 和 i+2 存在且大小关系可与右侧段衔接,则更新 ans 。 例如,若 arr[i-1] > arr[i+1] ,且左侧段以下降结尾(即 left_down[i-1] 有效),且 arr[i] < arr[i+2] 且右侧段以上升开头(即 right_up[i+2] 有效),则连接后长度为 left_down[i-1] + 2 + right_up[i+2] 。 d. 考虑边界情况(如翻转区间在数组两端)。 e. 返回 ans 。 复杂度分析 预处理和枚举均需 O(n) 时间,空间复杂度 O(n)。该方法覆盖了翻转操作的主要受益情况,通过连接预处理段最大化长度。 总结 本题通过预处理左右方向的湍流数组,枚举可能的翻转连接点,利用动态规划思想避免直接枚举所有翻转区间,高效求解允许一次翻转后的最长湍流子数组。