[LeetCode] 978. Longest Turbulent Subarray 最長湍流子數組



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] when k is odd, and
    • arr[k] < arr[k + 1] when k is even.
  • Or, for i <= k < j:
    • arr[k] > arr[k + 1] when k is even, and
    • arr[k] < arr[k + 1] when k 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


類似題目:

Maximum Subarray


參考資料:

https://leetcode.com/problems/longest-turbulent-subarray/

https://leetcode.com/problems/longest-turbulent-subarray/discuss/221935/Java-O(N)-time-O(1)-space

https://leetcode.com/problems/longest-turbulent-subarray/discuss/221929/C%2B%2BJava-6-lines-flip-the-sign


LeetCode All in One 題目講解匯總(持續更新中...)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM