先说一个消息,为了方便互相交流学习,青铜三人行建了个微信群,感兴趣的伙伴可以扫码加下面的小助手抱你入群哦!

青铜三人行——每周一题@验证栈序列 视频讲解

力扣题目

验证栈序列

给定 pushed 和 popped 两个序列,每个序列中的 值都不重复,只有当它们可能是在最初空栈上进行的推入 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 之前弹出。

提示:

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

栈结构

要做这道题,首先得了解一下什么是「栈」。为此书香搬来了维基百科上的解释:

堆栈(英语:stack)又称为栈或堆叠,是计算机科学中的一种抽象数据类型,只允许在有序的线性数据集合的一端(称为堆栈顶端,英语:top)进行加入数据(英语:push)和移除数据(英语:pop)的运算。因而按照后进先出(LIFO,
Last In First Out)的原理运作。 栈常与另一种有序的线性数据集合队列相提并论。 栈常用一维数组或链表来实现。

这个定义看起来多,其实也没什么大不了的。栈本身就是一个数组或者链表,只是人为定义它获取数据的方式只能从栈的顶端获取,因此遵循先进后出,后进先出的规则罢了。

想象栈就是一摞盘子,你只能在最上面放盘子或者拿走盘子。对应起来,栈的操作就有两个:

  • push操作,往栈顶放入一个数据。
  • pop操作,从栈顶取走一个数据。

解题思路

回到这道题目,一开始看起来题目有点绕,让人不知道要做什么。后来 helen 提议,既然题目要求是考虑在最初空栈上进行的推入 push 和弹出 pop 操作,那么我们不妨就建立一个空栈尝试用程序的方式来模拟一遍操作的流程,看看会不会明朗点:

var validateStackSequences = function (pushed, popped) {const stack = [];pushed.forEach((ele) => {stack.push(ele);stack.pop();});return !stack.length;
};

这样我们就建立了一个栈,并且在按题目中 pushed 数组的顺序将元素 push 进栈, 然后再按照同样的顺序 pop 出去。

不过这样子就跟数学题里面一边放水,一边加水的疯狂管理员一般,返回的结果肯定为 true。

回头再看看题目,发现其实就是在这个一边增加一边移出的过程上,添加了一个条件:只能按照 poped 的顺序来 pop 数据,看看能不能将 stack 清空 。

再拆解一下目标,就更明确了:

  • 按照 pushed 的顺序将元素 push 入栈。
  • 在 push 的过程中尝试 pop 元素。
  • pop 元素的顺序要和 poped 的顺序一样。

要满足这三个条件,一个方法就是,尝试在 push 的每一步时,尽可能按照指定顺序 pop 出所有的元素。根据这个思路,helen 给出了题解:

var validateStackSequences = function(pushed, popped) {const stack = [];let popIndex = 0;for (const val of pushed) {stack.push(val);while (stack.length !== 0 && stack[stack.length - 1] === popped[popIndex]) {stack.pop();popIndex++;}}return stack.length === 0;
};

书香的思路一模一样,只是把代码写的更短了点 :

var validateStackSequences = function (pushed, popped) {const stack = [];pushed.forEach((ele) => {stack.push(ele);while (stack.length && stack[stack.length - 1] === popped[0]) {stack.pop();popped.shift();}});return !stack.length;
};

Extra go

对于书香和 helen 这样的初级选手,通过实现一个栈结构来模拟题目中要求的操作,解出题目,就已经开心地到一边去玩耍了 ~

但对于追求完美的曾大师来说,push 和 pop 这两个操作,都非常消耗计算资源。而这种把数据一边 push 一边 pop 的疯狂操作显然是不能容忍的。

为此,他写出了2米长的 go 语言代码:

func validateStackSequences(pushed []int, popped []int) bool {if len(popped) == 0 {return true}pushedValues := make(map[int]int) //存储所有的已经入栈的值和数组索引left := 0right := 0for i:=0;i< len(pushed);i++ {if pushed[i] == popped[0] {pushed[i] = -1  // 出栈left = i-1right = i+1break}else{pushedValues[pushed[i]] = i}}for j:=1;j<len(popped);j++ {if _, ok := pushedValues[popped[j]]; ok { // 值已经加入stack了for left >= 0 {if pushed[left] == -1 {left--}else{break}}if left < 0 {left = 0}if popped[j] != pushed[left] {return false}else{ // 值相等,出栈pushed[left] = -1left--}}else{ // 值没有加入stack,继续往前找for right < len(popped) {if popped[j] == pushed[right] { // 找到了pushed[right] = -1 //出栈left = right - 1 // 重新赋值leftright ++  // 重新赋值rightbreak}else{ // 没有找到,继续往前pushedValues[pushed[right]] = rightright++}}}}return true

}
嗯…8 ms 的运行时间…

