解题思路:出栈序列字典序最大,可以很自然想到应该让最大的n第一个进栈再出栈,然后面临两个选择(1)继续出栈顶元素(2)继续入栈元素。
为了让字典序更大,应该在两种选择中选到值更大的元素。因此算法设计时每次出栈前都要判断(1)和(2)的最大值,决定是入栈还是出栈。实现算法时可以把第一个元素n也作为一般情况处理,具体请参看代码。
#include <iostream>
using namespace std;
int a[10005],n,s[100005],top=0;/**< s为栈结构,top为栈顶指针 */
int main()
{
int i,j=1,k,x;
cin>>n;
for(i=1;i<=n;i++)
cin>>a[i];
for(i=1;i<=n;i++)
{/**< 算法思想:判断可以出栈的栈顶元素和尚未入栈的元素哪个更大 */
int maxs=a[j];/**< 先找到还没入栈的元素中最大值 */
for(k=j;k<=n;k++)
maxs=max(maxs,a[k]);
if(top==0||s[top-1]<maxs)/**< 空栈或栈顶元素<未入栈最大值 */
{
while(a[j]!=maxs) /**< 将后面的元素依次入栈 */
s[top++]=a[j++];
cout<<maxs<<' ';
j++;/**< 跳过这个maxs值 */
}
else
cout<<s[--top]<<' ';/**< 栈顶元素更大,出栈 */
}
return 0;
}
优化:上面算法复杂度O(n^2)。求取未入栈最大值实际上是求 [j,n] 区间的最大值,可以用后缀极值数组进行优化,将复杂度降为O(n)。
int i,j,n,a[100005],mx[100005]={0}; cin>>n; for(i=1;i<=n;i++) cin>>a[i]; for(i=n;i>=1;i--) mx[i]=max(a[i],mx[i+1]);
上述代码构造后缀极值数组, 区间 [i,n]的最大值即为mx[i],这样无需循环去找区间最大值。