一、理论基础
- 队列:先进先出
- 栈:先进后出
二、用栈实现队列
-
题目
- 用栈实现队列
-
思路
- 在push数据的时候,只要数据放进输入栈就好。
- pop的时候,操作就复杂一些,输出栈如果为空,就把进栈数据全部导入进来(注意是全部导入),再从出栈弹出数据,如果输出栈不为空,则直接从出栈弹出数据就可以了。
-
代码
class MyQueue { private int size; private Deque<Integer> in; private Deque<Integer> out; public MyQueue() { this.size = 0; this.in = new LinkedList<>(); this.out = new LinkedList<>(); } public void push(int x) { size++; in.push(x); } public int pop() { size--; if (out.isEmpty()) { while (!in.isEmpty()) { out.push(in.pop()); } } return out.pop(); } public int peek() { int pop = this.pop(); out.push(pop); size++; return pop; } public boolean empty() { return size == 0; } }
三、用队列实现栈
-
题目
- 用队列实现栈
-
思路
-
一个队列在模拟栈弹出元素的时候只要将队列头部的元素(除了最后一个元素外) 重新添加到队列尾部,此时再去弹出元素就是栈的顺序了。
-
-
代码
class MyStack { // 先进后出 private Deque<Integer> deque; public MyStack() { this.deque = new LinkedList<>(); } public void push(int x) { deque.offer(x); } public int pop() { for (int i = deque.size(); i > 1; i--) { deque.offer(deque.poll()); } return deque.poll(); } public int top() { int pop = this.pop(); deque.offer(pop); return pop; } public boolean empty() { return deque.isEmpty(); } }
四、简化路径
-
题目
-
path = "/a/./b/../../c/", 结果:"/c"
-
-
思路
-
代码
class Solution { public String simplifyPath(String path) { Deque<String> deque = new LinkedList<>(); // ..弹出 String[] str = path.split("/"); for (String s : str) { if (!deque.isEmpty() && "..".equals(s)) { deque.pop(); } else if (!".".equals(s) && !"..".equals(s) && !"".equals(s)) { deque.push(s); } } StringBuilder sb = new StringBuilder(); while (!deque.isEmpty()) { sb.insert(0, "/" + deque.pop()); } return sb.length() == 0 ? "/" : sb.toString(); } }
五、有效括号
-
题目
- 给定一个只包括
'('
,')'
,'{'
,'}'
,'['
,']'
的字符串s
,判断字符串是否有效。
- 给定一个只包括
-
思路
- 遍历的过程中,匹配不上,返回false
- 遍历的过程中,栈空了,返回false
- 遍历完,栈不为空,发明会false
-
代码
class Solution { public boolean isValid(String s) { Deque<Character> deque = new LinkedList<>(); for (char ch : s.toCharArray()) { if (ch == '(' || ch == '{' || ch == '[') { deque.push(ch); } if (deque.isEmpty() || ch == ')' && deque.pop() != '(' || ch == '}' && deque.pop() != '{' || ch == ']' && deque.pop() != '[') { return false; } } return deque.isEmpty(); } }
六、删除字符串中的所有相邻重复项
-
题目
-
给出由小写字母组成的字符串
S
,重复项删除操作会选择两个相邻且相同的字母,并删除它们。在 S 上反复执行重复项删除操作,直到无法继续删除。
-
-
思路
- 遇到重复,则弹出
-
代码
class Solution { public String removeDuplicates(String s) { Deque<Character> deque = new LinkedList<>(); for (char ch : s.toCharArray()) { if (!deque.isEmpty() && ch == deque.peek()) { deque.pop(); continue; } deque.push(ch); } StringBuilder sb = new StringBuilder(); while (!deque.isEmpty()) { sb.append(deque.pop()); } return sb.reverse().toString(); } }
七、逆波兰表达式
-
题目
-
给你一个字符串数组
tokens
,表示一个根据 逆波兰表示法 表示的算术表达式。请你计算该表达式。返回一个表示表达式值的整数。
-
-
思路
-
代码
class Solution { public int evalRPN(String[] tokens) { Deque<Integer> deque = new LinkedList<>(); String s = "+-*/"; for (String str : tokens) { if (s.contains(str)) { int pop = deque.pop(); int push = deque.pop(); if ("+".equals(str)) { push += pop; } if ("-".equals(str)) { push -= pop; } if ("*".equals(str)) { push *= pop; } if ("/".equals(str)) { push /= pop; } deque.push(push); continue; } deque.push(Integer.valueOf(str)); } return deque.pop(); } }
八、滑动窗口最大值
-
题目
-
给你一个整数数组
nums
,有一个大小为k
的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的k
个数字。滑动窗口每次只向右移动一位。返回 滑动窗口中的最大值 。
-
-
思路
- 维护递减队列
-
代码
class Solution { public int[] maxSlidingWindow(int[] nums, int k) { // 维持递增队列(队尾->队首) List<Integer> list = new ArrayList<>(); Deque<Integer> deque = new LinkedList<>(); int slow = 0; for (int fast = 0; fast < nums.length; fast++) { // poll if (fast - slow + 1 > k && deque.peek() == nums[slow++]) { deque.poll(); } // add while (!deque.isEmpty() && deque.peekLast() < nums[fast]) { deque.pollLast(); } deque.offer(nums[fast]); if (fast - slow + 1 == k) { list.add(deque.peek()); } } return list.stream().mapToInt(i -> i).toArray(); } }
九、前k个高频元素
-
题目
- 给你一个整数数组
nums
和一个整数k
,请你返回其中出现频率前k
高的元素。你可以按 任意顺序 返回答案。
- 给你一个整数数组
-
思路
- 根据频率排序
-
代码
class Solution { public int[] topKFrequent(int[] nums, int k) { Map<Integer, Integer> map = new HashMap<>(); for (int num : nums) { map.put(num, map.getOrDefault(num, 0) + 1); } PriorityQueue<Map.Entry<Integer, Integer>> pq = new PriorityQueue<>(new Comparator<>() { @Override public int compare(Map.Entry<Integer, Integer> o1, Map.Entry<Integer, Integer> o2) { return o2.getValue() - o1.getValue(); } }); for (Map.Entry<Integer, Integer> entry : map.entrySet()) { pq.offer(entry); } List<Integer> list = new ArrayList<>(); while (k-- > 0) { list.add(pq.poll().getKey()); } return list.stream().mapToInt(i -> i).toArray(); } }