top1编程
← 返回题目
题解

出栈序列

1 条题解

  • 0
    @ 2026-8-7 12:55:51

    P4830 出栈序列(入门)

    解题思路

    第一步,想清楚什么才是"合理"的出栈顺序。 有5个不同的整数,按读入的顺序一个接一个地压进栈里。不过程序可以"边进边出":压进几个之后,先让栈顶的元素弹出,再继续压后面的。题目给的出栈顺序,必须能够真的按照这样的过程发生,才算"合理"。

    第二步,用一个真实的栈来"演一遍"。 我们把题目给出的可能出栈顺序记到数组 b 里,用变量 j 指向 b 中当前要出的是第几个。然后按照入栈顺序,把数字一个个压进栈 st。每压进一个数字,就检查一下:栈顶是不是正好等于 b[j]?如果是,就弹出栈顶,同时 j 加1;因为弹出后栈顶又会变成新元素,所以要循环检查,直到栈顶不再匹配为止。

    第三步,举个具体的例子。 入栈顺序是 3 6 2 5 4,目标出栈顺序是 2 6 3 5 4。先压入3、6、2,这时栈顶是2,正好等于目标里的第一个数2,弹出;栈顶变成6,等于目标的第二个数6,弹出;栈顶变成3,等于第三个数3,弹出。接着压入5、弹出5,压入4、弹出4。五个数全部弹出,所以输出 yes。

    第四步,想想为什么这样判断是对的。 栈的特点就是"后进先出",只有栈顶的元素才能弹出。我们只在栈顶恰好等于目标数字时才弹出,绝不跳着弹,所以模拟出来的就是真实的进出栈过程。只要目标顺序能从头到尾全部弹出,就说明它确实可以实现;如果最后 j 没有数到5,就说明中途卡住了,输出 no。边界情况:如果弹出的数字在栈里根本找不到(比如想弹出还没压进去的数),程序也会自然失败。

    参考代码

    // 出栈序列:模拟入栈过程,验证给出的出栈顺序是否合法
    #include <iostream>
    using namespace std;
    
    int main() {
        int a[10], b[10], st[10];
        int i;
        // 读入5个入栈数字和5个期望出栈数字
        for (i = 0; i < 5; i++) cin >> a[i];
        for (i = 0; i < 5; i++) cin >> b[i];
        int top = 0;  // 栈顶指针,st[top]是栈顶元素
        int j = 0;    // 已匹配好的出栈数字个数
        for (i = 0; i < 5; i++) {
            st[top++] = a[i];  // 按读入顺序入栈
            // 栈顶正好是要出栈的数字就不断弹出
            while (top > 0 && st[top - 1] == b[j]) {
                top--;
                j++;
            }
        }
        // 全部5个数字都按顺序出栈,说明序列合法
        if (j == 5) cout << "yes" << endl;
        else cout << "no" << endl;
        return 0;
    }
    

    复杂度分析

    本题固定是5个整数,每个数字最多压入栈一次、弹出栈一次,所以只需要常数次操作,时间复杂度是 O(1),空间上栈的大小也固定是5个格子,空间复杂度 O(1)。如果把题目推广到 n 个数字,那么每个数字同样最多入栈出栈各一次,时间复杂度就是 O(n),空间复杂度 O(n)。

    • 1