模板 | 單調(diào)棧求左右節(jié)點鄰近最小值
適用樣例:
給出長度為n的數(shù)組a,求數(shù)組中每個節(jié)點左右出現(xiàn)的第一個比該節(jié)點小的下標(biāo)。
樣例輸入:n:5,a={1,4,2,3,5}。
輸出結(jié)果:
編號(點) | 左端 | 右端 |
---|---|---|
1 | 0 | 0 |
2 | 1 | 3 |
3 | 1 | 0 |
4 | 3 | 0 |
5 | 4 | 0 |
代碼詳解:
本題用單調(diào)棧進行求解,當(dāng)進行遍歷時,可知當(dāng)出現(xiàn)棧頂比當(dāng)前節(jié)點大時,說明當(dāng)前節(jié)點就是右邊第一個比棧頂小的,用樣例模擬:
編號(點) | 狀態(tài) |
---|---|
1 | 1 |
2 | 1,4 |
3 | 1,4,2 |
彈出后剩余 | 1,2 |
代碼如下:
//當(dāng)棧不為空且節(jié)點小于棧頂時
while(!q.empty() && a[q.top()]>a[i])
{
int now=q.top();
//此時a[q.top()]>a[i],說明該節(jié)點是所有能彈出節(jié)點第一個比他小的值
r[now]=i;
q.pop();
}
q.push(i);
在確定右端值后,怎么確定左端值呢,通過樣例可以發(fā)現(xiàn)彈出的節(jié)點是大于此時的棧頂?shù)?,畢竟棧是從大到小排的,所以彈出?jié)點的后的棧頂,即為彈出節(jié)點的左端值。
//當(dāng)棧不為空且節(jié)點小于棧頂時
while(!q.empty() && a[q.top()]>a[i])
{
int now=q.top();
//此時a[q.top()]>a[i],說明該節(jié)點是所有能彈出節(jié)點第一個比他小的值
r[now]=i;
q.pop();
//棧中從小到大排序,所以彈出節(jié)點的左節(jié)點就是他第一個比他小的值
if (!q.empty())l[now]=q.top();
}
q.push(i);
繼續(xù)模擬樣例:
編號(點) | 狀態(tài) |
---|---|
彈出后剩余 | 1,2 |
4 | 1,2,3 |
5 | 1,2,3,5 |
此時我們會發(fā)現(xiàn)當(dāng)樣例從小到大排時,棧無法彈出,所以需要在遍歷結(jié)束后添加一段檢驗棧是否為空的代碼。
//當(dāng)出現(xiàn)節(jié)點一直從小到大排序時,棧不會為空
while(!q.empty())
{
//彈出節(jié)點,此時遍歷結(jié)束,說明剩余節(jié)點的右側(cè)以不存在比他們小的值
int now=q.top();
r[now]=0;
q.pop();
//當(dāng)節(jié)點還有剩余,說明他的左側(cè)存在比他小的節(jié)點
if (!q.empty())l[now]=q.top();
}
至此,就能得出模板代碼為:
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6+10;
int n;
int a[N];
int l[N],r[N];
stack<int>q;
int main() {
cin >>n;
for (int i=1;i<=n;i++)cin >>a[i];
//遍歷節(jié)點
for (int i=1;i<=n;i++)
{
//當(dāng)棧不為空且節(jié)點小于棧頂時
while(!q.empty() && a[q.top()]>a[i])
{
int now=q.top();
//此時a[q.top()]>a[i],說明該節(jié)點是所有能彈出節(jié)點第一個比他小的值
r[now]=i;
q.pop();
//棧中從小到大排序,所以彈出節(jié)點的左節(jié)點就是他第一個比他小的值
if (!q.empty())l[now]=q.top();
}
q.push(i);
}
//當(dāng)出現(xiàn)節(jié)點一直從小到大排序時,棧不會為空
while(!q.empty())
{
//彈出節(jié)點,此時遍歷結(jié)束,說明剩余節(jié)點的右側(cè)以不存在比他們小的值
int now=q.top();
r[now]=0;
q.pop();
//當(dāng)節(jié)點還有剩余,說明他的左側(cè)存在比他小的節(jié)點
if (!q.empty())l[now]=q.top();
}
for (int i=1;i<=n;i++)cout <<l[i]<<' '<<r[i]<<"\n";
return 0;
}