贪心算法

不知道你有没有发现,这道题目,在开始的时候看起来比较绕,但是真正实现起来并没有那么困难?

其实关键点在于「分而治之」,将任务中的每一步拆分开来,并且在每一步时,都尽可能去寻找最优解,再将每一步的最优解达到合起来,看是否能达成目标。

这种思路的算法就称为「贪心算法」,它在遇到寻找最优解问题的情况下,能够提供很大的帮助。

下次见~


三人行

  • 知乎专栏
  • 视频专辑

青铜三人行之验证栈序列相关推荐

  1. 946. 验证栈序列

    2020-05-15 1.题目描述 验证栈序列 2.题解 这个题目我本科的一位老师在给我们上算法课的时候讲过,他说关键是要明白我们什么时候需要入栈,什么 时候需要出栈,题目是要返回pushed数组能不 ...

  2. 栈——验证栈序列(洛谷 P4387)

    题目选自洛谷P4387 是一道栈的题,能够帮助理解栈的更深层次. 题目大意就是判断序列是否可能是对应序列的出栈序列. 如何判断是不是合理的出栈序列呢? 对于序列a 我们依次和序列b来比较,如果不相同, ...

  3. Leetcode 946.验证栈序列

    Time: 20190906 Type: Medium 题目描述 给定 pushed 和 popped 两个序列,只有当它们可能是在最初空栈上进行的推入 push 和弹出 pop 操作序列的结果时,返 ...

  4. P4387 【深基15.习9】验证栈序列

    #include<iostream> #include<stack>//不要忘记头文件 using namespace std; stack<int>k; int ...

  5. LeetCode 946. 验证栈序列(栈)

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

  6. 946. Validate Stack Sequences验证栈序列

    网址:https://leetcode.com/problems/validate-stack-sequences/ 参考:https://leetcode.com/problems/validate ...

  7. LeetCode946-验证栈序列

    问题:验证栈序列 给定 pushed 和 popped 两个序列,只有当它们可能是在最初空栈上进行的推入 push 和弹出 pop 操作序列的结果时,返回 true:否则,返回 false . 示例 ...

  8. 青铜三人行之在二叉树中增加一行

    先说一个消息,为了方便互相交流学习,青铜三人行建了个微信群,感兴趣的伙伴可以扫码加下面的小助手抱你入群哦! 每周一题,代码无敌~这周「青铜三人行」带了一个二叉树的问题: 在二叉树中增加一行 青铜三人行 ...

  9. 给定入栈序列,判断一个串是否为出栈序列

    剑指offer22:给定入栈序列,判断一个串是否为出栈序列 public static boolean isOutStackSequence(int[] Spush, int[] Spop) {if ...

最新文章

  1. 姚期智担纲,清华今日成立量子信息本科班!“着眼学术尖端,致力国家战略需求“...
  2. Java各类型变量之间的转换
  3. python绘制雷达图-使用Python绘制雷达图
  4. oracle 11g 大量废连接占满数据库连接问题处理
  5. [转]chroot的使用
  6. 3.QT事件处理,消息过滤器
  7. 发表和编辑Post的一个Bug
  8. oracle存储过程季度方法,Oracle存储过程、触发器实现获取时间段内周、月、季度的具体时间...
  9. php怎么求阶乘_如何实现一个PHP类来计算整数的阶乘?(代码详解)
  10. “有钱人大多不快乐”这种观点,只是普通人的心理安慰吗?
  11. Java集合之map 集合使用
  12. VS2019 产品密钥
  13. ufs qfil注意事项
  14. windows10商店应用离线安装方法
  15. Python连载(0011): 十分钟理解元组
  16. FFmpeg入门详解之114:DirectShow读取摄像头数据
  17. linux 搭建mycat
  18. 长见识了!一看就会的浏览器帧原理
  19. 【论文复刻】企业数字化转型与资本市场表现——来自股票流动性的经验证据(2007-2021年数据)
  20. 如何检查Mac配备的显卡(GPU)?

热门文章

  1. python中label有什么用_对Python中TKinter模块中的Label组件实例详解
  2. 刚刚发现在博客园的博客排行榜[前200人]中我的blog竟然排在第47位
  3. 可以重新缴费参加计算机考试吗,计算机二级考试报考成功后可以退费吗
  4. 小米员工面试阿里感慨:base太低时,HR都不要流水了,网友:我3000都要背调
  5. ASP.NET Web窗体(.NETFromWork应用程序) ADO.NET 实体数据模型 关于多表联查显示的实现
  6. 阿里云入主千方科技,顺道搞定宇视科技
  7. Excel只复制有公式的单元格进行批量的求和操作
  8. Ubuntu 20.10安装Flashplay插件
  9. python else用法_Python try else语句的用法
  10. 关于路由跟踪指令traceroute介绍