栈和排序
题意:
给你一个入栈排列,要你求字典序最大的出栈序列。
思路:
最先想到的:最先出的肯定是n。(它最大,肯定要在最前面)
反思x1:
我一开始想的时候走远了。错误示范:(以为找到最大n后,就看栈顶和后面的。如果后面有次大就,其它直接入栈直到找到次大。如果次大在前面,就把大于待入栈元素x的栈顶元素先出栈,其实这种思路是错的,假如次大是第一个入栈,那么无论如何都会去 “如果次大在前面,就把大于待入栈元素x的栈顶元素先出栈”,这种情况,假如把栈顶元素出栈了,那么可能后面待入栈元素有更大的,就矛盾了。
所以引进第二种思路,
下文中的待入栈元素
指的是输入,(以用红色标出
)
下文中的栈指的是为解决问题定义的栈。
- 对于找到最大后。
- 考察栈顶元素和
待入栈元素
中的最大(要 O ( n ) O(n) O(n)的查询后面待入栈元素
的最大) - 如果栈顶元素比后面的都大(比
待入栈元素
的最大 大,那么肯定比后面的都大)那么栈顶元素出栈,重复步骤2,3,直到不满足(或栈为空)。 - 3不满足来到4。直到找到
待入栈元素
的最大,其他都入栈。 - 之后重复步骤2
- 当没有
待入栈元素
时,把栈内元素出栈就行了。
AC(数据1e3)
#include <iostream>
#include <stack>
#include <queue>
#define For(i,x,y) for(register int i=(x); i<=(y); i++)
using namespace std;
stack<int>st;
int n,vis[300],x,maxx;
int main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n;
For(i,1,n)
{
cin>>x;
maxx=0;
For(i,1,n)if(!vis[i])maxx=max(i,maxx);
//没见过的元素,就是待入栈元素
while(!st.empty()&&maxx<st.top())
{
cout<<st.top()<<' ';st.pop();
}
st.push(x);
vis[x]=1;//cout<<i<<endl;
}
while(!st.empty())
{
cout<<st.top()<<' ';
st.pop();
}
return 0;
}
反思x2:
很明显,上面的代码,当数据量很大时,是会tle的,因为第2步中0n的查询。
优化方法:
也很简单,对于待入栈元素
,就是后面的元素中的最大值,那么可以用一个suf【】(后缀去预处理位置 i 以后的最大值)
AC(数据1e6)
#include <iostream>
#include <stack>
#include <queue>
#define For(i,x,y) for(register int i=(x); i<=(y); i++)
using namespace std;
const int maxn=1e5+10;
stack<int>st;
int n,x,a[maxn],suf[maxn];//,pre[maxn]maxx,vis[maxn],t,
int main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n;
For(i,1,n)cin>>a[i];
for(int i=n; i>=1; i--)
{
if(a[i]>suf[i+1])suf[i]=a[i];
else suf[i]=suf[i+1];
}
For(i,1,n)
{
x=a[i];
while(!st.empty()&&suf[i]<st.top())
//suf【i】就是优化,省了0n查询
{
cout<<st.top()<<' ';st.pop();
}
st.push(x);
}
while(!st.empty())//把剩下的输出
{
cout<<st.top()<<' ';
st.pop();
}
return 0;
}