大多數借鑑了:
單調佇列是什麼呢?可以直接從問題開始來展開。
poj 2823
給定乙個數列,從左至右輸出每個長度為m的數列段內的最小數和最大數。
數列長度:n<=106,m<=n
我們知道,解法①在暴力列舉的過程中,有乙個地方是重複比較了,就是在找當前的f(i)的時候,i的前面其它m-1個數在算f(i-1)的時候我們就比較過了。
當你乙個個往下找時,每一次都是少乙個然後多乙個,如果少的不是最大值,然後再問新加進來的,看起來很省時間對吧,那麼如果少了的是最大值呢?第二個最大值是什麼??
那麼我們能不能儲存上一次的結果呢?當然主要是i的前k-1個數中的最大值了。答案是可以,這就要用到單調佇列。
對於單調佇列,我們這樣子來定義:
1、維護區間最值
2、去除冗雜狀態 如上題,區間中的兩個元素a[i],a[j](假設現在再求最大值)
若 j>i且a[j]>=a[i] ,a[j]比a[i]還大而且還在後面(目前a[j]留在佇列肯定比a[i]有用,因為你是往後推, 核心思想 !!!)
3、保持佇列單調,最大值是單調遞減序列,最小值反之
4、最優選擇在隊首
單調佇列實現的大致過程:
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
}
單調棧 單調佇列
單調棧 單調佇列是在棧和佇列的基礎上加上單調結構的資料結構。如果乙個元素入棧或入隊,他會檢查之前的元素,如果之前的元素不可能是答案的解,那麼就彈出元素,使得當前元素入棧或入隊。leetcode 239 滑動視窗最大值 此題是單調佇列,每次遇到乙個元素,一直從隊尾彈出,直到隊尾元素大於該元素為止。還需...
單調棧 單調佇列
啊學完了來寫個總結吧 顧名思義,單調,就是指色彩單一某乙個容器裡面的元素都是遞增或遞減的,而單調棧和單調佇列就是這個容器。單調棧 單調棧模板 其他的我就不說了,講下為什麼單調棧是從後往前掃瞄 當我們在判斷乙個數後面第乙個比它大的數時,前提是後面的數已經被處理了,所以我們要從後往前掃瞄。我做了兩種做法...
單調棧 單調佇列
最近打了三場比賽瘋狂碰到單調棧和單調佇列的題目,第一,二兩場每場各乙個單調棧,第三場就碰到單調佇列了。於是乎就查各種部落格,找單調棧,單調佇列的模板題去做,搞著搞著發現其實這兩個其實是一回事,只不過利用了容器內元素單調的不同特性,用來加速處理不同的問題。單調棧解決的是以某個值為最小 最大 值的最大區...