【html-css】02 html的基本結構
阿新 • • 發佈:2022-05-19
單調棧
什麼是單調棧
顧名思義,如果棧中元素單調增(或減),則該棧被稱為單調棧
如何維護單調棧
以維護一個單調增的棧為例, 插入元素2, 1, 4, 5, 3。
-
插入元素2,此時棧中為空,直接入棧;棧中元素:2。
-
插入元素1,棧頂元素2大於1,先出棧,此時棧中為空,插入1;棧中元素:1。
-
插入元素4,棧頂元素1小於4,插入4;棧中元素:1,4。
-
插入元素5,棧頂元素4小於5,插入5;棧中元素:1,4,5。
-
插入元素3,棧頂元素5大於3,先出棧,此時棧頂元素4大於3,再次出棧,最後棧頂元素1小於3,入棧,棧中元素:1,3。
這樣我們就維護了一個單調增的棧了。
核心程式碼
stack<int>sta; void insert(x){ while(!sta.empty() && sta.top() >= x)sta.pop(); sta.push(x); }
應用
題目大意
給定一個數列\(\,a_{i...n}\),找到每一個數向右第一個大於它的數的下標,即\(\,a_i<a_j,i<j,\text {求每一個}\,a_i\text{對應的}\text {min}(j)\),沒有則為0。\((1\le n \le 3\times10^6)\)
題目思路
如果我們直接暴力列舉,對每一個數\(\,a_i\,\)往右進行一次查詢。這種做法的時間複雜度最壞的情況下是 \(O(n^2)\) 的,這無疑是會TLE的。下面考慮優化。
首先觀察一個特殊情況:5,3,3,2,1。顯然每個數都沒有滿足題意的下標,這時如果我們在其右邊在插入一個大小為3的數,則可以模擬以下情況:
- 首先1和2小於3,則都有其對應答案。
- 接下來由於原來數列本身是不嚴格遞減的,所以3及以後的數必定大於等於3,所以後面的數依舊沒有答案。(這裡的不嚴格遞減指的是數列中\(\,a_i\ge a_{i - 1}, \forall\ i \in[1,n)\) 都成立。
- 因為1和2都有答案了,直接退出數列就好,這時,我們可以得到下一個數列:5,3,3,3。我們可以發現,得到的數列依然是一個不嚴格遞減數列。重複上述步驟便可以得出每一個數答案了
經過上面的模擬過程,相信你應該知道為什麼要用單調棧了,我們不妨維護一個不嚴格遞減的單調棧,每次要出棧時記錄答案即可,像上面的1和2一樣。
這便是單調棧的一個簡單應用
程式碼
#include<cstdio>
#include<stack>
int a[3000005]; //記錄答案
int main(void){
int n;
std::stack<int>sta; //記錄資料大小
std::stack<int>ind; //記錄對應下標
scanf("%d",&n);
for(int i=1;i<=n;i++){
int key;
scanf("%d",&key);
while(!sta.empty()&&sta.top()<key){ //單調棧核心程式碼
a[ind.top()]=i; //記錄大於該數的下標
sta.pop();
ind.pop();
}
sta.push(key);
ind.push(i);
}
for(int i=1;i<=n;i++)printf("%d ",a[i]);
return 0;
}