1. 程式人生 > >單調棧以及單調隊列

單調棧以及單調隊列

否則 插入 width 項目 ack nss 最小 click https

單調棧:

  • 定義:

棧內的元素,按照某種方式排列下(單調遞增或者單調遞減),如果新入棧的元素破壞了單調性,就彈出棧內元素,直至滿足單調性。

  • 作用:單調棧可以找到從左/右遍歷第一個比它大/小的元素的位置。時間復雜度為O(N);

  • 實現方式:(以維護單調遞增棧為例)

  進棧操作:每次進入棧時,先檢驗棧頂元素和進棧元素的大小,如果小於,那麽直接入棧;否則,大於等於進棧元素的出棧,直到棧空或者棧頂元素小於入棧元素。

例如:3 8 2 3 1

  • 初始時刻棧為空,3入棧。.....................................棧內元素(3);
  • 8要進棧,8比3大,直接入棧。..............................棧內元素(3,8);
  • 2要進棧,2比8小,全部彈出,2入棧。.................棧內元素(2);
  • 3要進棧,3比2大,直接入棧。..............................棧內元素(2,3);
  • 1要進棧,1比3小,全部彈出,1入棧。.................棧內元素(1);

根據此時求出從左往右第一個比它小的元素。

3 8 2 3 1

0 3 0 2 0

代碼:

技術分享圖片
stack<int>s;
for
(int i=1;i<=n;i++) { while(s.size()&&s.top()>=a[i]) { s.pop(); } if(s.empty()) l[i]=0; else l[i]=s.top(); s.push(a[i]); }
View Code
stack<int>s;
for(int i=1;i<=n;i++)
{
     while(s.size()&&s.top()>=a[i])
     {
           s.pop();
     }
     
if(s.empty()) l[i]=0; else l[i]=s.top(); s.push(a[i]); }

例題:poj 2559

題意:給出一個柱形統計圖,它的每個項目的寬是1,高度和具體問題有關,現在編輯求出這個柱形圖中的最大面積的長方形(n<=le5)

例如:2,1,4,5,1,3,3

技術分享圖片

面積為8。

分析:

  • 我們首先想到的是逐個考慮每個項目,求出每個項目被包含的長方形。
  • 求出每個被包含的長方形,那麽左右兩邊的高度不能比項目本身的高度低,就是向左右兩邊延展。
  • 那麽用單調棧,時間復雜度是2N:
  1. 求出兩邊比項目第一個小的位置。為什麽不是取兩邊比項目第一個大的位置呢?因為如果是大的位置,它們之間可能包含比項目本身要小值,就不能達到連續。
  2. 分別對項目進行左右延伸。

單調隊列:

  • 定義:

隊列中元素之間的關系具有單調性,而且,隊首和隊尾都可以進行出隊操作,只有隊尾可以進行入隊操作。

  • 作用:

對於維護好的單調隊列,單調隊列是有序的,那麽取出最大值(最小值)的復雜度是O(1);

可以拿來優化DP;

  • 操作:

  1. 插入:若新元素從隊尾插入後會破壞單調性,則刪除隊尾元素,直至插入後不再破壞單調性為止,在將其插入單調隊列。這和單調棧的插入一樣。
  2. 獲取最優值:訪問首尾元素。
  3. 定長連續子區間的最值問題

例題:

題意:給定一個長度為n的數列,求長度為k的定長連續子區間{a1,a2,a3,a4............,ak-1,ak}...............中每個區間的最大值和最小值。

分析:

  • 當我們看到這個第一個想法應該是枚舉起始元素ax,然後再求ax到ak-1+x的最大(小)值,那麽區間的復雜度為O(nk);
  • al,al+1,al+2....................ar-1,ar,ar+1,以最大值為例:
  1. 當我們求區間(l,r)最大值時:=max{al,max(al+1,al+2..........ar-1,ar)};
  2. 當我們求區間(l+1,r+1)最大值時:=max{ar+1,max(al+1,al+2..........ar-1,ar)};
  3. 那麽再求區間(l+1,r+1)時,我們完全沒必要在重新掃描一次。只有當最值在al才需要重新掃描。
  4. 那麽如果在區間(l,r)求最大值時,l<i<j<r,如果ai<aj,那麽在向右移動的過程中ai就失去了效果,這就與單調隊列彈出所不符合單調的元素性質一樣。
  5. 當我們將區間從(l,r)移動到(l+1,r+1)時,我們將ar+1插入單調隊列中,若隊首元素不在(l,r)區間中,那麽說明最大值不是(l,r)區間的數,清除隊首元素(出隊);

例如:4 1 3 2 7 5 6 n=7,k=3;求長度為k的連續子序列的最大值。

  • 初始隊列為空,4入隊.....................................................隊列元素(4);
  • 進隊元素為1,1比4小,直接入隊...................................隊列元素(4,1);
  • 進隊元素為3,3比1大,彈出1,3入隊...........................隊列元素(4,3);那麽最大值為4;
  • 進隊元素為2,2比3小,直接入隊...................................隊列元素(4,3,2);因為4不在a2~a4元素中,所有要先彈出4元素,此時最大值為3,隊列元素(3,2);
  • 進隊元素為7,7比4大,全部彈出...................................隊列元素(7);此時最大值為7;
  • 進隊元素為5,5比7小,直接入隊...................................隊列元素(7,5);此時最大值為7;
  • 進隊元素為6,6比5大,彈出5,6入隊...........................隊列元素(7,6);此時最大值為7;

單調棧以及單調隊列