【图解】L2-1 出栈序列的合法性 (25分)

22 篇文章 0 订阅

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;}
    }
}

本文参考blog

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值