用栈实现队列
题目:232
-
队列:先进先出 栈:先进后出。所以如果只用一个栈来模拟队列,是不太行的,一个不行那就来两个
-
一个用来进,一个用来出
-
队列要实现的作用无非是:
-
push(将元素x推至队列尾部):直接用栈的push就行
-
pop(从队列的开头移除并返回元素):因为栈是先进后出,要想实现队列的先进先出,得用另一个栈起到转运元素的作用。就先把In栈里的元素放到Out栈里的元素,这样Out栈的第一个元素就是曾经先进去的元素了。然后就用Out栈的pop
-
peek(返回队列开头元素):和pop一样的思路
-
empty(检查队列是否为空):两个栈空了就是空了
-
细节上来说:构造器里就是两个栈,然后由于push和pop都要用到两个栈用来转移元素,为了代码的复用性,直接弄一个方法用来转移元素,要转移就是转移全部的。看Out栈是非空的,原路返回,看In栈是非空的,都放到Out栈里
-
以及很尴尬......我忘了怎么定义栈了
-
Stack<Integer> stackIn; Stack<Integer> stackOut;public MyQueue() {stackIn = new Stack<>(); stackOut = new Stack<>();}
用队列实现栈
题目:225
-
或许是一种把思路逆转过来
-
......好像并没有,队列好像有点不熟。不过也是可以用两个队列,一个是和栈的进出顺序一样的q1,一个是用来辅助的q2。因为栈是先进后出,后push的是先出来的,但是队列后push的是在后面,也是后出,为了避免这个情况,可以先把要push的元素x 放在辅助队列p2,这样她就是第一个元素可以先出来了,然后再其后面挨个放p1的元素。这样p2就和栈的顺序一样了,但是为了保证p1 p2分工明确,这里要把p1 p2交换一下
-
震惊,queue的定义竟然是
-
Queue<Integer> queue1; // 和栈中保持一样元素的队列 Queue<Integer> queue2; // 辅助队列 /** Initialize your data structure here. */ public MyStack() { queue1 = new LinkedList<>(); queue2 = new LinkedList<>(); } -
deque的定义更是没怎么用过
-
Deque 接口继承了 Queue 接口
-
所以 Queue 中的 add、poll、peek等效于 Deque 中的 addLast、pollFirst、peekFirst
-
Deque<Integer> que1; // 和栈中保持一样元素的队列 Deque<Integer> que2; // 辅助队列 /** Initialize your data structure here. */ public MyStack() { que1 = new ArrayDeque<>(); que2 = new ArrayDeque<>(); } -
当然,还可以优化,只用一个队列,靠一些首尾循环。 每 offer 一个数(A)进来,都重新排列,把这个数(A)放到队列的队首 `
public void push(int x) { queue.offer(x); int size = queue.size(); //移动除了 A 的其它数 while (size-- > 1) queue.offer(queue.poll()); }
有效的括号
题目:20
- 经典题目,找括号配对,看是否配对成功
- 字符串里有个左括号,就往栈里放一个配对的右括号。然后等轮到字符串里不是左括号时,与栈的顶部做对比(此时栈的顶部是最近的右括号)直接用pop ,对不上就返回false
- 最后如果顺利的话,栈里是没有元素的,说明配对成功
- 主要是栈的操作,代码能力还是堪忧x
删除字符串中所有相邻重复项
题目:1047
- 简单来说,就是继续用栈的特性,对比字符串里的字符ch 与 目前在栈的顶端元素,如果两者一样,把顶端元素pop出去。一些连连看x 最后剩下来的就是符合要求的了
- 不过因为在栈里,出来后的顺序会反,不过可以自行调整拼接顺序。
while (!deque.isEmpty()) {
str = deque.pop() + str; //注意看,拼接时是把栈顶的元素放在了前面,相当于一种反转顺序
}
- 感觉有必要看一下双端队列Deque的使用
- 普通队列(一端进另一端出): Queue queue = new LinkedList()或Deque deque = new LinkedList()
- 双端队列(两端都可进出) Deque deque = new LinkedList()
- 堆栈 Deque deque = new LinkedList()
- 而在堆栈这里,都什么年代了,还在用传统Stack 好像现在JAVA更倾向于用Deque作为堆栈......,不过方法一样,都是push pop peek
- 顺便,上面三个看起来好像都是一个东西......这个双端队列Deque有点兼容,想让它是什么,就用对应的方法就行。具体在csdn上也收藏了一个文章
- 这题甚至能用双指针,等着去试试
逆波兰表达式求值
题目:150
- 题目的提示就可以立大功了
- 逆波兰表达式主要有以下两个优点:
- 去掉括号后表达式无歧义,上式即便写成 1 2 + 3 4 + * 也可以依据次序计算出正确结果。
- 适合用栈操作运算:遇到数字则入栈;遇到算符则取出栈顶两个数字进行计算,并将结果压入栈中
- 按照提示2,进行分类操作,检测到不同运算符就进行不同操作,把两个数字取出运算然后再压入栈内。是数字就直接压入栈内
滑动窗口最大值
题目:239
- 其中心思路好像是:利用一个单调队列,让它的队列头结点始终是当前窗口的最大值
- 在这里就维护好看见的最大值就行,如果后来进入的值比目前的队尾数值大,那就把后进入的最大值的前面的值poll出去,一直到队列为空(该值最大) 或者 前面有大于该值的数(此时进入的值算是以后窗口最大值的预备役)
- 除了值的判定外,也要注意节点位置的判定,要在窗口范围内
- 然后,从第一个窗口里的值判定完后,一直取队列里的队首最大值即可
- 大概思路可能就是这样,代码记得多看看
前K个高频元素
题目:347
- 首先要解决一下,题解中出现的什么大顶堆、小顶堆,优先级队列之类的。要不代码都看不懂......
- 遍历Map
for (Map.Entry<Integer,Integer> entry:map.entrySet()) - 获取Key:entry.getKey() 获取Value:entry,getValue()
- getOrDefault() 方法获取指定 key 对应对 value,如果找不到 key ,则返回设置的默认值。
- 大顶堆:
PriorityQueue<int[]> pq = new PriorityQueue<>((pair1, pair2)->pair2[1]-pair1[1]);
- 小顶堆:从小到大排
PriorityQueue<int[]> pq = new PriorityQueue<>((pair1,pair2)->pair1[1]-pair2[1]);
- 然后把元素add到优先队列级后,优先队列会把它们按照自定义的排序方式排序。靠一些智能数据结构。
- 总之,大顶堆就取前k个。小顶堆先把次数少的几个poll掉,后面剩的都是所要的k个元素了,再挨个取
- 依然是多看代码吧