題目
概述:給定一個整數數組,求出這個數組中良好的子數組的最大長度。良好的子數組定義如下:大于8的數的占比超過50%
輸入:整數數組,長度范圍[1, 10000],每個數范圍[0, 16]
輸出:良好的子數組的最大長度
出處:https://leetcode-cn.com/problems/longest-well-performing-interval/
思路
- 參考 劉岳 https://leetcode-cn.com/problems/longest-well-performing-interval/solution/qian-zhui-he-dan-diao-zhan-python3-by-smoon1989/
- 對于本題來說,8是一個分界點,所以小于等于8的數之間沒有差別,大于8的數也沒有差別,所以可以把小于等于8的數看作-1,大于8的數看作1,那么本題可以轉化為求所有元素和大于0的子數組中最長的子數組
- 將數組分解為以索引x為終點的子數組(x屬于[0,n-1],設數組長度為n),先求以索引x為終點的子數組的最優解,然后綜合這些最優解可以得到最終答案
- 求以索引x為終點的子數組的解,可以先將數組求前綴和,得到一個前綴和數組,前綴和數組中后一個索引位置的數減去前一個索引位置的數大于0表示一個解,綜合所有解可以得到以索引x為終點的子數組的最優解(索引差距最大的)
- 問題的關鍵在于如何快速找到這個索引差距最大的最優解,可以先找終點x左邊最小的數,然后從該最小的數開始,遞歸地找左邊比它大的第一個數,直到無解
- 找左邊比它大的第一個數可以用單調棧這一數據結構解決,這里適用的是單調遞減棧(構造過程中沒有元素彈出,棧為空或當前數小于棧頂元素時,當前數入棧)
- 求解索引x-1為終點的子數組的最優解可以繼承求解索引x為終點的子數組的最優解用到的單調棧,因為以被彈出的元素為起點的解以索引x為終點總比以索引x-1為終點更優(長度增加了1)
代碼
class Solution {
public int longestWPI(int[] hours) {
int len = hours.length;
int[] preSums = new int[len + 1];
preSums[0] = 0;
for (int i = 1; i <= len; ++i) {
preSums[i] = preSums[i - 1] + (hours[i - 1] > 8 ? 1 : -1);
}
// stack stores index & index starts with 0
LinkedList<Integer> stack = new LinkedList<>();
for (int i = 0; i <= len; ++i) {
if (stack.isEmpty() || preSums[i] < preSums[stack.peek()]) {
stack.push(i);
}
}
// use i > res optimize
int res = 0;
for (int i = len; i > res; --i) {
while (!stack.isEmpty() && preSums[stack.peek()] < preSums[i]) {
res = Math.max(res, i - stack.pop());
}
}
return res;
}
}