【牛客JZ31】—栈的压入弹出序列判断算法详解

【牛客JZ31】—栈的压入弹出序列判断算法详解
坚持用清晰易懂的图解+代码语言,让每个知识点变得简单!
🚀呆头个人主页详情
🌱 呆头个人Gitee代码仓库
📌 呆头详细专栏系列
座右铭:“不患无位,患所以立。”

【牛客JZ31】—栈的压入弹出序列判断算法详解


摘要


目录

题目描述

牛客链接直达----------请点击

给定两个整数序列:

  • pushV:压栈序列
  • popV:待验证的弹栈序列

需要判断 popV 是否可能是 pushV 对应的弹栈序列。


核心思路

要解决这个问题,我们需要理解栈的工作机制:压栈操作:元素按照 pushV 的顺序依次入栈弹栈操作:在任意时刻,只能弹出栈顶元素时机选择:可以在压入任意元素后选择弹出栈顶元素

关键洞察:我们可以通过模拟整个压栈弹栈过程来验证序列的合法性。

完整代码实现

#include<vector>#include<stack>usingnamespace std;classSolution{public:boolIsPopOrder(vector<int>& pushV, vector<int>& popV){// 使用辅助栈模拟压栈弹栈过程 stack<int> st;// 双指针:_push指向当前要压入的元素,_pop指向当前要弹出的元素 size_t _push =0;// 压栈序列的索引 size_t _pop =0;// 弹栈序列的索引// 遍历所有需要压入的元素while(_push < pushV.size()){// 将当前元素压入栈中 st.push(pushV[_push++]);// 检查栈顶元素是否与当前期望弹出的元素匹配// 如果匹配,则连续弹出所有匹配的元素while(!st.empty()&& st.top()== popV[_pop]){ _pop++;// 移动弹栈序列指针 st.pop();// 弹出栈顶元素}}// 如果所有元素都能正确弹出,栈应该为空return st.empty();}};

算法步骤详解

让我们通过一个具体例子来理解算法的执行过程:

示例输入

  • pushV = [1, 2, 3, 4, 5]
  • popV = [4, 5, 3, 2, 1]
执行过程模拟
// 初始状态 stack<int> st;// 空栈 size_t _push =0;// 指向元素1 size_t _pop =0;// 指向元素4

第1轮循环

// 压入元素1 st.push(1);// 栈:[1] _push =1;// 指向元素2// 检查栈顶:1 != 4,不匹配,继续

第2轮循环

// 压入元素2 st.push(2);// 栈:[1, 2] _push =2;// 指向元素3// 检查栈顶:2 != 4,不匹配,继续

第3轮循环

// 压入元素3 st.push(3);// 栈:[1, 2, 3] _push =3;// 指向元素4// 检查栈顶:3 != 4,不匹配,继续

第4轮循环

// 压入元素4 st.push(4);// 栈:[1, 2, 3, 4] _push =4;// 指向元素5// 检查栈顶:4 == 4,匹配! st.pop();// 栈:[1, 2, 3] _pop =1;// 指向元素5

第5轮循环

// 压入元素5 st.push(5);// 栈:[1, 2, 3, 5] _push =5;// 超出范围// 检查栈顶:5 == 5,匹配! st.pop();// 栈:[1, 2, 3] _pop =2;// 指向元素3// 继续检查:3 == 3,匹配! st.pop();// 栈:[1, 2] _pop =3;// 指向元素2// 继续检查:2 == 2,匹配! st.pop();// 栈:[1] _pop =4;// 指向元素1// 继续检查:1 == 1,匹配! st.pop();// 栈:[] _pop =5;// 超出范围

最终结果:栈为空,返回 true


算法复杂度分析

时间复杂度

// 主循环:遍历pushV中的每个元素while(_push < pushV.size()){// O(n) st.push(pushV[_push++]);// O(1)// 内层循环:每个元素最多被弹出一次while(!st.empty()&& st.top()== popV[_pop]){// 总计O(n) _pop++; st.pop();}}
  • 外层循环:执行 n 次(n 为序列长度)
  • 内层循环:虽然是嵌套循环,但每个元素最多被压入和弹出各一次
  • 总时间复杂度:O(n)

空间复杂度

stack<int> st;// 辅助栈,最坏情况下存储所有元素
  • 辅助栈空间:最坏情况下需要存储所有 n 个元素
  • 总空间复杂度:O(n)

边界情况处理

空序列处理

