2021.7.7今日小結
阿新 • • 發佈:2021-07-07
感覺自己對這種資料結構理解的一直不是很好……
於是就有了這一篇。相信所有人都能看懂(
符號約定:
- 對於佇列,使用[表示隊首,使用]表示隊尾。
- 對於棧,使用<表示棧頂,使用]表示棧底。
1. 單調佇列
1.1 什麼是單調佇列
顧名思義,“單調佇列”就是佇列內元素滿足單調性的佇列。比如下面這兩個佇列:
[3 6 9 10] [90 4 2 -1] [6 4 2 5]
顯然前兩個佇列滿足單調性,而最後一個不滿足。不妨稱第一個佇列為單調遞增的,而第二個為單調遞減的。
1.2 如何滿足佇列的單調性
這個非常簡單。比如說我們遇到了一個單調遞增的佇列:
[1 4 6]
但是這個時候我們要插入2。於是為了滿足佇列的單調性,我們將4和6從隊尾移除,並從隊尾插入2。
最後佇列就變成了:
[1 2]
有一句著名的話就體現了單調佇列的性質(當然此處說的應是單調遞減的單調佇列):
如果一個人比你小,又比你強,那你就打不過他了。
但是這裡有兩個需要注意的點。
- 這個佇列是可以從隊尾移除元素的,所以這並不是一個我們一般所說的佇列。
方便起見,我們會使用STL中的deque來模擬單調佇列。 - 為什麼不把4和6再push回去?
這保證了單調佇列的時間複雜度。
如果像剛剛這樣做,那麼對於一個單調遞增的佇列,插入倒序的數列時間複雜度直接\(O(n^2)\)。如:
1000000 999999 999998 ...... 2 1
但是,如果我們將元素pop出之後就不再將其push進佇列,
那麼容易發現每個元素最多進隊一次,出隊一次,
如此時間複雜度達到了優秀的\(O(n)\)
1.3 單調佇列的應用兩例
1.3.1 維護定長區間最值
題意:
有一個長為 \(n\) 的序列 \(a\),以及一個大小為 \(k\) 的視窗。現在這個從左邊開始向右滑動,每次滑動一個單位,求出每次滑動後窗口中的最大值和最小值。
這裡只分析最大值,最小值同理可得。