栈与队列总结

基础知识

  • Java中的栈一般用 Deque 实现,因为stack有设计上的缺陷,官方建议使用 Deque
  • Deque的全称为:double ended queue(双端队列):
  • Deque 有三种用途
    • 普通队列
    • 双端队列
    • 堆栈
  • 一般实现Deque使用 ArrayDeque 或者 LinkedList ,根据增删多还是查询多来决定使用那个实现,
    如果是增删多,使用 LinkedList 更加高效,如果是查询多,使用ArrayDeque 更高效
  • 双端队列两端访问元素的方法,提供插入,删除和检查元素方法
    每种方法都存在两种实现方式:一种在失败时抛出异常,一种在失败时返回 null 或 false
    插入操作的后一种形式是专为使用有容量限制的 Deque 实现设计的;在大多数实现中,插入操作不能失败。
  • 递归的实现也是栈:每一次递归调用都会把函数的局部变量、参数值和返回地址等压入栈中
    然后在递归返回的时候,从栈顶弹出上一次递归的各项参数

具体方法 API

作为双端队列

栈与队列总结_第1张图片
作为普通队列
将元素添加到 Deque 的末尾,删除元素将 Deque 开头的元素删除
栈与队列总结_第2张图片

作为堆栈
元素添加时被推入 Deque 的队首,删除元素时 元素从 Deque 队首弹出
栈与队列总结_第3张图片
简单来说就是,add,get,remove开头的方法失败抛出异常
offer,peek,poll 开头的方法失败返回 null 或 false

例题

LeetCode:

232. 用栈实现队列

用两个栈,一个栈 in 实现 push 操作,一个栈 out 实现 pop 和 peek 操作,每次将一个out栈中为空时,将 in 栈中的元素倒腾到 out 栈即可

225. 用队列实现栈

法1:
两个队列:
一个队列 que1 存储所有入队元素,另一个队列 que2 做临时存储
pop函数中:
每次将 que1 中除开最后加入的元素之外的所有元素从传入 que2
弹出 que1 最后加入的这个元素,即达到后进先出栈的效果
push函数、top函数和empty函数直接对 que1 操作即可

法2:
用一个队列:
每次将除开第一个元素之外的元素全部按原来的顺序加入此队列的开头即可,即保证了最后加入的这个元素第一个被弹出

20. 有效的括号

技巧:匹配左括号的时候,右括号先入栈,下一次遇到右括号时 就只需要比较当前元素和栈顶元素是否相等就可以了,实现逻辑更加简单

1047. 删除字符串中的所有相邻重复项

使用StringBuffer模拟栈,更加快速
单独使用一个top指向栈顶即可

347. 前 K 个高频元素

维护小根堆,然后求出 k 个元素,优先队列配合HashMap 实现对应元素的计数 和 排序

239. 滑动窗口最大值

关键是利用单调队列实现,查询最值的时间从O(n) 降低到 O(1)

一般使用 双端队列 来实现单调队列

单调队列主要思想:队列没有必要维护窗口里的所有元素,只需要维护有可能成为窗口里最大值或者最小值的元素就可以了,同时保证队列里的元素数值是由大到小或者由小到大的

push操作:将要push元素 与 队尾元素比较,为了维持递减,只有当 push元素 < 队尾元素 时,才将其加入队尾,否则,弹出队尾元素
pop操作:将要出队元素与队首元素比较,如果相等,则说明队首元素就是要出队元素,否则,要出队的不是队首元素,也就不需要弹出队首元素了
每次取最值就只需要取队首元素即可。

具体的单调队列的 pop 和 push 操作要根据题目具体分析来设计,并不是一成不变的

总结

  • Java中的 Deque 可以用来实现 单调队列,单调队列 和 优先队列 相似,都是用来减少查询最值所消耗的时间复杂度的
    但单调队列通常通常是用来维护一定范围内的元素单调,同时只考虑最值的获取,不维护其他与最值无关的元素
    而优先队列是通过二叉树来实现的,也可以快速的实现最值的获取,但需要每次插入删除都需要维护内所有元素的顺序

参考

devnn:https://blog.csdn.net/devnn/article/details/82716447
Carl:https://mp.weixin.qq.com/s/xBcHyvHlWq4P13fzxEtkPg

你可能感兴趣的:(数据结构,堆栈,队列,java,栈)