單調佇列之滑動視窗

2021-10-03 12:47:48 字數 2856 閱讀 3092

也許這種資料結構的名字你沒聽過, 其實沒啥難的, 就是⼀個「佇列」 , 只是使⽤了⼀點巧妙的⽅法,使得佇列中的元素單調遞增(或遞減)。 這個資料結構有什麼⽤? 可以解決滑動窗⼝的⼀系列問題。

看⼀道 leetcode 題⽬, 難度 hard:

給定乙個陣列 nums,有乙個大小為 k 的滑動視窗從陣列的最左側移動到陣列的最右側。你只可以看到在滑動視窗內的 k 個數字。滑動視窗每次只向右移動一位。

返回滑動視窗中的最大值。

示例:

輸入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3

輸出: [3,3,5,5,6,7]

解釋:

滑動視窗的位置 最大值

--------------- -----

[1 3 -1] -3 5 3 6 7 3

1 [3 -1 -3] 5 3 6 7 3

1 3 [-1 -3 5] 3 6 7 5

1 3 -1 [-3 5 3] 6 7 5

1 3 -1 -3 [5 3 6] 7 6

1 3 -1 -3 5 [3 6 7] 7

⼀、 搭建解題框架在⼀堆數字中, 已知最值, 如果給這堆數新增⼀個數, 那麼⽐較⼀下就可以很快算出最值; 但如果減少⼀個數, 就不⼀定能很快得到最值了, ⽽要遍歷所有數重新找最值回到這道題的場景, 每個窗⼝前進的時候, 要新增⼀個數同時減少⼀個數,所以想在 o(1

)o(1)

o(1)

的時間得出新的最值, 就需要「單調佇列」 這種特殊的資料結構來輔助了

⼀個「單調佇列」 的操作也不多:

這個思路很簡單, 能理解吧? 下⾯我們開始重頭戲, 單調佇列的實現。

⼆、 實現單調佇列資料結構

⾸先我們要認識另⼀種資料結構:deque, 即雙端佇列。 很簡單:

class deque 

;

這些操作的複雜度都是 o(1

)o(1)

o(1)

單調佇列」 的核⼼思路和「單調棧」 類似。單調佇列的 push ⽅法依然在隊尾新增元素, 但是要把前⾯⽐新元素⼩的元素都刪掉

class monotonicqueue 

};

你可以想象, 加⼊數字的⼤⼩代表⼈的體重, 把前⾯體重不⾜的都壓扁了,直到遇到更⼤的量級才停住。

如果每個元素被加⼊時都這樣操作, 最終單調佇列中的元素⼤⼩就會保持⼀個單調遞減的順序, 因此我們的max()api 可以可以這樣寫:

int

max(

)

pop()api 在隊頭刪除元素 n, 也很好寫:

void

pop(

int n)

之所以要判斷 data.front() == n , 是因為我們想刪除的隊頭元素 n 可能已經被「壓扁」 了, 這時候就不⽤刪除了⾄此, 單調佇列設計完畢, 看下完整的解題**:

class monotonicqueue 

intmax()

void

pop(

int n)};

vector<

int>

maxslidingwindow

(vector<

int>

& nums,

int k)

else

}return res;

}

讀者可能疑惑, push 操作中含有 while 迴圈, 時間複雜度不是 o(1

)o(1)

o(1)

呀, 那

麼本演算法的時間複雜度應該不是線性時間吧?

單獨看 push 操作的複雜度確實不是 o(1

)o(1)

o(1)

, 但是演算法整體的複雜度依然是o(n

)o(n)

o(n)

線性時間。 要這樣想, nums 中的每個元素最多被 pus

hbac

kpush_back

pushb​

ack 和pop

back

pop_back

popb​a

ck⼀次, 沒有任何多餘操作, 所以整體的複雜度還是 o(n

)o(n)

o(n)

。空間複雜度就很簡單了, 就是窗⼝的⼤⼩o(k

)o(k)

o(k)

單調佇列 滑動視窗

nkoj 2152 description 給你乙個長度為n n 10 6 的陣列,乙個長為k的滑動的窗體從最左移至最右端,你只能見到視窗的k個數,每次窗體向右移動一位,找出窗體所包含的數字的最大和最小值,如下表所示 k的值為3 視窗位置 最小值 最大值 1 3 1 3 5 3 6 7 1 3 1 ...

滑動視窗 單調佇列

給定乙個大小為n 106的陣列。有乙個大小為k的滑動視窗,它從陣列的最左邊移動到最右邊。您只能在視窗中看到k個數字。每次滑動視窗向右移動乙個位置。以下是乙個例子 該陣列為 1 3 1 3 5 3 6 7 k為3。視窗位置 最小值 最大值 1 3 1 3 5 3 6 7 1 3 1 3 1 3 5 3...

單調佇列 滑動視窗

p1886 滑動視窗 模板 單調佇列 有乙個長為 n 的序列 a,以及乙個大小為 k 的視窗。現在這個從左邊開始向右滑動,每次滑動乙個單位,求出每次滑動後視窗中的最大值和最小值。如果按照暴力方法做的話,每一次判斷相鄰的k個數的最大值和最小值,複雜度為o n k 肯定會超時,因此就想到把每次的最大值和...