Longest Turbulent Subarray LT978
A subarray A[i], A[i+1], ..., A[j]
of A
is said to be turbulent if and only if:
- For
i <= k < j
,A[k] > A[k+1]
whenk
is odd, andA[k] < A[k+1]
whenk
is even; - OR, for
i <= k < j
,A[k] > A[k+1]
whenk
is even, andA[k] < A[k+1]
whenk
is odd.
That is, the subarray is turbulent if the comparison sign flips between each adjacent pair of elements in the subarray.
Return the length of a maximum size turbulent subarray of A.
Example 1:
Input: [9,4,2,10,7,8,8,1,9]
Output: 5
Explanation: (A[1] > A[2] < A[3] > A[4] < A[5])
Example 2:
Input: [4,8,12,16]
Output: 2
Example 3:
Input: [100]
Output: 1
Idea 1. Extending to a new element in the array. How to extend the solution from A[0...i] to A[0,...i, i+1]? We care about if the comparison sign has been alternated. The new length ending at i could be determined by the length ending at i-1 and the sign alternation.
len(i) = 1 if A[i-1] == A[i]
len(i) = 2 if A[i-1] != A[i] and comparison sign has not been alternated, i.e. previousSign * currentSign != -1
len(i) = len(i-1) + 1 if previousSign * currentSign == -1
Time complexity: O(n)
Space complexity: O(1)
1 class Solution { 2 public int maxTurbulenceSize(int[] A) { 3 int sign = 0; 4 int len = 1; 5 int maxLen = 1; 6 for(int i = 1; i< A.length; ++i) { 7 int currSign = Integer.compare(A[i-1], A[i]); 8 if(currSign != 0) { 9 if(sign * currSign != -1) { 10 len = 2; 11 } 12 else { 13 ++len; 14 } 15 } 16 sign = currSign; 17 maxLen = Math.max(maxLen, len); 18 } 19 return maxLen; 20 } 21 }
1.b. save an extra variable, since we care only the consecutive comparison, 3 elements can determin if the sign has been alternated.
1 class Solution { 2 public int maxTurbulenceSize(int[] A) { 3 4 int len = 0; 5 int maxLen = 1; 6 for(int i = 0; i< A.length; ++i) { 7 if(i >= 2 && (Integer.compare(A[i-2], A[i-1]) * Integer.compare(A[i-1], A[i]) == -1)) { 8 ++len; 9 } 10 else if(i >=1 && A[i-1] != A[i]) { 11 len = 2; 12 } 13 else { 14 len = 1; 15 } 16 17 maxLen = Math.max(maxLen, len); 18 } 19 return maxLen; 20 } 21 }
Idea 1.c recording length of the alternating block ending at i, the last two elements is either increasing or decreasing:
inc = dec + 1 if A[i] > A[i-1], reset dec = 1
dec = inc + 1 if A[i] < A[i-1], reset inc = 1
dec =1 , inc = 1 if A[i] == A[i-1] or i == 0
1 class Solution { 2 public int maxTurbulenceSize(int[] A) { 3 4 int dec = 0; 5 int inc = 0; 6 int maxLen = 0; 7 for(int i = 0; i< A.length; ++i) { 8 if(i== 0 || A[i-1] == A[i]) { 9 dec = 1; 10 inc = 1; 11 } 12 else if(A[i-1] < A[i]) { 13 inc = dec + 1; 14 dec = 1; 15 } 16 else { 17 dec = inc + 1; 18 inc = 1; 19 } 20 maxLen = Math.max(maxLen, Math.max(dec, inc)); 21 22 } 23 return maxLen; 24 } 25 }
Idea 2. Sliding window, recording the potential starting point of the alternative block, once the block stop flipping the sign or reaching the end of the array, then caculate the length of the block. This idea reminds me the subarray min sum which find the previous smallest element and the next smallest element to find the length of block which contains larger elements.
start = i if A[i-1] == A[i]
len = i - start + 1 if i == nums.lengh -1 or Integer.compare(A[i-1], A[i]) == Integer.compare(A[i], A[i+1])
1 class Solution { 2 public int maxTurbulenceSize(int[] A) { 3 4 int start = 0; 5 int maxLen = 1; 6 for(int i = 1; i< A.length; ++i) { 7 int sign = Integer.compare(A[i-1], A[i]); 8 if(sign == 0) { 9 start = i; 10 } 11 else if(i == A.length-1 || sign * Integer.compare(A[i], A[i+1]) != -1) { 12 int len = i - start + 1; 13 maxLen = Math.max(maxLen, len); 14 start = i; 15 } 16 17 18 } 19 return maxLen; 20 } 21 }
Note:
1 <= A.length <= 40000
0 <= A[i] <= 10^9