18715 出栈序列
Description
一种简洁的栈定义方法如下 int st[1000],top=0;//以top作为栈顶指针,top==0为空栈 st[top++]=x;//把x入栈,栈顶指针+1 top--;//出栈 现在有一个1-n的排列,入栈序列已知,请给出字典序最大的出栈序列。
输入格式
第一行一个整数n。(1<=n<=100) 第二行n个整数,数据确保为1-n的排列。
输出格式
输出n个整数,既字典序最大的出栈序列。
输入样例
5 1 2 4 5 3
输出样例
5 4 3 2 1
一道不错的考察对栈存取理解运用的题目,要求也很简单,数据规模很小(n<=100),数据唯一,因此算法复杂度不用卡太紧就能过。
算法原理:对于一条固定的入栈序列,假设是从左到右依次入栈,则第一个出栈元素能自由选择,不难理解,一直push,直到遇到想pop的元素就好。题目要求出栈序列元素满足字典序从大到小排序,那第一个出栈元素是最大的元素就OK。第i(i不为1)个出栈元素只能从第i-1个出栈元素的左边第一个未出栈元素以及右边所有未进栈元素中选取,右边的序列选择最大的,与左边比较,max(左,右),记录下标,出栈并标记,然后移动指针到该出栈元素的下标,用循环重复这个过程直至将所有元素出栈。
算法复杂度:考408一般都要计算自己写的算法的复杂度。由于每个出栈元素都要在上一个出栈元素左扫描右扫描一次,看作n级别,共有n个元素,因此时间复杂度为O(n^2)。算法额外创建3个大小为n+1的数组,因此空间复杂度为O(n)。
代码:
#include <iostream>
//出栈序列
using namespace std;
int getNext(int a[],int maxi,int next,int n,bool b[])
{
//返回的是下一个出栈的下标
if(next==0)
{
return 0;
}
int last,nexti = maxi+1;
for(int i=maxi-1;i>0;i--)
{
if(!b[i])
{
last = a[i];
maxi = i;
break;
}
}
next = last;
for(int i=nexti;i<=n;i++)
{
if(a[i]>next&&!b[i])
{
maxi = i;
next = a[i];
}
}
return maxi;
}
int main()
{
int n;
cin>>n;
int a[n+1],st[1000];
bool b[n+1];//标记出栈的元素
int maxi = 0;
for(int i=1;i<=n;i++)
{
//初始化
b[i] = false;
cin>>a[i];
if(a[i]==n)
{
maxi = i;//初始化时就找到最大元素的下标
}
}
for(int top=n;top>0;top--)
{
b[maxi] = true;
st[top] = a[maxi];//出栈,记录序列用st[n]到st[1]
maxi = getNext(a,maxi,top-1,n,b);
}
for(int i=n;i>0;i--)
{
cout<<st[i]<<' ';
}
return 0;
}
后记:
n<=100,因此会出现两位数、三位数的情况,但是由于不用将序列拼在一起成一个串,因此,就当它要从大到小输出就好,字典序那里完全是描述有问题,吓唬人。