如果在彈棧的時候,遇到了一個 h[ pos ] == h[ cur ] ,那么當彈完棧后,此時棧頂的位置到 cur 的位置之間一定是存在著一個位置 pos 使得 h[ pos ] == h[ cur ] 的,此時的棧頂無法給 cur 轉移狀態
如果沒有遇到的話,那么在彈完棧后,可以保證棧頂到 cur 之間的數都嚴格大于 h[ cur ],證明還是和上面的反證法一樣,假設存在一個數 x ∈ [ 棧頂 , cur ] ,且 x 小于等于 h[ cur ] ,那么在之前維護單調棧的時候,棧頂早就被彈出去了,所以得證,此時棧頂是可以向 cur 位置進行狀態轉移的
理論比較復雜,但是代碼實現起來比較簡單,我是用 stl 的棧寫的,可能看起來比較繞一些
代碼: ?
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
using namespace std;typedef long long LL;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=3e5+100;int h[N],dp[N];stack<int>st1,st2;int main()
{
#ifndef ONLINE_JUDGE
// freopen("data.in.txt","r",stdin);
// freopen("data.out.txt","w",stdout);
#endif
// ios::sync_with_stdio(false);memset(dp,inf,sizeof(dp));int n;scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d",h+i);dp[1]=0;st1.push(1);st2.push(1);for(int i=2;i<=n;i++){bool flag1=false,flag2=false;while(st1.size()&&h[st1.top()]>=h[i]){if(h[st1.top()]==h[i])flag1=true;dp[i]=min(dp[i],dp[st1.top()]+1);st1.pop();}if(st1.size()&&!flag1)dp[i]=min(dp[i],dp[st1.top()]+1);while(st2.size()&&h[st2.top()]<=h[i]){if(h[st2.top()]==h[i])flag2=true;dp[i]=min(dp[i],dp[st2.top()]+1);st2.pop();}if(st2.size()&&!flag2)dp[i]=min(dp[i],dp[st2.top()]+1);st1.push(i);st2.push(i);}printf("%d\n",dp[n]);return 0;
}