boolIsPopOrder(vector<int>& pushV, vector<int>& popV){// 如果两个序列长度不同,直接返回falseif(pushV.size()!= popV.size()){returnfalse;}// 空序列的情况if(pushV.empty()){returntrue;// 两个空序列匹配}// 原算法逻辑...}

单元素序列

// 测试用例 vector<int> pushV ={1}; vector<int> popV ={1};// 结果:true vector<int> pushV2 ={1}; vector<int> popV2 ={2};// 结果:false

总结

通过这道题的分析,我们深入理解了以下几个重要概念:

  1. 栈的模拟:通过辅助栈来模拟实际的压栈弹栈过程
  2. 双指针技巧:使用两个指针分别跟踪压栈和弹栈的进度
  3. 贪心策略:每当栈顶元素与期望弹出元素匹配时,立即弹出
  4. 算法验证:通过最终栈是否为空来验证序列的合法性

这种模拟法不仅适用于栈的相关问题,在很多其他算法场景中也有广泛应用。掌握这种思维方式,对于提升算法设计能力具有重要意义。


参考链接

  1. LeetCode 946. 验证栈序列
  2. 牛客网 - 栈的压入、弹出序列
  3. 数据结构与算法 - 栈的应用
  4. C++ STL stack 容器详解
  5. 算法导论 - 栈和队列

关键词标签

栈数据结构算法模拟双指针C++STL

Read more

WebStorm对个人免费开放

WebStorm对个人免费开放

前端开发的普惠革命:JetBrains WebStorm 非商业免费政策深度解析 2024 年 10 月 24 日,正值程序员节来临之际,JetBrains 抛出重磅消息:旗下旗舰级前端开发 IDE WebStorm 正式对非商业用途用户全面免费开放。这一举措不仅延续了 RustRover 的免费许可模式,更标志着专业级 Web 开发工具向大众化普及迈出了关键一步,为全球千万前端开发者带来了实质性利好。 一、政策内核:清晰界定的免费边界与权益 1. 非商业用途的精准定义 JetBrains 在 Toolbox 订阅协议中明确划分了免费使用的适用场景,覆盖群体远超传统教育优惠范畴: * 核心免费场景:包括前端技术学习与技能提升、无商业收益的开源项目贡献、技术博客 / 视频教程等内容创作、个人兴趣导向的 Web 开发(如自制工具、创意 demo)。值得注意的是,即使内容创作通过广告产生间接收益,仍属于非商业范畴。 * 商业付费边界:任何直接或间接获取经济收益的开发活动均需付费,

By Ne0inhk

漫画分镜理解任务中GLM-4.6V-Flash-WEB的表现水平测评

GLM-4.6V-Flash-WEB在漫画分镜理解中的表现深度解析 当我们在阅读一部日漫时,那些由多个画格组成的页面,并非随意排列——每一格的构图、角色动作、气泡文字乃至留白,都在共同讲述一个连贯的故事。这种“图文协同”的表达方式,正是视觉语言模型最难攻克的领域之一。 而如今,随着轻量化多模态大模型的发展,我们终于看到了真正理解漫画分镜逻辑的可能性。其中,智谱AI推出的 GLM-4.6V-Flash-WEB 正是这一方向上的代表性尝试。它不追求参数规模的极致膨胀,而是聚焦于“可用性”:能否在消费级显卡上运行?响应是否足够快以支持实时交互?开发者能不能轻松部署? 这些问题的答案,决定了一个模型究竟是实验室里的展示品,还是能真正进入产品流水线的工具。本文将围绕GLM-4.6V-Flash-WEB在“漫画分镜理解”任务中的实际表现展开分析,从技术实现到工程落地,还原其真实能力边界。 从视觉编码到语义生成:它是如何“看懂”一幅漫画的? 传统方法处理漫画内容时,往往依赖OCR识别文本+目标检测框定人物+规则引擎判断顺序。这种方式虽然高效,但割裂了画面与文字之间的深层联系——比如角色低

By Ne0inhk

OpenClaw Skills扩展:nanobot通过webhook对接钉钉/飞书,实现跨平台消息同步

OpenClaw Skills扩展:nanobot通过webhook对接钉钉/飞书,实现跨平台消息同步 1. nanobot简介 nanobot是一款受OpenClaw启发的超轻量级个人人工智能助手,仅需约4000行代码即可提供核心代理功能。相比传统方案,代码量减少了99%,但功能依然强大。 这个轻量级助手内置了vllm部署的Qwen3-4B-Instruct-2507模型,使用chainlit进行推理交互。最吸引人的是,你可以轻松配置它作为QQ聊天机器人使用,或者通过webhook对接企业通讯工具如钉钉和飞书。 2. 基础环境验证 2.1 检查模型服务状态 在开始扩展功能前,我们需要确认基础服务运行正常。通过以下命令检查模型部署状态: cat /root/workspace/llm.log 如果看到服务启动成功的日志信息,说明模型已准备就绪。常见的成功标志包括"Model loaded successfully"或"Service started on port xxxx"等提示。 2.2 测试基础问答功能

By Ne0inhk
前端如何写出优秀的 AI Agent Skills

前端如何写出优秀的 AI Agent Skills

背景 用 Cursor 写代码的时候,明明团队有自己的组件规范,但 AI 生成出来的代码风格完全对不上号,每次都要手动改半天——这不是 AI 不够聪明,而是你没"教"过它。 从 Cursor、Claude Code 到 GitHub Copilot,AI 编码工具正在从"对话助手"进化成能「自主执行任务」的 Agent。在这个趋势下,「Agent Skills」 悄然成为标配——简单说,它就是你写给 AI 的"操作手册",教会它一项技能,它就能在合适的场景自动调用。 这篇文章,我会讲清楚 Skills 是什么、

By Ne0inhk