【946. 验证栈序列】

来源:力扣(LeetCode)

描述:

给定 pushedpopped 两个序列,每个序列中的 值都不重复,只有当它们可能是在最初空栈上进行的推入 push 和弹出 pop 操作序列的结果时,返回 true;否则,返回 false

示例 1:

输入:pushed = [1,2,3,4,5], popped = [4,5,3,2,1]
输出:true
解释:我们可以按以下顺序执行:
push(1), push(2), push(3), push(4), pop() -> 4,
push(5), pop() -> 5, pop() -> 3, pop() -> 2, pop() -> 1

示例 2:

输入:pushed = [1,2,3,4,5], popped = [4,3,5,1,2]
输出:false
解释:1 不能在 2 之前弹出。

提示:

  • 1 <= pushed.length <= 1000
  • 0 <= pushed[i] <= 1000
  • pushed 的所有元素 互不相同
  • popped.length == pushed.length
  • popped 是 pushed 的一个排列

方法:栈模拟

这道题需要利用给定的两个数组 pushed 和 popped 的如下性质:

  • 数组 pushed 中的元素互不相同;

  • 数组 popped 和数组 pushed 的长度相同;

  • 数组 popped 是数组 pushed 的一个排列。

根据上述性质,可以得到如下结论:

  • 栈内不可能出现重复元素;

  • 如果 pushed 和 popped 是有效的栈操作序列,则经过所有的入栈和出栈操作之后,每个元素各入栈和出栈一次,栈为空。

因此,可以遍历两个数组,模拟入栈和出栈操作,判断两个数组是否为有效的栈操作序列。

模拟入栈操作可以通过遍历数组 pushed 实现。由于只有栈顶的元素可以出栈,因此模拟出栈操作需要判断栈顶元素是否与 popped 的当前元素相同,如果相同则将栈顶元素出栈。由于元素互不相同,因此当栈顶元素与 popped 的当前元素相同时必须将栈顶元素出栈,否则出栈顺序一定不等于 popped。

根据上述分析,验证栈序列的模拟做法如下:

  1. 遍历数组 pushed,将 pushed 的每个元素依次入栈;

  2. 每次将 pushed 的元素入栈之后,如果栈不为空且栈顶元素与 popped 的当前元素相同,则将栈顶元素出栈,同时遍历数组 popped,直到栈为空或栈顶元素与 popped 的当前元素不同。

遍历数组 pushed 结束之后,每个元素都按照数组 pushed 的顺序入栈一次。如果栈为空,则每个元素都按照数组 popped 的顺序出栈,返回 true。如果栈不为空,则元素不能按照数组 popped 的顺序出栈,返回 false。

代码:

class Solution {
public:
    bool validateStackSequences(vector<int>& pushed, vector<int>& popped) {
        stack<int> st;
        int n = pushed.size();
        for (int i = 0, j = 0; i < n; i++) {
            st.emplace(pushed[i]);
            while (!st.empty() && st.top() == popped[j]) {
                st.pop();
                j++;
            }
        }
        return st.empty();
    }
};

执行用时:4 ms, 在所有 C++ 提交中击败了95.94%的用户
内存消耗:15 MB, 在所有 C++ 提交中击败了16.99%的用户
复杂度分析
时间复杂度: O(n),其中 n 是数组 pushed 和 popped 的长度。需要遍历数组 pushed 和 popped 各一次,判断两个数组是否为有效的栈操作序列。
空间复杂度: O(n),其中 n 是数组 pushed 和 popped 的长度。空间复杂度主要取决于栈空间,栈内元素个数不超过 n。
author:LeetCode-Solution

### 顺序的实现 以下是基于 C++ 的顺序实现,涵盖了初始化、入、出、判断是否为空以及释放的功能。代码还包含了一个主函数来展示这些基本操作。 #### 初始化顺序 通过定义一个结构体 `SeqStack` 来表示顺序,并分配初始空间用于存储中的字符数据[^1]。 ```cpp #define MAX_SIZE 100 // 定义大容量 typedef struct { char data[MAX_SIZE]; // 存储中元素的数组 int top; // 顶指针 } SeqStack; ``` #### 创建并初始化 初始化时需将顶指针设置为 `-1` 表示为空状态[^2]。 ```cpp void InitStack(SeqStack &s) { s.top = -1; // 初始状态下,顶指针指向 -1 } ``` #### 入操作 当向中压入新元素时,先检查是否已满;如果未满,则将新元素存放到当前顶位置并将顶指针加一[^1]。 ```cpp bool Push(SeqStack &s, char elem) { if (s.top >= MAX_SIZE - 1) { // 如果满了返回 false return false; } s.data[++s.top] = elem; // 将元素放入顶并更新顶指针 return true; } ``` #### 出操作 执行弹出操作前应验证是否为空。若非空,则取出顶元素后减小顶指针[^2]。 ```cpp bool Pop(SeqStack &s, char &elem) { if (s.top == -1) { // 若为空则无法弹出任何东西 return false; } elem = s.data[s.top--]; // 取得顶元素并调整顶指针 return true; } ``` #### 判断是否为空 只需比较顶指针与默认初即可得出结论。 ```cpp bool IsEmpty(const SeqStack &s) { return s.top == -1 ? true : false; } ``` #### 获取顶元素 此方法同样依赖于的状态——只有存在至少一项的情况下才能成功获取其顶部项。 ```cpp bool GetTop(const SeqStack &s, char &elem) { if (IsEmpty(s)) { // 验证是否有内容可读取 return false; } elem = s.data[s.top]; return true; } ``` #### 销毁 销毁过程简单地重置顶指针至起始状态,实际内存资源由操作系统管理回收。 ```cpp void DestroyStack(SeqStack &s) { s.top = -1; // 设置顶指针回到初始状态即完成销毁动作 } ``` #### 主程序演示 下面是一个完整的测试例子,它展示了如何利用上述定义好的接口来进行一系列标准的操作流程: ```cpp #include <iostream> using namespace std; // 上述所有函数声明... int main() { SeqStack stack; InitStack(stack); cout << "是否为空:" << (IsEmpty(stack) ? "是" : "否") << endl; char ch[] = {'a', 'b', 'c'}; for(auto c : ch){ if(!Push(stack, c)){ cout << "已满,无法继续压入!" << endl; break; } } char topElem; if(GetTop(stack, topElem)) cout << "当前顶元素为:" << topElem << endl; cout << "尝试从中依次弹出元素..." << endl; while (!IsEmpty(stack)) { char poppedElem; if(Pop(stack, poppedElem)) cout << "弹出了元素: " << poppedElem << endl; } DestroyStack(stack); cout << "已被销毁." << endl; return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千北@

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值