一、队列与栈相互转换
1. 232【用栈实现队列】
- 题目: 请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty):
实现 MyQueue 类:- void push(int x) 将元素 x 推到队列的末尾
- int pop() 从队列的开头移除并返回元素
- int peek() 返回队列开头的元素
- boolean empty() 如果队列为空,返回 true ;否则,返回 false
说明: - 你只能使用标准的栈操作 —— 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。
- 你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。
- 代码:
class MyQueue {Stack<Integer> stackIn;Stack<Integer> stackOut;public MyQueue() {stackIn = new Stack<>();stackOut = new Stack<>();}public void push(int x) {stackIn.push(x);}public int pop() {if(stackOut.isEmpty()){while (!stackIn.isEmpty()){int temp = stackIn.pop();stackOut.push(temp);}}return stackOut.pop();}public int peek() {int ans = pop();stackOut.push(ans);return ans;}public boolean empty() {if(stackOut.isEmpty() && stackIn.isEmpty()){return true;}return false;}
}
2. 225【用队列实现栈】
- 题目: 请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。
实现 MyStack 类:- void push(int x) 将元素 x 压入栈顶。
- int pop() 移除并返回栈顶元素。
- int top() 返回栈顶元素。
- boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。
注意: - 你只能使用队列的基本操作 —— 也就是 push to back、peek/pop from front、size 和 is empty 这些操作。
- 你所使用的语言也许不支持队列。 你可以使用 list (列表)或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。
- 代码:
class MyStack {Queue<Integer> q1;Queue<Integer> q2;public MyStack() {q1 = new LinkedList<>();q2 = new LinkedList<>();}public void push(int x) {q1.add(x);}public int pop() {int size = q1.size();while(size>1){q2.add(q1.poll());size--;}int ans = q1.poll();while (!q2.isEmpty()){q1.add(q2.poll());}return ans;}public int top() {int ans = pop();q1.add(ans);return ans;}public boolean empty() {if(q1.isEmpty()){return true;}return false;}
}
二、栈的应用
1. 20【有效的括号】
- 题目: 给定一个只包括 ‘(’,‘)’,‘{’,‘}’,‘[’,‘]’ 的字符串 s ,判断字符串是否有效。
有效字符串需满足:- 左括号必须用相同类型的右括号闭合。
- 左括号必须以正确的顺序闭合。
- 每个右括号都有一个对应的相同类型的左括号。
- 代码:
class Solution {public boolean isValid(String s) {Stack<Character> stack = new Stack<>();for(int i=0; i<s.length();i++){char c = s.charAt(i);if(c == '('){stack.push(')');}else if(c == '{'){stack.push('}');}else if(c == '['){stack.push(']');}else if(stack.isEmpty() || stack.peek()!=c){return false;}else{stack.pop();}}return stack.isEmpty();}
}
2. 1047【删除字符串中的所有相邻重复项】
- 题目: 给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。
- 代码:
方法一:双指针法
class Solution {public String removeDuplicates(String s) {int slow = 0;StringBuilder sb = new StringBuilder();for (int i = 0; i < s.length(); i++) {char c = s.charAt(i);if(slow == 0){sb.append(c);slow++;}else if(c != sb.charAt(slow-1)){sb.append(c);slow++;}else{sb.deleteCharAt(slow-1);slow--;}}return sb.toString();}
}
方法二:栈
class Solution {public String removeDuplicates(String s) {Deque<Character> stack = new LinkedList<>();for (int i = 0; i < s.length(); i++) {char c = s.charAt(i);if(stack.isEmpty() || stack.peek()!=c){stack.push(c);}else {stack.pop();}}String str = "";while (!stack.isEmpty()) {str = stack.pop() + str;}return str;}
}
3. 150【逆波兰表达式求值】
- 题目: 给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。
请你计算该表达式。返回一个表示表达式值的整数。
注意:- 有效的算符为 ‘+’、‘-’、‘*’ 和 ‘/’ 。
- 每个操作数(运算对象)都可以是一个整数或者另一个表达式。
- 两个整数之间的除法总是 向零截断 。
- 表达式中不含除零运算。
- 输入是一个根据逆波兰表示法表示的算术表达式。
- 答案及所有中间计算结果可以用 32 位 整数表示。
- 代码:
class Solution {public int evalRPN(String[] tokens) {//如果把运算符作为中间节点,将表达式按照中序遍历的规则转换成一个二叉树,//那么逆波兰表达式就是用后序遍历的方式把二叉树序列化的结果。Deque<Integer> stack = new LinkedList<>();for (String s:tokens) {if(s.equals("+")){stack.push(stack.pop()+stack.pop());}else if(s.equals("-")){stack.push(-stack.pop()+stack.pop());}else if(s.equals("*")){stack.push(stack.pop()*stack.pop());}else if(s.equals("/")){int temp = stack.pop();stack.push(stack.pop()/temp);}else{stack.push(Integer.valueOf(s));}}return stack.pop();}
}
三、队列的应用
1. 239【滑动窗口最大值】
- 题目: 给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。返回滑动窗口中的最大值。
- 代码:
class Solution {public int[] maxSlidingWindow(int[] nums, int k) {//不能使用双指针法,因为如果当前窗口的最大值不在下一个窗口,//则下一个窗口还需重新寻找最大值//因此需要维护一个最大值队列,该队列是递减的//若滑出元素等于队头元素,则需将队头弹出//若滑入元素大于队尾元素,则需将队尾弹出//将滑入元素入队int[] ans = new int[nums.length-k+1];Deque<Integer> queue = new ArrayDeque<>();for (int i = 0; i < nums.length; i++) {while (!queue.isEmpty() && nums[i]>queue.peekLast()){queue.pollLast();}queue.add(nums[i]);if(i-k+1>=0){ans[i-k+1] = queue.peek();if(nums[i-k+1] == queue.peek()){queue.poll();}}}return ans;}
}
2. 347【前K个高频元素】
- 题目: 给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按任意顺序返回答案。
- 代码:
class Solution {public int[] topKFrequent(int[] nums, int k) {//可以使用map来存储每个元素及其对应出现的频率//寻找频率前k个元素,可以使用优先级队列PriorityQueue//PriorityQueue底层使用了堆的数据结构,满足FIFO原则//队头元素只可能是队列中优先级最高的元素//所以这里使用小根堆方式保留出现频率前k个高的元素PriorityQueue<int[]> pq = new PriorityQueue<>(new compareArr());HashMap<Integer,Integer> map = new HashMap<>();int[] ans = new int[k];for (int i = 0; i < nums.length; i++) {map.put(nums[i],map.getOrDefault(nums[i],0)+1);}for(Map.Entry<Integer,Integer> entry:map.entrySet()){int[] temp = new int[2];temp[0] = entry.getKey();temp[1] = entry.getValue();pq.offer(temp);}for (int i = pq.size()-1; i >= 0; i--) {if(i>=k){pq.poll();}else{ans[i] = pq.poll()[0];}}return ans;}
}
class compareArr implements Comparator<int[]>{@Overridepublic int compare(int[] m,int[] n) {return m[1]-n[1];}
}