參考文章)
單調佇列
poj 2823
給定乙個數列,從左至右輸出每個長度為m的數列段內的最小數和最大數。
數列長度:n
<=106
,m<=
n'>n<=106,m<=n
n<=106
,m<=
n'>直接暴力求解複雜度在0(mn)
可以考慮維護區間最值,單調佇列則是維護區間佇列的強大**
單調佇列的定義:
單調佇列實現的大致過程:
1、維護隊首(對於上題就是如果隊首已經是當前元素的m個之前,則隊首就應該被刪了,head++)
2、在隊尾插入(每插入乙個就要從隊尾開始往前去除冗雜狀態,保持單調性)
簡單舉例應用
數列為:6 4 10 10 8 6 4 2 12 14
n=10,k=3;
那麼我們構造乙個長度為3的單調遞減佇列:
首先,那6和它的位置0放入佇列中,我們用(6,0)表示,每一步插入元素時佇列中的元素如下
插入6:(6,0);
插入4:(6,0),(4,1);
插入10:(10,2);
插入第二個10,保留後面那個:(10,3);
插入8:(10,3),(8,4);
插入6:(10,3),(8,4),(6,5);
插入4,之前的10已經超出範圍所以排掉:(8,4),(6,5),(4,6);
插入2,同理:(6,5),(4,6),(2,7);
插入12:(12,8);
插入14:(14,9);
那麼f(i)就是第i步時佇列當中的首元素:6,6,10,10,10,10,8,6,12,14
同理,最小值也可以用單調佇列來做。
#include#include#include#includeusing namespace std;單調棧問題描述地上從左到右豎立著 n 塊木板,從 1 到 n 依次編號,如下圖所示。我們知道每塊木板的高度,在第 n 塊木板右側豎立著一塊高度無限大的木板,現對每塊木板依次做如下的操作:對於第 i 塊木板,我們從其右側開始倒水,直到水的高度等於第 i 塊木板的高度,倒入的水會淹沒 ai 塊木板(如果木板左右兩側水的高度大於等於木板高度即視為木板被淹沒),求 n 次操作後,所有 ai 的和是多少。如圖上所示,在第 4 塊木板右側倒水,可以淹沒第 5 塊和第 6 塊一共 2 塊木板,a4 = 2。int a[1000010],n,m,mx[1000010],mn[1000010],q[1000010],p[1000010];//p放佇列中每乙個數字的編號
void getmin()
for(;i<=n;i++)
printf("\n");
for(int i=1;i<=n-m+1;i++)
printf("\n");
}return 0;
}
尋找在第 i 個數右邊第乙個比它大的數
單調棧來求解的話,複雜度是o(n)
結合單調棧的性質:使用單調棧可以找到元素向左遍歷第乙個比他小的元素,也可以找到元素向左遍歷第乙個比他大的元素。
顧名思義,單調棧就是棧內元素單調遞增或者單調遞減的棧,這一點和單調佇列很相似,但是單調棧只能在棧頂操作。
單調棧有以下兩個性質:
1、若是單調遞增棧,則從棧頂到棧底的元素是嚴格遞增的。若是單調遞減棧,則從棧頂到棧底的元素是嚴格遞減的。
2、越靠近棧頂的元素越後進棧。
單調棧與單調佇列不同的地方在於棧只能在棧頂操作,因此一般在應用單調棧的地方不限定棧的大小,否則可能會造成元素無法進棧。
元素進棧過程:對於單調遞增棧,若當前進棧元素為e,從棧頂開始遍歷元素,把小於e或者等於e的元素彈出棧,直接遇到乙個大於e的元素或者棧為空為止,然後再把e壓入棧中。對於單調遞減棧,則每次彈出的是大於e或者等於e的元素。
資料模擬木板倒水單調棧的入棧計算過程
思路:尋找比棧頂高的木板i,找到就出棧,不是就把木板i入棧,給出迴圈計數樣例 10,5,8,12,6
從左往右掃瞄
棧為空,10入棧 棧:10 此時棧頂是10,也就是說要尋找比10大的木板
5比10小,5入棧 棧:5,10 此時棧頂是5,也就是說要尋找比5大的木板
8比5大,5出棧 棧:10
這個時候,第二個高度為5的木板右邊比它高的木板已經找到了,是第三個木板8,所以5出棧,計算a2 = 3-2-1 = 0
8比10小,8入棧 棧:8,10 此時棧頂是8,也就是說要尋找比8大的木板
12比8大,8出棧 棧:10
第三個高度為8的木板右邊比它高的木板已經找到了,是第四個木板12,8出棧,計算a3 = 4-3-1 = 0
12比10大,10出棧 棧:空
第乙個高度為10的木板右邊比它高的木板已經找到了,是第四個木板12,所以10出棧,計算a1 = 4-1-1 = 2
棧為空,12入棧 棧:12 此時棧頂是12,也就是說要尋找比12大的木板
6比12小,6入棧 棧:6,12 此時棧頂是6,也就是說要尋找比6大的木板
掃瞄完成結束
最後棧的結構是:6,12 棧頂為6
由於最右端豎立著一塊高度無限大的木板,即存在第六塊木板高度為無窮,所以剩餘兩塊木板的演算法如下 a5 = 6-5-1 =0
a4 = 6-4-1 = 1
sum = a1 + a2 +a3 +a4 +a5 = 3
因此本題可以在o(n
)'>o(n)
o(n)的時間內迎刃而解了。
從左往右將木板節點壓棧,遇到比棧頂木板高的木板就將當前棧頂木板出棧並計算淹沒的木板數,如此迴圈直到棧頂木板高度比當前木板高或者棧為空,然後將此木板壓棧。木板全都壓棧完成後,棧內剩餘的木板都是右側沒有比它們更高的木板的,所以乙個個出棧並計算ai=n+1-temp_id-1(用最右邊無限高的木板減)。
#include#include#includeusing namespace std;struct node
;int main()
s.push(now);
} while(!s.empty())
cout<
return 0;
}
棧和佇列 單調佇列 單調棧
講解部落格鏈結 一 單調棧 1 什麼是單調棧?單調棧是指乙個棧內部元素具有嚴格單調性 單調遞增,單調遞減 的一種資料結構。2 單調棧的兩個性質 滿足從棧頂到棧底具有嚴格的單調性 滿足後進先出的特徵,越靠近棧底的元素越早的進棧。3 元素進棧的過程 對於當前進棧元素x 如果x 棧頂元素,x 進棧。否則 ...
單調佇列與單調棧
單調棧 單調棧,顧名思義,就是維持單調性 遞增或者遞減 的棧結構,如果新入棧的元素破壞了單調性,就彈出原先棧內元素,直到能夠滿足單調性 用途 它可以很方便地求出某個數的左邊或者右邊第乙個比它大或者小的元素,而且總時間複雜度o n 並且單調棧本身並不難實現 維護 每次入棧前先檢驗入棧後是否會破壞棧的單...
單調佇列與單調棧
線段樹等等容易tle,我們需要乙個o n 的演算法來解決這個問題。思路 可以看出,這個視窗是可以用乙個雙向佇列來模擬的,每當後方加入乙個數,都要從佇列尾部開始淘汰掉所有的小於它的數,保證佇列中每乙個數的後面,在視窗範圍內沒有大於等於它的數。當隊首元素不在視窗範圍時,隊首元素出隊。這樣操作後,隊內的元...