單調棧和單調佇列

2021-10-19 09:23:20 字數 3813 閱讀 6630

本文摘自部落格,歡迎前往部落格以獲得更好的體驗。

從名字上就聽的出來,單調棧中存放的資料應該是嚴格單調有序的,具有以下兩個性質。

滿足從棧頂到棧底的元素具有嚴格的單調遞增或單調遞減性;

滿足棧的後進先出特性,即越靠近棧底的元素越早進棧。

單調棧也分為單調遞增棧和單調遞減棧。

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...