在演算法題目中,經常會遇到給定乙個陣列,找出符合某種特性的連續子陣列。這時候可以採用滑動視窗的方法。
例如,給定陣列a = [1,1,3,2,1,0,2],找出滿足和小於等於5的最長連續子陣列。
採用暴力的方法,需要用一層迴圈枚舉子陣列的起始位置,然後用第二層迴圈枚舉子陣列的長度,時間複雜度為o(n^2)。
採用滑動視窗的方式即可將演算法複雜度降到o(n)。
其核心思想是,採用兩個指標,分別指代子陣列的左右邊界。找到以每個座標為起點的比之前長的子陣列。以上述問題為例,剛開始,left=0, right = 0, ans =0 window_sum = 0
現在我們想要找到以[1]為起點,並且符合條件的最長子陣列。
此時我們移動right,可以發現當right=3的時候,和就已經大於5了,所以以[1]為開始的最長子陣列的長度是3,更新ans = 3,window_sum = 5
此時我們將left向右移動,此時可以發現指代的是[1,3,2]這樣乙個陣列,我們可以直接認為以第二個[1]為開始,並不存在最優解。這是因為,如果想要比之前的3還要長,至少要從現在這個2開始,就算之前[1,3]滿足條件,這也毫無意義,我們想要找的是比之前長的子陣列,所以我們再將left向右移動,直到結束。
可以發現這種演算法的魅力所在是left和right一直都在向右移動,所以說複雜度為2*o(n)。其通過不斷尋找最長這樣乙個思想,每次限定了right最小的起始位置,從而捨棄了很多一定不是最優解的計算,達到了o(n)的時間複雜度。
演算法如下:
window_sum = 0
left = 0
length = 0
for right in range(len(nums)):
window_sum += nums[right]
while window_sum > cost:
length = max(length, right-left)
window_sum -= nums[left]
left += 1
return max(length, right - left + 1)
其中注意一點的是,如果最後的結果包含最後一位數字,也就是最後沒有進入while迴圈來更新length,所以我們需要在外層額外判斷這種情況。
有了找到小於等於k的最長連續子陣列,我們自然會想到找到大於等於k的最短連續子陣列這樣乙個問題。
和上面的思想同理,我們首先找到起始位是0的最短子陣列,然後將left向左邊滑動,right保持不變。這是因為如果存在乙個新的右界值得注意的是,由於是滿足條件進入的while,所以長度是right-left + 1,並且沒有外面的額外判斷。
**如下:
window_sum = 0
left = 0
length = float('inf')
for right in range(len(nums)):
window_sum += nums[right]
while window_sum >= cost:
length = min(length, right-left+1)
window_sum -= nums[left]
left += 1
return length
滑動視窗演算法 演算法 滑動視窗 二
演算法 這算是滑動視窗的另外乙個典型題目,在資料量比較少的時候,可以直接採用暴力法解決 不過資料量比較大的時候,我們就需要想辦法解決視窗裡面最大值的思路,這裡我們採用雙端佇列queue來實現,借助 queue來儲存前面計算過的最大值資訊。題目 解法1 暴力解法 按照 視窗大小,從頭到尾依次遍歷,將每...
演算法 滑動視窗
一.滑動視窗 滑動視窗其實就是高階版的雙指標技巧,只不過它依靠了資料結構 hashmap,hashset 的幫助,使得雙指標運用起來更加的靈活,更加的方便,他主要就是來解決子字串匹配問題。他主要的思路就是這樣的固定步驟 1 我們在字串 s 中使用雙指標中的左右指標技巧,初始化 left right ...
演算法 滑動視窗
最多可以將k個值從0變成1,因此滑動視窗的限制條件 0的數量 zeros 小於k,演算法過程如下 有乙個滑動視窗 slipper 每次都會從a中讀入乙個數 當讀入的數為0時,zeros 當zeros的數量大於k時,會取出slipper首部的元素,當取值為0時zeros 總體 如下 上述演算法效率並不...