我自己的話單調棧是也用陣列模擬出來的,我是根據這個部落格學的,原理挺簡單的,但是做題思想的轉變有點麻煩,最後陣列模擬的單調佇列其實是雙向佇列。
下邊是大佬的部落格:
單調佇列是什麼呢?可以直接從問題開始來展開。
poj 2823
給定乙個數列,從左至右輸出每個長度為m的數列段內的最小數和最大數。
數列長度:n<=106,m<=nn<=106,m<=n
很直觀的一種解法,那就是從數列的開頭,將窗放上去,然後找到這最開始的k個數的最大值,然後窗最後移乙個單元,繼續找到k個數中的最大值。
這種方法每求乙個f(i),都要進行k-1次的比較,複雜度為o(nk)o(nk)。
顯然,如果暴力時間複雜度為 o(nm)o(nm) 不超時就怪了。
還有一種想法是維護乙個bst,然後for迴圈從左到右,依次加入到bst裡面,如果某個數超出了k的範圍,就從bst中刪除。
因為每個數隻insert一次,最多erase一次,所以複雜度是o(nlogn)o(nlogn)的,已經很不錯了。
但是106106級別的極限資料,這種做法會被卡掉的,況且維護乙個bst的**也比較麻煩。
void getans()
cout我們知道,解法①在暴力列舉的過程中,有乙個地方是重複比較了,就是在找當前的f(i)的時候,i的前面其它m-1個數在算f(i-1)的時候我們就比較過了。
當你乙個個往下找時,每一次都是少乙個然後多乙個,如果少的不是最大值,然後再問新加進來的,看起來很省時間對吧,那麼如果少了的是最大值呢?第二個最大值是什麼??
那麼我們能不能儲存上一次的結果呢?當然主要是i的前k-1個數中的最大值了。答案是可以,這就要用到單調佇列。
對於單調佇列,我們這樣子來定義:
單調佇列實現的大致過程: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
同理,最小值也可以用單調佇列來做。
單調佇列的時間複雜度是o(n),因為每個數隻會進隊和出隊一次,所以這個演算法的效率還是很高的。
注意:建議直接用陣列模擬單調佇列,因為系統自帶容器不方便而且不易除錯,同時,每個數隻會進去一次,所以,陣列絕對不會爆,空間也是s(n),優於堆或線段樹等資料結構。
更重要的:單調是一種思想,當我們解決問題的時候發現有許多冗雜無用的狀態時,我們可以採用單調思想,用單調佇列或類似於單調佇列的方法去除冗雜狀態,儲存我們想要的狀態,
#include#include#include#includeusing namespace std;
struct node
v[1010000]; //x表示值,y表示位置 可以理解為下標
int a[1010000],n,m,mx[1010000],mn[1010000];
void getmin()
for(;i<=n;i++)
stack.push(temp);
}//現在棧中的木板右側沒有比它高的木板,用最右側無限高的木板減
while(!stack.empty())
cout<
return 0;
}
單調棧,單調佇列
大多數借鑑了 單調佇列是什麼呢?可以直接從問題開始來展開。poj 2823 給定乙個數列,從左至右輸出每個長度為m的數列段內的最小數和最大數。數列長度 n 106,m n 我們知道,解法 在暴力列舉的過程中,有乙個地方是重複比較了,就是在找當前的f i 的時候,i的前面其它m 1個數在算f i 1 ...
單調棧 單調佇列
單調棧 單調佇列是在棧和佇列的基礎上加上單調結構的資料結構。如果乙個元素入棧或入隊,他會檢查之前的元素,如果之前的元素不可能是答案的解,那麼就彈出元素,使得當前元素入棧或入隊。leetcode 239 滑動視窗最大值 此題是單調佇列,每次遇到乙個元素,一直從隊尾彈出,直到隊尾元素大於該元素為止。還需...
單調棧 單調佇列
啊學完了來寫個總結吧 顧名思義,單調,就是指色彩單一某乙個容器裡面的元素都是遞增或遞減的,而單調棧和單調佇列就是這個容器。單調棧 單調棧模板 其他的我就不說了,講下為什麼單調棧是從後往前掃瞄 當我們在判斷乙個數後面第乙個比它大的數時,前提是後面的數已經被處理了,所以我們要從後往前掃瞄。我做了兩種做法...