232. 用栈实现队列
https://leetcode-cn.com/problems/implement-queue-using-stacks/
两个栈
在push数据的时候,只要数据放进输入栈就好,但在pop的时候,操作就复杂一些,输出栈如果为空,就把进栈数据全部导入进来(注意是全部导入),再从出栈弹出数据,如果输出栈不为空,则直接从出栈弹出数据就可以了。
最后如何判断队列为空呢?如果进栈和出栈都为空的话,说明模拟的队列为空了。
在代码实现的时候,会发现pop() 和 peek()两个函数功能类似,代码实现上也是类似的,可以思考一下如何把代码抽象一下。
class MyQueue {Stack<Integer> stackIn = new Stack<>();Stack<Integer> stackOut = new Stack<>();public MyQueue() {}public void push(int x) {stackIn.push(x);}public int pop() {dumpstackIn();return stackOut.pop();}public int peek() {dumpstackIn();return stackOut.peek();}public boolean empty() {return stackIn.isEmpty() && stackOut.isEmpty();}private void dumpstackIn() {if (!stackOut.isEmpty()) return;while (!stackIn.isEmpty()) {stackOut.push(stackIn.pop());}}}
225. 用队列实现栈
https://leetcode-cn.com/problems/implement-stack-using-queues/
两个队列
队列模拟栈,其实一个队列就够了,那么我们先说一说两个队列来实现栈的思路。
队列是先进先出的规则,把一个队列中的数据导入另一个队列中,数据的顺序并没有变,并没有变成先进后出的顺序。
所以用栈实现队列, 和用队列实现栈的思路还是不一样的,这取决于这两个数据结构的性质。
但是依然还是要用两个队列来模拟栈,只不过没有输入和输出的关系,而是另一个队列完全用又来备份的!
如下面动画所示,用两个队列que1和que2实现队列的功能,que2其实完全就是一个备份的作用,把que1最后面的元素以外的元素都备份到que2,然后弹出最后面的元素,再把其他元素从que2导回que1。
class MyStack {Queue<Integer> queue1;Queue<Integer> queue2; // 备份队列public MyStack() {queue1 = new LinkedList<>();queue2 = new LinkedList<>();}public void push(int x) {queue1.offer(x);}public int pop() {int size = queue1.size();for (int i = 0; i < size - 1; i++) {queue2.offer(queue1.poll());}int res = queue1.poll();while (!queue2.isEmpty()) {queue1.offer(queue2.poll());}return res;}public int top() {int pop = pop();queue1.offer(pop);return pop;}public boolean empty() {return queue1.isEmpty();}}
优化:一个队列
一个队列在模拟栈弹出元素的时候只要将队列头部的元素(除了最后一个元素外) 重新添加到队列尾部,此时在去弹出元素就是栈的顺序了。
// 一个队列class MyStack2 {Queue<Integer> queue;public MyStack2() {queue = new LinkedList<>();}public void push(int x) {queue.offer(x);}public int pop() {int size = queue.size();for (int i = 0; i < size - 1; i++) {queue.offer(queue.poll());}return queue.poll();}public int top() {int pop = pop();queue.offer(pop);return pop;}public boolean empty() {return queue.isEmpty();}}
20. 有效的括号
https://leetcode-cn.com/problems/valid-parentheses/
public boolean isValid(String s) {char[] str = s.toCharArray();Stack<Character> stack = new Stack<>();for (char c : str) {if (c == '(' || c == '[' || c == '{') {// 遇到左括号就把对应的右括号入栈stack.push(c == '(' ? ')' : c == '[' ? ']' : '}');} else {if (stack.isEmpty()) {return false;}if (c != stack.pop()) {return false;}}}return stack.isEmpty();}
1047. 删除字符串中的所有相邻重复项
拿字符串作为栈
https://leetcode-cn.com/problems/remove-all-adjacent-duplicates-in-string/submissions/
public String removeDuplicates(String s) {// 拿字符串直接作为栈,省去了栈还要转为字符串的操作。StringBuilder sb = new StringBuilder();int top = -1;for (int i = 0; i < s.length(); i++) {char c = s.charAt(i);if (top >= 0 && sb.charAt(top) == c) {sb.deleteCharAt(top--);} else {sb.append(c);top++;}}return sb.toString();}
150. 逆波兰表达式求值
https://leetcode-cn.com/problems/evaluate-reverse-polish-notation/
public int evalRPN(String[] tokens) {Stack<Integer> stack = new Stack<>();for (String s : tokens) {if (s.equals("+") || s.equals("-") || s.equals("*") || s.equals("/")) {// 注意这里先弹出的是num2, 后弹出的是num1, 因为后面涉及到除法int num2 = stack.pop();int num1 = stack.pop();int ans = 0;switch (s){case "+":ans = num1 + num2;break;case "-":ans = num1 - num2;break;case "*":ans = num1 * num2;break;case "/":ans = num1 / num2;break;}stack.push(ans);} else {stack.push(Integer.valueOf(s));}}return stack.peek();}
239. 滑动窗口最大值
https://leetcode-cn.com/problems/sliding-window-maximum/
笔记 https://www.yuque.com/docs/share/3d2b3396-b0af-4caf-945b-08b9ebe9a9d9?# 《滑动窗口及其更新结构》
public int[] maxSlidingWindow(int[] nums, int k) {// 双端队列,大->小, 存下标,LinkedList<Integer> qMax = new LinkedList<>();int[] ans = new int[nums.length - k + 1];// L一方面是窗口的L, 又可以作答案数组的索引int L = 0;for (int R = 0; R < nums.length; R++) {while (!qMax.isEmpty() && nums[qMax.peekLast()] <= nums[R]) {qMax.pollLast();}qMax.addLast(R);/* 两层含义: R - k是过期下标1. 如果窗口没有形成k的长度, 是不弹出数字的2. L要缩之前,看下L是不是双端队列中的头,若是,则此刻的L是即将要过期的,弹出*/if (qMax.peekFirst() == R - k) {qMax.pollFirst();}//开始记录if (R >= k - 1) {ans[L++] = nums[qMax.peekFirst()];}}return ans;}
347. 前K个高频元素
笔记https://www.yuque.com/docs/share/2ca380dd-f64b-49ec-8f95-3d7834dfc9f4?# 《347. 前K个高频元素》
public class Node {int num;int count;public Node(int num) {this.num = num;this.count = 1;}}public int[] topKFrequent(int[] nums, int k) {int[] result = new int[k];// map统计词频HashMap<Integer, Node> map = new HashMap<>();for (int num : nums) {if (!map.containsKey(num)) {map.put(num, new Node(num));} else {map.get(num).count++;}}// 小顶堆PriorityQueue<Node> minHeap = new PriorityQueue<>((o1, o2) -> o1.count - o2.count );for (Node node : map.values()) {minHeap.add(node);if (minHeap.size() > k) {minHeap.poll();}}for (int i = 0; i < k; i++) {result[i] = minHeap.poll().num;}return result;}
