【單調棧的定義】
滿足單調性的棧結構
【圖例】
【leetcode 1124 表現良好的最長時間段】
【題目】
給你一份工作時間表 hours,上面記錄着某一位員工每天的工作小時數。
我們認爲當員工一天中的工作小時數大於 8 小時的時候,那麼這一天就是「勞累的一天」。
所謂「表現良好的時間段」,意味在這段時間內,「勞累的天數」是嚴格 大於「不勞累的天數」。
請你返回「表現良好時間段」的最大長度。
示例 1:
輸入:hours = [9,9,6,0,6,6,9]
輸出:3
解釋:最長的表現良好時間段是 [9,9,6]。
提示:
1 <= hours.length <= 10000
0 <= hours[i] <= 16
【分析】
第一步:根據時間是否大於8,將每一天的工作小時數量化成1與-1,這樣有利於後續的計算。
題目中的[9,9,6,0,6,6,9]被量化爲[1,1,-1,-1,-1,-1,1]。這樣,理解題意,可以看出我們需要得到一個區間,在這個區間裏面1和-1加起來要大於0。
第二步:怎樣可以更方便的得到一個區間的和?
在這裏,我們需要利用前綴和這個方法。利用前綴和方法,我們可以將[1,1,-1,-1,-1,-1,1]轉化爲前綴和prefixSrc = [0, 1, 2, 1, 0, -1, -2, -1],我們在前綴和前面加了一個0,是爲了好操作。
如果要得到[1,3]區間的和,根據前綴和的定義,只需要使用prefixSrc[3]-prefixSrc[0]即可。
第三步:我們現在需要找到的是:區間和>0的最長區間。
那麼可以這樣思考,想要prefixSrc[j]大於prefixSrc[i],我們只需要找到比prefixSrc[j]更小的元素在哪裏就可以了。這樣就可以使用單調棧了。
我們先遍歷一遍prefixSrc ,建議一個嚴格單調遞減的單調棧,這樣我們的棧頂元素就一定是prefixSrc 中的最小值。(其中,棧中存儲的是元素的索引)
然後,我們從後向前遍歷prefixSrc ,若遍歷到的元素大於棧頂元素,則這個區間是符合規則的,需要記錄下區間的大小,並且我們將棧頂元素彈出,然後繼續比較當前遍歷到的元素是不是大於棧頂元素。
圖一
圖二
圖三
圖四
圖五
【python代碼】
class Solution:
def longestWPI(self, hours: List[int]) -> int:
num = [ 0 for i in range(len(hours))]
for i in range(len(hours)):
if hours[i] > 8:
num[i] = 1
else:
num[i] = -1
j = 0
ans = []
ans.append(j)
for i in num:
j = j + i
ans.append(j)
stack = []
for i in range(len(num)):
if len(stack) == 0 or ans[stack[-1]] > ans[i]:
stack.append(i)
k = 0
n = len(hours)
while n > k:
while len(stack) != 0 and ans[stack[-1]] < ans[n]:
k = max(k,n-stack[-1])
stack.pop()
n -= 1
return k