1. 程式人生 > 其它 >2021.7.7今日小結

2021.7.7今日小結

感覺自己對這種資料結構理解的一直不是很好……
於是就有了這一篇。相信所有人都能看懂(

符號約定:

  1. 對於佇列,使用[表示隊首,使用]表示隊尾。
  2. 對於棧,使用<表示棧頂,使用]表示棧底。

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]

有一句著名的話就體現了單調佇列的性質(當然此處說的應是單調遞減的單調佇列):

如果一個人比你小,又比你強,那你就打不過他了。

但是這裡有兩個需要注意的點。

  1. 這個佇列是可以從隊尾移除元素的,所以這並不是一個我們一般所說的佇列。
    方便起見,我們會使用STL中的deque來模擬單調佇列。
  2. 為什麼不把4和6再push回去?
    這保證了單調佇列的時間複雜度。
    如果像剛剛這樣做,那麼對於一個單調遞增的佇列,插入倒序的數列時間複雜度直接\(O(n^2)\)。如:
 1000000 999999 999998 ...... 2 1

但是,如果我們將元素pop出之後就不再將其push進佇列,
那麼容易發現每個元素最多進隊一次,出隊一次,
如此時間複雜度達到了優秀的\(O(n)\)

1.3 單調佇列的應用兩例

1.3.1 維護定長區間最值

luoguP1886 滑動視窗

題意:
有一個長為 \(n\) 的序列 \(a\),以及一個大小為 \(k\) 的視窗。現在這個從左邊開始向右滑動,每次滑動一個單位,求出每次滑動後窗口中的最大值和最小值。

這裡只分析最大值,最小值同理可得。