以下为力扣官方题解
题目
当 A A A 的子数组$ A[i], A[i+1], …, A[j]$ 满足下列条件时,我们称其为湍流子数组:
- 若 i < = k < j i <= k < j i<=k<j,当 k k k 为奇数时, A [ k ] > A [ k + 1 ] A[k] > A[k+1] A[k]>A[k+1],且当 k k k 为偶数时, A [ k ] < A [ k + 1 ] A[k] < A[k+1] A[k]<A[k+1];
- 若 i < = k < j i <= k < j i<=k<j,当 k k k 为偶数时, A [ k ] > A [ k + 1 ] A[k] > A[k+1] A[k]>A[k+1] ,且当 k k k 为奇数时, A [ k ] < A [ k + 1 ] A[k] < A[k+1] A[k]<A[k+1]。
也就是说,如果比较符号在子数组中的每个相邻元素对之间翻转,则该子数组是湍流子数组。
返回 A A A 的最大湍流子数组的长度。
示例1
输入: [ 9 , 4 , 2 , 10 , 7 , 8 , 8 , 1 , 9 ] [9,4,2,10,7,8,8,1,9] [9,4,2,10,7,8,8,1,9]
输出: 5 5 5
解释: ( A [ 1 ] > A [ 2 ] < A [ 3 ] > A [ 4 ] < A [ 5 ] ) (A[1] > A[2] < A[3] > A[4] < A[5]) (A[1]>A[2]<A[3]>A[4]<A[5])
示例2
输入: [ 4 , 8 , 12 , 16 ] [4,8,12,16] [4,8,12,16]
输出: 2 2 2
示例3
输入: [ 100 ] [100] [100]
输出: 1 1 1
提示
- 1 <= A.length <= 40000
- 0 <= A[i] <= 109
官方题解
思路一 滑动窗口
设数组 a r r arr arr 的长度为 n n n,窗口 [ l e f t , r i g h t ] ( 0 ≤ l e f t ≤ r i g h t ≤ n − 1 ) [left, right] (0 \le left \le right \le n-1) [left,right](0≤left≤right≤n−1) 为当前的窗口,窗口内构成了一个「湍流子数组」。随后,我们要考虑下一个窗口的位置。
根据「湍流子数组」的定义,当 0 < r i g h t < n − 1 0<right<n−1 0<right<n−1 时:
- 如果 a r r [ r i g h t − 1 ] < a r r [ r i g h t ] arr[right-1] \lt arr[right] arr[right−1]<arr[right] 且 a r r [ r i g h t ] > a r r [ r i g h t + 1 ] arr[right] \gt arr[right+1] arr[right]>arr[right+1],则 [ l e f t , r i g h t + 1 ] [left, right+1] [left,right+1] 也构成了「湍流子数组」,因此需要将 r i g h t right right 右移一个单位;
- 如果 a r r [ r i g h t − 1 ] > a r r [ r i g h t ] arr[right-1] \gt arr[right] arr[right−1]>arr[right] 且 a r r [ r i g h t ] < a r r [ r i g h t + 1 ] arr[right] \lt arr[right+1] arr[right]<arr[right+1],同理,也需要将 r i g h t right right 右移一个单位;
- 否则, [ r i g h t − 1 , r i g h t + 1 ] [right-1, right+1] [right−1,right+1] 无法构成「湍流子数组」,当 l e f t < r i g h t left \lt right left<right, [ l e f t , r i g h t + 1 ] [left, right+1] [left,right+1] 也无法构成「湍流子数组」,因此需要将 l e f t left left 移到 r i g h t right right,即令 l e f t = r i g h t left=right left=right。
此外,我们还需要特殊考虑窗口长度为 1 1 1 (即 l e f t left left 和 r i g h t right right 相等的情况):只要 a r r [ r i g h t ] ≠ a r r [ r i g h t + 1 ] arr[right] \neq arr[right+1] arr[right]=arr[right+1],就可以将 r i g h t right right 右移一个单位;否则, l e f t left left 和 r i g h t right right 都要同时右移。
代码
class Solution {
public int maxTurbulenceSize(int[] arr) {
int n = arr.length;
int ret = 1;
int left = 0, right = 0;
while (right < n - 1) {
if (left == right) {
if (arr[left] == arr[left + 1]) {
left++;
}
right++;
} else {
if (arr[right - 1] < arr[right] && arr[right] > arr[right + 1]) {
right++;
} else if (arr[right - 1] > arr[right] && arr[right] < arr[right + 1]) {
right++;
} else {
left = right;
}
}
ret = Math.max(ret, right - left + 1);
}
return ret;
}
}
复杂度分析
- 时间复杂度: O ( n ) O(n) O(n),其中 n n n 为数组的长度。窗口的左右端点最多各移动 n n n 次。
- 空间复杂度: O ( 1 ) O(1) O(1)。只需要维护常数额外空间。
思路二
也可以使用动态规划的方法计算最长湍流子数组的长度。
记 d p [ i ] [ 0 ] dp[i][0] dp[i][0] 为以 a r r [ i ] arr[i] arr[i] 结尾,且 a r r [ i − 1 ] > a r r [ i ] arr[i−1]>arr[i] arr[i−1]>arr[i] 的「湍流子数组」的最大长度; d p [ i ] [ 1 ] dp[i][1] dp[i][1] 为以 a r r [ i ] arr[i] arr[i] 结尾,且 a r r [ i − 1 ] < a r r [ i ] arr[i−1]<arr[i] arr[i−1]<arr[i] 的「湍流子数组」的最大长度。显然,以下标 0 0 0 结尾的「湍流子数组」的最大长度为 1 1 1,因此边界情况为 d p [ 0 ] [ 0 ] = d p [ 0 ] [ 1 ] = 1 dp[0][0]=dp[0][1]=1 dp[0][0]=dp[0][1]=1。
当 i > 0 i>0 i>0 时,考虑 a r r [ i − 1 ] arr[i−1] arr[i−1] 和 a r r [ i ] arr[i] arr[i] 之间的大小关系:
- 如果 a r r [ i − 1 ] > a r r [ i ] arr[i−1]>arr[i] arr[i−1]>arr[i],则如果以下标 i − 1 i-1 i−1 结尾的子数组是「湍流子数组」,应满足 i − 1 = 0 i−1=0 i−1=0,或者当 i − 1 > 0 i−1>0 i−1>0 时 a r r [ i − 2 ] < a r r [ i − 1 ] arr[i−2]<arr[i−1] arr[i−2]<arr[i−1],因此 d p [ i ] [ 0 ] = d p [ i − 1 ] [ 1 ] + 1 dp[i][0]=dp[i−1][1]+1 dp[i][0]=dp[i−1][1]+1;
- 如果 a r r [ i − 1 ] < a r r [ i ] arr[i−1]<arr[i] arr[i−1]<arr[i],则如果以下标 i − 1 i-1 i−1 结尾的子数组是「湍流子数组」,应满足 i − 1 = 0 i−1=0 i−1=0,或者当 i − 1 > 0 i−1>0 i−1>0 时 a r r [ i − 2 ] > a r r [ i − 1 ] arr[i−2]>arr[i−1] arr[i−2]>arr[i−1],因此 d p [ i ] [ 1 ] = d p [ i − 1 ] [ 0 ] + 1 dp[i][1]=dp[i−1][0]+1 dp[i][1]=dp[i−1][0]+1;
- 如果 a r r [ i − 1 ] = a r r [ i ] arr[i−1]=arr[i] arr[i−1]=arr[i],则 a r r [ i − 1 ] arr[i−1] arr[i−1] 和 a r r [ i ] arr[i] arr[i] 不能同时出现在同一个湍流子数组中,因此 d p [ i ] [ 0 ] = d p [ i ] [ 1 ] = 1 dp[i][0]=dp[i][1]=1 dp[i][0]=dp[i][1]=1。
最终, d p dp dp 数组的最大值即为所求的答案。
代码
class Solution {
public int maxTurbulenceSize(int[] arr) {
int n = arr.length;
int[][] dp = new int[n][2];
dp[0][0] = dp[0][1] = 1;
for (int i = 1; i < n; i++) {
dp[i][0] = dp[i][1] = 1;
if (arr[i - 1] > arr[i]) {
dp[i][1] = dp[i - 1][0] + 1;
} else if (arr[i - 1] < arr[i]) {
dp[i][0] = dp[i - 1][1] + 1;
}
}
int ret = 1;
for (int i = 0; i < n; i++) {
ret = Math.max(ret, dp[i][0]);
ret = Math.max(ret, dp[i][1]);
}
return ret;
}
}
优化代码
上述实现的空间复杂度是 O ( n ) O(n) O(n)。注意到当 i > 0 i>0 i>0 时,下标 i i i 处的 d p dp dp 值只和下标 i − 1 i−1 i−1 处的 d p dp dp 值有关,因此可以用两个变量 d p 0 dp0 dp0 和 d p 1 dp1 dp1 代替 d p [ i ] [ 0 ] dp[i][0] dp[i][0] 和 d p [ i ] [ 1 ] dp[i][1] dp[i][1],将空间复杂度降到 O ( 1 ) O(1) O(1)。
class Solution {
public int maxTurbulenceSize(int[] arr) {
int ret = 1;
int n = arr.length;
int dp0 = 1, dp1 = 1;
for (int i = 1; i < n; i++) {
if (arr[i - 1] > arr[i]) {
dp0 = dp1 + 1;
dp1 = 1;
} else if (arr[i - 1] < arr[i]) {
dp1 = dp0 + 1;
dp0 = 1;
} else {
dp0 = 1;
dp1 = 1;
}
ret = Math.max(ret, dp0);
ret = Math.max(ret, dp1);
}
return ret;
}
}
复杂度分析
- 时间复杂度: O ( n ) O(n) O(n),其中 n n n 为数组的长度。需要遍历数组 a r r arr arr 一次,计算 d p dp dp 的值。
- 空间复杂度: O ( 1 ) O(1) O(1)。使用空间优化的做法,只需要维护常数额外空间。