剑指offer系列——剑指 Offer 31. 栈的压入、弹出序列(中等题)

✨剑指 Offer 31. 栈的压入、弹出序列✨

🌈大家好!本篇文章将继续介绍关于栈队列堆的OJ题,题目来自力扣:剑指 Offer 31. 栈的压入、弹出序列,展示代码语言暂时为:C++代码 😇。

昨天考六级去了,打卡中断一天🕊,今天继续力扣C++打卡(12.11)!✊✊✊


🔒1、题目:

输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如,序列 {1,2,3,4,5} 是某栈的压栈序列,序列 {4,5,3,2,1} 是该压栈序列对应的一个弹出序列,但 {4,3,5,1,2} 就不可能是该压栈序列的弹出序列。
🌲 示例 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 之前弹出。

❗️ 提示 ❗️ :

	0 <= pushed.length == popped.length <= 1000
	0 <= pushed[i], popped[i] < 1000
	pushed 是 popped 的排列。

来源:力扣(LeetCode)👈

链接:https://leetcode.cn/problems/zhan-de-ya-ru-dan-chu-xu-lie-lcof/description/?orderBy=most_votes

☀️2、思路:

题目要求输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。
我们首先应了解,栈的数据操作具有 先入后出 的特性,其只有一个出口,因此某些弹出序列是无法实现的。
我们可以初始化一个栈来进行进出栈的模拟,逐个按照压入顺序进行压入🔨🔨,在这过程中,如果 栈顶的元素和弹出顺序的首个元素相等 的话,则将该栈顶元素进行 弹出 。如果第二个序列为弹出序列的话,最终模拟栈会被 弹空 。故可以将最终栈是否为空作为第二个序列是否为该栈的弹出顺序的判断条件。

实现流程:
1️⃣ 初始化一个栈stack容器 s,弹出序列的索引 i;
2️⃣ 按照压入顺序逐个压入元素;
3️⃣ 每压入一个元素,都进行栈顶的元素和弹出顺序的首个元素相等的判断,若相当,则将满足条件的栈顶都弹出,同时更新序列 i;
4️⃣ 若 s 最终为空,则此弹出序列有效✔️。

复杂度分析:
⏳时间复杂度 O(N):其中 N为第一个序列的长度;其中每个元素最多入栈与出栈一次,即最多有2N 次栈操作;
🏠空间复杂度 O(N) :栈s最多存储N个元素。

🔑3、代码:
class Solution {
public:
    bool validateStackSequences(vector<int>& pushed, vector<int>& popped) {
        stack<int> s;
        int i = 0;
        for(int num : pushed) {
            s.push(num); 
            while( !s.empty() && s.top() == popped[i]) { // 循环判断与出栈
                s.pop();
                i++;
            }
        }
        return s.empty();
    }
};
📚4、补充思路:

再来补充一个思路,可以不创建新的栈。在pushed中,设置一个栈顶计数器top,每次入栈的时候将元素从pushed[i] 复制到pushed[top]。而出栈的时候top–即可。由于每次入栈的时候会有 i++和top++,出栈的时候会有top–,所以i一定大于等于top,所以这样的复制并不会有任何的问题。 可以将空间复杂的优化为O(1)。C++代码如下:

class Solution {
public:
    bool validateStackSequences(vector<int>& pushed, vector<int>& popped) {
        int i = 0;
        int k = 0;
        int j = 0;
        while(j < popped.size()){
            if(k > 0 && pushed[k - 1] == popped[j]) {
                k--;
                j++;
            }
            else if(i < pushed.size()){
                pushed[k++] = pushed[i++];
            }
            else{
                break;
            }
        }
        if(k == 0 && j == popped.size())
            return true;
        return false;
    }
};

作者:Ryan Yee
该方法时看讨论区看到的,他提出的是C#版本的,本文将其用C++实现。

🐾5、总结

🌈 今天题目虽然是中等题,但其实有了之前做题经验后,上手会快许多,看评论区后,发现很多网友是因为BUG无法提交成功,博主提交时并没有遇到相关问题,应该是官方已经进行维护。
🚀🚀觉得文章写得不错的老铁们,点赞评论关注走一波!谢谢啦🙏 🙏🙌 !

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

君莫笑lucky

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

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

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

打赏作者

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

抵扣说明:

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

余额充值