题解:P4387 【深基15.习9】验证栈序列
简化题目
这个题目实际上有很多要注意的地方,所以我们先尝试从简单的类似问题入手。
以下文段可以在我的博客里阅读 验证栈序列
输入一个
第二行
第一种情况:
第
那我们来思考是不是只用记录
答案是肯定的,因为出栈只需要不断地判断栈顶,所以我们只需要维护栈顶
但是如果
第二种情况:
即第
特殊情况:
比如
出现
按照上述算法会发现,当判断
显然,应该先让
代码:
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int a[100005];
bool check(int n){
bool s[100005];//记录i是否已经合法出栈
stack<int>q;//储存当前栈顶元素
int maxx=0;//记录最大值
for(int i=1;i<=n;i++){
if(a[i]>maxx){//最大值一定可以入栈并出栈
maxx=a[i];
//特别的,a[i]==1时不能记录1-1即0
if(!s[a[i]-1]&&a[i]>1)q.push(a[i]-1);//记录栈顶
s[a[i]]=1;
}
else{
if(q.empty()){//栈空也可以正常弹出
s[a[i]]=1;
if(!s[a[i]-1]&&a[i]>1)q.push(a[i]-1);
continue;
}
if(q.top()==a[i]){
q.pop();
s[a[i]]=1;
if(!s[a[i]-1]&&a[i]>1)q.push(a[i]-1);
continue;
}
return 0;
}
}
return 1;
}
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
cout<<check(n);
return 0;
}
针对本题的解法
从刚才的算法中我们解决了元素为
实际上本题也可以转化为
我选择的是一种简单但时间复杂度比较高的方法:
map映射大法
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int a[100005];
bool s[100005];//记录i是否已经合法出栈
bool check(int n){
stack<int>q;//储存当前栈顶元素
memset(s,0,sizeof(s));
int maxx=0;
for(int i=1;i<=n;i++){
if(a[i]>maxx){//最大值一定可以入栈并出栈
maxx=a[i];
if(!s[a[i]-1]&&a[i]>1)q.push(a[i]-1);//记录栈顶
s[a[i]]=1;
}
else{
if(q.empty()){
s[a[i]]=1;
if(!s[a[i]-1]&&a[i]>1)q.push(a[i]-1);
continue;
}
if(q.top()==a[i]){
q.pop();
s[a[i]]=1;
if(!s[a[i]-1]&&a[i]>1)q.push(a[i]-1);
continue;
}
return 0;
}
}
return 1;
}
map<int,int>mp;
int main(){
int t;
cin>>t;
while(t--){
memset(a,0,sizeof(a));
mp.clear();
int n;
cin>>n;
for(int i=1;i<=n;i++){
int x;
cin>>x;
mp[x]=i;
}
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++){
a[i]=mp[a[i]];
}
if(check(n))cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
return 0;
}