双端单调队列
上次我們介紹了單調(diào)棧結(jié)構(gòu)https://blog.csdn.net/hebtu666/article/details/82717317
這次介紹一種新的數(shù)據(jù)結(jié)構(gòu):雙端隊(duì)列:雙端隊(duì)列是指允許兩端都可以進(jìn)行入隊(duì)和出隊(duì)操作的隊(duì)列,其元素的邏輯結(jié)構(gòu)仍是線性結(jié)構(gòu)。將隊(duì)列的兩端分別稱為前端和后端,兩端都可以入隊(duì)和出隊(duì)。
堆棧、隊(duì)列和優(yōu)先隊(duì)列都可以采用雙端隊(duì)列來實(shí)現(xiàn)
本文介紹單調(diào)雙端隊(duì)列的原理及應(yīng)用。
單調(diào)隊(duì)列,顧名思義,就是一個(gè)元素單調(diào)的隊(duì)列,那么就能保證隊(duì)首的元素是最小(最大)的,從而滿足最優(yōu)性問題的需求。
給定一個(gè)長度為n的數(shù)列,一個(gè)k,求所有的min(ai,ai+1.....ai+k-1),i=0,1,....n-k
通俗一點(diǎn)說就是一個(gè)長度固定的滑動(dòng)的窗口,求每個(gè)窗口內(nèi)的最小值。
你當(dāng)然可以暴力求解,依次遍歷每個(gè)窗口.
介紹單調(diào)隊(duì)列用法:我們維護(hù)一個(gè)單調(diào)隊(duì)列
單調(diào)隊(duì)列呢,以單調(diào)遞增序列為例:
1、如果隊(duì)列的長度一定,先判斷隊(duì)首元素是否在規(guī)定范圍內(nèi),如果超范圍則增長隊(duì)首。
2、每次加入元素時(shí)和隊(duì)尾比較,如果當(dāng)前元素小于隊(duì)尾且隊(duì)列非空,則減小尾指針,隊(duì)尾元素依次出隊(duì),直到滿足隊(duì)列的調(diào)性為止
?
我們說算法的優(yōu)化就是重復(fù)計(jì)算過程的去除。
按窗口一次次遍歷就是重復(fù)計(jì)算。最值信息沒有利用好。
我們?yōu)槭裁纯梢赃@么維護(hù)?
首先,遍歷到的元素肯定在隊(duì)列元素之后。
其次,如果當(dāng)前元素更小的話。
頭部的值比當(dāng)前元素大,頭部還比當(dāng)前元素先過期。所以以后計(jì)算再也不會用到它了。我們可以放心的去掉它。
下面給出代碼和解釋
int n,k;//長度為n的數(shù)列,窗口為k int a[MAX_N];//數(shù)列 int b[MAX_N];//存放 int deq[MAX_N]//模擬隊(duì)列void solve() {int s = 0,t = 0;//頭和尾for(int i=0;i<n;i++){//不滿足單調(diào),尾就彈出while(s<t && a[deq[t-1]]>=a[i])t--;//直到滿足,放入deq[t++]=i;//計(jì)算窗口最大值if(i-k+1>=0)b[i-k+1]=a[deq[s];//判斷頭過期彈出if(deq[s]==i-k+1)s++;} }基本入門就到這里。
總結(jié)
- 上一篇: leetcode139 单词拆分
- 下一篇: 22种编程语言新年快乐