雙端單調佇列
阿新 • • 發佈:2018-12-10
這次介紹一種新的資料結構:雙端佇列:雙端佇列是指允許兩端都可以進行入隊和出隊操作的佇列,其元素的邏輯結構仍是線性結構。將佇列的兩端分別稱為前端和後端,兩端都可以入隊和出隊。
堆疊、佇列和優先佇列都可以採用雙端佇列來實現
本文介紹單調雙端佇列的原理及應用。
單調佇列,顧名思義,就是一個元素單調的佇列,那麼就能保證隊首的元素是最小(最大)的,從而滿足最優性問題的需求。
給定一個長度為n的數列,一個k,求所有的min(ai,ai+1.....ai+k-1),i=0,1,....n-k
通俗一點說就是一個長度固定的滑動的視窗,求每個視窗內的最小值。
你當然可以暴力求解,依次遍歷每個視窗.
介紹單調佇列用法:我們維護一個單調佇列
單調佇列呢,以單調遞增序列為例:
1、如果佇列的長度一定,先判斷隊首元素是否在規定範圍內,如果超範圍則增長隊首。
2、每次加入元素時和隊尾比較,如果當前元素小於隊尾且佇列非空,則減小尾指標,隊尾元素依次出隊,直到滿足佇列的調性為止
我們說演算法的優化就是重複計算過程的去除。
按視窗一次次遍歷就是重複計算。最值資訊沒有利用好。
我們為什麼可以這麼維護?
首先,遍歷到的元素肯定在佇列元素之後。
其次,如果當前元素更小的話。
頭部的值比當前元素大,頭部還比當前元素先過期。所以以後計算再也不會用到它了。我們可以放心的去掉它。
下面給出程式碼和解釋
int n,k;//長度為n的數列,視窗為k int a[MAX_N];//數列 int b[MAX_N];//存放 int deq[MAX_N]//模擬佇列 void solve() { int s = 0,t = 0;//頭和尾 for(int i=0;i<n;i++) { //不滿足單調,尾就彈出 while(s<t && a[deq[t-1]]>=a[i])t--; //直到滿足,放入 deq[t++]=i; //計算視窗最大值 if(i-k+1>=0)b[i-k+1]=a[deq[s]; //判斷頭過期彈出 if(deq[s]==i-k+1)s++; } }
基本入門就到這裡。