棧和排序
題意:
給你一個入棧排列,要你求字典序最大的出棧序列。
思路:
最先想到的:最先出的肯定是n。(它最大,肯定要在最前面)
反思x1:
我一開始想的時候走遠了。錯誤示範:(以爲找到最大n後,就看棧頂和後面的。如果後面有次大就,其它直接入棧直到找到次大。如果次大在前面,就把大於待入棧元素x的棧頂元素先出棧,其實這種思路是錯的,假如次大是第一個入棧,那麼無論如何都會去 “如果次大在前面,就把大於待入棧元素x的棧頂元素先出棧”,這種情況,假如把棧頂元素出棧了,那麼可能後面待入棧元素有更大的,就矛盾了。
所以引進第二種思路,
下文中的待入棧元素
指的是輸入,(以用紅色標出
)
下文中的棧指的是爲解決問題定義的棧。
- 對於找到最大後。
- 考察棧頂元素和
待入棧元素
中的最大(要0n的查詢後面待入棧元素
的最大) - 如果棧頂元素比後面的都大(比
待入棧元素
的最大 大,那麼肯定比後面的都大)那麼棧頂元素出棧,重複步驟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;
}