代码源:55、出栈序列判断

386 阅读3分钟

本文已参与[新人创作礼]活动,一起开启掘金创作之路 logo.png

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

题目描述

这是3月12日代码源div2的每日一题。

知识点:栈

出栈序列判断 - 题目 - Daimayuan Online Judge

现在有一个栈,有n个元素,分别为1,2,…,n。我们可以通过push和pop操作,将这n个元素依次放入栈中,然后从栈中弹出,依次把栈里面的元素写下来得到的序列就是出栈序列。

比如n=3,如果执行push 1, push 2, pop, push 3, pop, pop,那么我们pop操作得到的元素依次是2,3,1。也就是出栈序列就是2,3,1。

现在给定一个合法的出栈序列,请输出一个合法的由push和pop操作构成的出栈序列。这里要求push操作一定是按1,2,…,n的顺序。

输入格式

第一行一个整数n,接下来一行n个整数,表示出栈序列。

输出格式

输出2n行,每行一个push xpop的操作,可以发现一个出现序列对应的操作序列是唯一的。

样例输入1

3
2 3 1

样例输出1

push 1
push 2
pop
push 3
pop
pop

数据规模

对于100%100%的数据,保证1≤n≤100000,出栈序列一定是个合法的出栈序列。

问题解析

这题就是很直接的用栈模拟,先模拟一遍入栈,最后再全部出栈。

我们从1到n开始一个个入栈并输出push i,然后我们比较当前栈顶元素与题目给出栈序列的元素(初始从第一个元素开始),如果相同,则把这个元素出栈并输出pop。然后继续用新的栈顶元素对比出栈序列元素,因为可能会有连续出栈的情况,比如出栈序列是1 4 3 2 5,就是连续出栈3个元素,重复以上操作直到栈为空或者栈顶元素与题目所给序列元素不相等为止。

当我们模拟从1到n的入栈后,剩下的就是无脑出栈了,栈内有多少元素就输出多少pop。

AC代码

用栈模拟

#include<iostream>
using namespace std;
#include<vector>
#include<stack>

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int n;
    cin >> n;
    vector<int>v(n);
    for (int i = 0; i < n; i++)cin >> v[i];
    int ans = 0;
    stack<int>sta;
    for (int i = 1; i <= n; i++)
    {
        sta.push(i);
        cout << "push " << i << '\n';
        while (!sta.empty()&&sta.top() == v[ans])
        {
            sta.pop();
            ans++;
            cout << "pop" << '\n';
        }
    }
    while (!sta.empty())
    {
        sta.pop();
        cout << "pop" << '\n';
    }
    return 0;
}

用vector模拟

#include<iostream>
using namespace std;
#include<vector>

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int n;
    cin >> n;
    vector<int>v(n);
    for (int i = 0; i < n; i++)cin >> v[i];
    int ans = 0;
    vector<int>sta;
    for (int i = 1; i <= n; i++)
    {
        cout << "push" <<" "<< i << '\n';
        if (i == v[ans])
        {
            cout << "pop" << '\n';
            ans++;
            while (!sta.empty() && sta.back() == v[ans])
            {
                sta.pop_back();
                ans++;
                cout << "pop" << '\n';
            }
        }
        else
        {
            sta.push_back(i);
        }
        
    }
    while (!sta.empty())
    {
        sta.pop_back();
        cout << "pop" << '\n';
    }
    return 0;
}
  • 时间复杂度:O(n)

最后

虽然我们的解法时间复杂度为O(n),而且此题目的数据范围也只有10^5,但实际上我们提交的时候还是容易超时(这里给出的代码都是可以正确AC的)。

这是因为cout和cin的效率所导致的,cin和cout的运行效率较scanf和printf较慢,虽然大多数时候这一因素并不会使得我们超时,但这题,我们要根据题目给的n输出2n条语句,这是比较可怕的,所以为了对应这一因素,我们要么使用scanf和printf做输入输出操作,要么关闭流同步。还有一点就是换行符我们不应该使用endl,而是\n,这也是使得代码TLE的元凶之一。对此知识感兴趣的可以自行搜索相关文章,这里便不多做赘述。