最长湍流子数组问题
题目描述
给定一个整数数组 arr,如果比较符号在子数组中的每个相邻元素对之间翻转,则该子数组为湍流子数组。更正式地说,对于子数组 arr[i..j]:
- 当 i <= k < j 时:
- 如果 k 是偶数,那么 arr[k] > arr[k+1] 当且仅当 arr[k+1] < arr[k+2](当 k+2 <= j)
- 如果 k 是奇数,那么 arr[k] < arr[k+1] 当且仅当 arr[k+1] > arr[k+2](当 k+2 <= j)
或者另一种等价定义是:湍流子数组中,元素的大小关系交替变化(即 >, <, >, <, ... 或 <, >, <, >, ...)。
求 arr 中最长湍流子数组的长度。
解题过程
-
问题理解与重新表述
湍流子数组要求相邻元素的大小关系必须交替变化。例如,对于子数组 [a, b, c]:- 如果 a > b,则必须 b < c
- 如果 a < b,则必须 b > c
- 如果 a = b,则这个子数组不可能是湍流的(因为大小关系没有变化)
我们可以将问题重新表述为:找到最长的连续子数组,其中每个相邻三元组 (arr[i], arr[i+1], arr[i+2]) 都满足湍流条件。
-
动态规划状态定义
我们可以定义两个状态数组:up[i]:表示以位置 i 结尾,且 arr[i] > arr[i-1] 的最长湍流子数组长度down[i]:表示以位置 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] = 1down[i] = 1
初始条件:对于 i = 0,
up[0] = 1,down[0] = 1(单个元素可以视为长度为1的湍流子数组) - 如果 arr[i] > arr[i-1]:
-
计算过程示例
假设 arr = [9, 4, 2, 10, 7, 8, 8, 1, 9]i=0: up=1, down=1, max_len=1
i=1: 9>4? 否;9<4? 否;9=4? 否 → 4<9? 是 → 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最终结果为6,对应子数组 [4, 2, 10, 7, 8, 8] 不满足,应该是 [4, 2, 10, 7, 8] 长度为5?让我们检查:
实际正确的最长湍流子数组是 [4, 2, 10, 7, 8] 或 [2, 10, 7, 8, 1, 9],长度应该是5?让我重新计算...等等,我发现了错误。让我重新分析:
正确的计算应该是:
arr = [9, 4, 2, 10, 7, 8, 8, 1, 9]i=0: up=1, down=1, max=1
i=1: 9>4 → up[1]=down[0]+1=2, down[1]=1, max=2
i=2: 4>2 → up[2]=down[1]+1=2, down[2]=1, max=2
i=3: 2<10 → down[3]=up[2]+1=3, up[3]=1, max=3
i=4: 10>7 → up[4]=down[3]+1=4, down[4]=1, max=4
i=5: 7<8 → down[5]=up[4]+1=5, up[5]=1, max=5
i=6: 8=8 → up[6]=1, down[6]=1, max=5
i=7: 8>1 → up[7]=down[6]+1=2, down[7]=1, max=5
i=8: 1<9 → down[8]=up[7]+1=3, up[8]=1, max=5正确结果是5,对应子数组 [4, 2, 10, 7, 8] 或 [2, 10, 7, 8, 1, 9]?等等,[2, 10, 7, 8, 1, 9] 长度是6,让我验证:
2<10, 10>7, 7<8, 8>1, 1<9 ✓ 确实是湍流子数组,长度为6我意识到我的计算有误。让我重新仔细计算:
对于 i=2: arr[2]=2, arr[1]=4 → 4>2 ✓
但 up[2] 应该 = down[1]+1,而 down[1] 是多少?让我一步步来:
i=0: up=1, down=1
i=1: arr[1]=4, arr[0]=9 → 9>4 ✓ → up[1]=down[0]+1=2, down[1]=1
i=2: arr[2]=2, arr[1]=4 → 4>2 ✓ → up[2]=down[1]+1=2, down[2]=1
i=3: arr[3]=10, arr[2]=2 → 2<10 ✓ → down[3]=up[2]+1=3, up[3]=1
i=4: arr[4]=7, arr[3]=10 → 10>7 ✓ → up[4]=down[3]+1=4, down[4]=1
i=5: arr[5]=8, arr[4]=7 → 7<8 ✓ → down[5]=up[4]+1=5, up[5]=1
i=6: arr[6]=8, arr[5]=8 → 相等 → up[6]=1, down[6]=1
i=7: arr[7]=1, arr[6]=8 → 8>1 ✓ → up[7]=down[6]+1=2, down[7]=1
i=8: arr[8]=9, arr[7]=1 → 1<9 ✓ → down[8]=up[7]+1=3, up[8]=1最大值出现在 i=5,值为5。但 [2,10,7,8,1,9] 长度是6,说明我的状态定义或计算有误。
-
修正状态定义
我意识到问题:我的状态定义只考虑了相邻两个元素的关系,但湍流子数组需要交替变化。让我修正方法。更准确的方法是:定义 dp[i] 表示以 i 结尾的最长湍流子数组长度。
我们需要比较 arr[i] 与 arr[i-1] 的关系,以及 arr[i-1] 与 arr[i-2] 的关系。正确的状态转移:
- 如果 (arr[i] > arr[i-1] 且 arr[i-1] < arr[i-2]) 或 (arr[i] < arr[i-1] 且 arr[i-1] > arr[i-2]):
- dp[i] = dp[i-1] + 1
- 否则如果 arr[i] ≠ arr[i-1]:
- dp[i] = 2
- 否则:
- dp[i] = 1
- 如果 (arr[i] > arr[i-1] 且 arr[i-1] < arr[i-2]) 或 (arr[i] < arr[i-1] 且 arr[i-1] > arr[i-2]):
-
最终解决方案
经过分析,最初的双状态方法实际上是正确的,但我的计算有误。让我给出最终正确的代码逻辑:def maxTurbulenceSize(arr): if len(arr) == 1: return 1 up = [1] * len(arr) # 以i结尾,且arr[i] > arr[i-1] down = [1] * len(arr) # 以i结尾,且arr[i] < arr[i-1] max_len = 1 for i in range(1, len(arr)): if arr[i] > arr[i-1]: up[i] = down[i-1] + 1 down[i] = 1 elif arr[i] < arr[i-1]: down[i] = up[i-1] + 1 up[i] = 1 else: # arr[i] == arr[i-1] up[i] = 1 down[i] = 1 max_len = max(max_len, up[i], down[i]) return max_len对于 arr = [9,4,2,10,7,8,8,1,9],正确结果是 5(对应子数组 [4,2,10,7,8] 或 [10,7,8,1,9] 等)。