本文摘自部落格,歡迎前往部落格以獲得更好的體驗。從名字上就聽的出來,單調棧中存放的資料應該是嚴格單調有序的,具有以下兩個性質。
滿足從棧頂到棧底的元素具有嚴格的單調遞增或單調遞減性;
滿足棧的後進先出特性,即越靠近棧底的元素越早進棧。
單調棧也分為單調遞增棧和單調遞減棧。
stackst;
for (遍歷這個陣列)
else
當前資料入棧;
}}
如何維護乙個單調棧?出棧很簡單,與普通棧相同,關鍵操作是入棧。
具體進棧過程
對於乙個元素a,如果棧空則直接入棧。否則比較a與棧頂元素。假設乙個單調遞增的棧,若a > 棧頂元素,則直接把a入棧,棧仍滿足單調的性質。若a < 棧頂元素,則將棧頂元素出棧,直到滿足a < 棧頂元素,此時將a入棧。
例子進棧元素分別為3,4,2,6,4,5,2,3
同樣,c++在實現時,我們也可以使用stl中的棧。
柱狀圖中最大的矩形
給定 n 個非負整數,用來表示柱狀圖中各個柱子的高度。每個柱子彼此相鄰,且寬度為 1 。思路:求在該柱狀圖中,能夠勾勒出來的矩形的最大面積。
以上是柱狀圖的示例,其中每個柱子的寬度為 1,給定的高度為 [2,
圖中陰影部分為所能勾勒出的最大矩形面積,其面積為 10
1010
個單位。
那麼,該如何去尋找左右邊界值呢?
這時,我們便可以使用單調棧進行優化。
在思路中,我們列舉高說向左右遍歷尋找。未來降低時間複雜度,我們可以使用單調棧只向一邊遍歷。
當第i個柱子進棧時,如果棧頂的高度低於或等於第i個柱子,則第i個柱子進棧;
如果棧頂的高度高於第i個柱子,則出棧,並計算以柱子a為高的矩形最大面積。
同時,為防止越界問題,我們可以在左右兩側虛擬兩根無限低的柱子,記高度為 0
00 。
c
int largestrectanglearea(int* heights, int heightssize)
buff[heightssize + 1] = 0;
stack[++top] = 0;
for (i = 1; i < heightssize + 2; i++)
stack[++top] = i;
}return maxarea;
}
c++
int largestrectanglearea(vector& heights)
left[i] = (mono_stack.empty() ? -1 : mono_stack.top());
mono_stack.push(i);
}int ans = 0;
for (int i = 0; i < n; ++i)
return ans;
}
佇列中元素之間的關係具有嚴格單調有序性,而且,隊首和隊尾都可以進行出隊操作,只有隊尾可以進行入隊操作。因此,在單調佇列中求最值十分容易。
單調佇列與普通佇列有些不同,因為右端既可以插入又可以刪除,因此在**中通常用乙份陣列和 rea
rrear
rear
與 rear
rear
rear
兩個指標來實現,而不是使用 stl 中的 que
uequeue
queu
e。如果一定要使用 stl ,那麼則可以使用雙端佇列(即兩端都可以插入和刪除),即 deq
uedeque
deque 。
在談及單調棧時,無需關心棧的大小。而對於佇列,佇列的大小就很重要了。如果佇列滿了,我們的解決方法是,將佇列頭的元素彈出,再新增新的元素到佇列尾。
具體入隊過程 例子
佇列大小不能超過3,入隊元素依次為3,2,8,4,5,7,6,4
滑動視窗
給定乙個數列,從左至右輸出每個長度為m
mm的數列段內的最小數和最大數。
window position
minimum value
maximum value
[1 3 -1] -3 5 3 6 7-13
1 [3 -1 -3] 5 3 6 7-33
1 3 [-1 -3 5] 3 6 7-35
1 3 -1 [-3 5 3] 6 7-35
1 3 -1 -3 [5 3 6] 736
1 3 -1 -3 5 [3 6 7]37
數列長度:n
<=1
06n <= 10^6
n<=1
06,m
<=n
m<=n
m<=n
#include #include #include using namespace std;
const int maxn = 1e6+5;
int n, k, a[maxn];
int q[maxn];//佇列,存的是下標
int main()
//維護最大值,同上
putchar('\n');
memset(q,0,sizeof(q));
front = 1, rear = 0;
for(int i = 1; i <= n; ++i)
return 0;
}
單調佇列
可以查詢區間最值(不能維護區間k大,因為佇列中很有可能沒有k個元素)
優化dp
單調佇列一般是用於優化動態規劃方面問題的一種特殊資料結構,且多數情況是與定長連續子區間問題相關聯。
單調棧左邊區間第乙個比它小的數,第乙個比它大的數
確定這個元素是否是區間最值
右邊區間第乙個大於它的值
到 右邊區間第乙個大於它的值 的距離
確定以該元素為最值的最長區間
單調佇列和單調棧的「頭部」都是最先新增的元素,「尾部」都是最後新增的元素。
遞增和遞減的判斷依據相同:從棧底(隊尾)到棧頂(隊首),元素大小的變化情況。所以佇列和棧是相反的。
兩者維護的時間複雜度都是o(n
)o(n)
o(n)
,每個元素都只操作一次。
單調佇列可以從佇列頭彈出元素,可以方便地根據入隊的時間順序(訪問的順序)刪除元素。
單調佇列和單調棧維護的區間不同。當訪問到第i個元素時,單調棧維護的區間為[0,
i)[0, i)
[0,i
),而單調佇列維護的區間為(la
stpo
p,i)
(lastpop, i)
(lastp
op,i
)單調棧無法獲取[0,
i)[0, i)
[0,i
)的區間最大值/最小值。因為單調佇列可以訪問「頭部」和「尾部」,而單調棧只能訪問棧頂(也就是「尾部」)。
棧和佇列 單調佇列 單調棧
講解部落格鏈結 一 單調棧 1 什麼是單調棧?單調棧是指乙個棧內部元素具有嚴格單調性 單調遞增,單調遞減 的一種資料結構。2 單調棧的兩個性質 滿足從棧頂到棧底具有嚴格的單調性 滿足後進先出的特徵,越靠近棧底的元素越早的進棧。3 元素進棧的過程 對於當前進棧元素x 如果x 棧頂元素,x 進棧。否則 ...
單調棧和單調佇列
最近又在重新刷題,又看到了單調棧和單調佇列的題目,發現當時也就是背一背就過了,沒有領會到精髓,這次看了幾位前輩寫的心得,感覺理解深了一些。傳送門 關鍵 用單調佇列來解決問題,一般都是需要得到當前的某個範圍內的最小值或最大值。就比如滑動視窗中的最大值問題 eg 1,1,2,3,4 5,6,7,7,9 ...
單調棧和單調佇列
用陣列模擬出單調棧和單調佇列 單調棧常常用來維護離最近的比當前值小或大的值,單調佇列維護乙個固定區間的最小或最大值 單調棧維護乙個左邊比他小的值的 1 include2 using namespace std 3int st 100010 n,a 100010 4 inttt 5int main 6...