Given an integer array arr
, return the length of a maximum size turbulent subarray of arr
.
A subarray is turbulent if the comparison sign flips between each adjacent pair of elements in the subarray.
More formally, a subarray [arr[i], arr[i + 1], ..., arr[j]]
of arr
is said to be turbulent if and only if:
- For
i <= k < j
:arr[k] > arr[k + 1]
whenk
is odd, andarr[k] < arr[k + 1]
whenk
is even.
- Or, for
i <= k < j
:arr[k] > arr[k + 1]
whenk
is even, andarr[k] < arr[k + 1]
whenk
is odd.
Example 1:
Input: arr = [9,4,2,10,7,8,8,1,9]
Output: 5
Explanation: arr[1] > arr[2] < arr[3] > arr[4] < arr[5]
Example 2:
Input: arr = [4,8,12,16]
Output: 2
Example 3:
Input: arr = [100]
Output: 1
Constraints:
1 <= arr.length <= 4 * 104
0 <= arr[i] <= 109
這道題給了一個數組,定義一種湍流子數組,即數字增減交替,就是先增大再減小再增大等交替進行,或者是先減小再增大再減小等交替進行的。現在讓找出最長的湍流子數組,並返回長度。首先最無腦的暴力搜索就是遍歷所有的子數組,並判斷是否是湍流數組,這樣太不高效了,有點不尊重 OJ 的感覺,估計不會給過。畢竟是道 Medium 題,總得給點面子吧,那就來想一下,我們並不知道湍流子數組的起點在哪,也不知道它到底是先增大還是先減小,這樣的話其實每個位置都有可能是一個湍流數組的起點或終點,就按終點來考慮,每個位置都代表一種狀態,而且這道題又是求極值的問題,那么該什么方法是不是就呼之欲出了,來~大聲地告訴博主,用什么方法?對了,就是動態規划 Dynamic Programming,首先來想怎么定義 dp 數組,要求的是湍流子數組的長度,那么 dp 值代表的含義應該也是長度。又因為每個位置都可能是個湍流子數組的終點,並且末尾數字可能是下降或者上升,有兩種狀態,可以用一個二維 dp 數組,也可以用兩個一維數組 dec 和 inc 來表示,這里 dec[i] 表示湍流數組的長度,同時其末尾是數字是 arr[i] 且是下降的,同理,inc[i] 表示湍流數組的長度,同時其末尾是數字是 arr[i] 且是上升的。數組定義好了,下面是就是找狀態轉移方程了,其實也不難,當前狀態跟前一個狀態息息相關,首先要比較當前數字和前一個數字的大小關系,若前一個數字大於當前數字,則表示下降的關系,則可以更新 dec[i] 為 inc[i-1] + 1,反之,若前一個數字小於當前數字,則表示上升的關系,則可以更新 inc[i] 為 dec[i-1] + 1。每次更新完一個位置,從 dec[i] 和 inc[i] 中找出最大的位置,用來更新結果 res 即可,參見代碼如下:
解法一:
class Solution {
public:
int maxTurbulenceSize(vector<int>& arr) {
int res = 1, n = arr.size();
vector<int> dec(n, 1), inc(n, 1);
for (int i = 1; i < n; ++i) {
if (arr[i - 1] > arr[i]) {
dec[i] = inc[i - 1] + 1;
} else if (arr[i - 1] < arr[i]) {
inc[i] = dec[i - 1] + 1;
}
res = max(res, max(dec[i], inc[i]));
}
return res;
}
};
我們可以進一步的更新空間復雜度,因為當前狀態僅僅依賴前一個狀態,所以沒有必要保留所有位置的狀態,就只有兩個變量就可以了,不過要注意的是別忘了及時的將 inc 或 dec 重置為1,當相鄰的兩個數字相同時,兩者還要同時重置1,參見代碼如下:
解法二:
class Solution {
public:
int maxTurbulenceSize(vector<int>& arr) {
int res = 1, n = arr.size(), inc = 1, dec = 1;
for (int i = 1; i < n; ++i) {
if (arr[i] < arr[i - 1]) {
dec = inc + 1;
inc = 1;
} else if (arr[i] > arr[i - 1]) {
inc = dec + 1;
dec = 1;
} else {
inc = 1;
dec = 1;
}
res = max(res, max(inc, dec));
}
return res;
}
};
Github 同步地址:
https://github.com/grandyang/leetcode/issues/978
類似題目:
參考資料:
https://leetcode.com/problems/longest-turbulent-subarray/
https://leetcode.com/problems/longest-turbulent-subarray/discuss/221935/Java-O(N)-time-O(1)-space