利用单调栈高效的求出,一个数a[i]在哪个区间内可作为最小值存在。
正向扫描,求出a[i]可做为最小值的区间的左边界
反向扫描,求出a[i]可作为最小值的区间的右边界
r[i] - l[i] +1 就是a[i]可作为最小值的区间的 最大长度
我们知道:长度为len的区间,包含长度为len-1的区间
所以最后,需要逆向[确保无后效性]更新答案数组,保留最大值。
#include<stdio.h> #include<math.h> #include<cstring> #include<stack> #include<iostream> #include<algorithm> #include<queue> #define MAXSIZE 200005 #define LL long long using namespace std; const int INF=999999999; int a[MAXSIZE],l[MAXSIZE],r[MAXSIZE],s[MAXSIZE],dp[MAXSIZE]; int main() { memset(dp,0,sizeof(dp)); memset(s,0,sizeof(s)); int n,top; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); top = 0; for(int i=1;i<=n;i++) //递增栈 { if(top==0) { s[++top] = i; l[i] = i; } else { while(top>=1 && a[s[top]]>=a[i]) { top--; } if(top==0) l[i] = 1; else l[i] = s[top]+1; s[++top] = i; } } top = 0; for(int i=n;i>=1;i--) { if(top==0) { s[++top] = i; r[i] = i; } else { while(top>=1 && a[s[top]]>=a[i]) { top--; } if(top==0) r[i] = n; else r[i] = s[top]-1; s[++top] = i; } } for(int i=1;i<=n;i++) { dp[r[i]-l[i]+1] = max(dp[r[i]-l[i]+1],a[i]); } for(int i=n-1;i>=1;i--) { dp[i] = max(dp[i+1],dp[i]); } for(int i=1;i<=n;i++) { printf("%d%c",dp[i],i==n?' ':' '); } return 0; }