L2-1 出栈序列的合法性 (25分)
题目:
给定一个最大容量为 M 的堆栈,将 N 个数字按 1, 2, 3, …, N 的顺序入栈,允许按任何顺序出栈,则哪些数字序列是不可能得到的?例如给定 M=5、N=7,则我们有可能得到{ 1, 2, 3, 4, 5, 6, 7 },但不可能得到{ 3, 2, 1, 7, 5, 6, 4 }。
输入格式:
输入第一行给出 3 个不超过 1000 的正整数:M(堆栈最大容量)、N(入栈元素个数)、K(待检查的出栈序列个数)。最后 K 行,每行给出 N 个数字的出栈序列。所有同行数字以空格间隔。
输入样例:
5 7 5
1 2 3 4 5 6 7
3 2 1 7 5 6 4
7 6 5 4 3 2 1
5 6 4 3 7 2 1
1 7 6 5 4 3 2
输出样例:
YES
NO
NO
YES
NO
思路:
5 6 4 3 7 2 1
是题目所给的一组合法数据。
程式读入第一个元素 5:
设想一下,栈中第一个弹出元素为5,意味着什么 ?
没错!你猜对了,栈中能弹出5,是因为栈中已经有1 2 3 4 5共五个元素了对吧。
【5】
【4】
【3】
【2】
【1】
虽说是图解,但懒得画图,只能用这种骚操作了。
这也意味着:1 2 3 4在5被弹出之前早已入栈,在未来的操作中,这几个元素只可能出栈,不可能再次入栈。
所以我们建立一个变量start
,这里称它为“入栈顺序”,题目要求我们入栈顺序是1 2 3 4 5 6 7……
,start正是来维持这个顺序的,我们把它初始化为1,栈中每存入一个数据,start+1,倘若存入的数据不等于start,则破坏了这种入栈顺序,故是一种不可能的序列!
看到这里你已经晕了吗?晕就对了!!我觉得这部分结合末尾的程式会好理解些。
看上面那组红色的数据,5是第一个被弹出的,我们弹出它!
【4】
【3】
【2】
【1】
猜一猜现在入栈顺序到几啦??肯定是 6 啦,为什么是6 ,第一,start是从1开始++的,第二,入栈顺序start不会因为有元素弹出而改变!
程式读入第二个元素 6:
元素6从来没有入栈,而且符合入栈顺序 ,so
【6】
【4】
【3】
【2】
【1】
当然,它也是第二个被弹出的元素,这时弹出 6:
【4】
【3】
【2】
【1】
此时入栈顺序start到 7
程式读入第三个元素 4:
元素4是栈顶元素,刚好也是第三个被弹出的元素:
把他弹出就是了
【3】
【2】
【1】
此时入栈顺序start到 7
程式读入第四个元素3:
跟上面一样,3是栈顶,弹!
【2】
【1】
此时入栈顺序start到 7
程式读入第五个元素 7:
7 符合入栈顺序,压入到栈中
【7】
【2】
【1】
7也是第五个被弹出的元素,so,弹就对了
【2】
【1】
此时入栈顺序start到 8
程式读入第六个元素 2:
2是栈顶元素 ,弹
【1】
程式读入最后一个元素 1 :
弹出后栈就 empty 了。
如果看不懂图解就看程式吧,模拟几次程式应该很快能看懂
AC代码:
#include "iostream"
#include "stack"
using namespace std;
int main(){
int M,N,K,num,start,flag;
cin>>M>>N>>K;
for (int i=0;i<K;i++){
stack<int>st;
start = 1;flag = 1;
for (int j=0;j<N;j++){
cin>>num;
while (start<=num)st.push(start++);
// 不空,不爆并且读入的元素是栈顶元素
if (!st.empty()&&st.size()<=M&&num==st.top())st.pop();
else flag = 0;
}
if (flag){cout<<"YES"<<endl;}
else {cout<<"NO"<<endl;}
}
}