上次我們介紹了單調棧結構https://blog.csdn.net/hebtu666/article/details/82717317
這次介紹一種新的數據結構:雙端隊列:雙端隊列是指允許兩端都可以進行入隊和出隊操作的隊列,其元素的邏輯結構仍是線性結構。將隊列的兩端分別稱為前端和后端,兩端都可以入隊和出隊。
堆棧、隊列和優先隊列都可以采用雙端隊列來實現
本文介紹單調雙端隊列的原理及應用。
單調隊列,顧名思義,就是一個元素單調的隊列,那么就能保證隊首的元素是最小(最大)的,從而滿足最優性問題的需求。
給定一個長度為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++;}
}
基本入門就到這里。