1.LeetCode150. 逆波兰表达式求值
题目链接:https://leetcode.cn/problems/evaluate-reverse-polish-notation/description/
文章链接:https://programmercarl.com/0150.%E9%80%86%E6%B3%A2%E5%85%B0%E8%A1%A8%E8%BE%BE%E5%BC%8F%E6%B1%82%E5%80%BC.html
视频链接:https://www.bilibili.com/video/BV1kd4y1o7on
思路:
什么是逆波兰表达式?即,后缀表达式。如:[“4”, “13”, “5”, “/”, “+”] 等价于中缀表达式4 + 13 / 5
运算符会与其左边两个数字进行运算,并将结果参与下一个运算符的运算。
可以使用栈的方式解决该题:
遍历字符串数组,当获取到数字时加入栈中;当获取到运算符时,将栈顶及之后的两个数字pop()出进行运算符的计算,并将计算结果添加到栈中继续参与判断计算。直到最后,栈中只剩下一个数字,该值就是表达式的最终值。
解法:
class Solution {
public int evalRPN(String[] tokens) {
Deque<Integer> stack = new ArrayDeque<>();
int num1;
int num2;
for(String token:tokens){
if (token.equals("+")){
num1 = stack.pop();
num2 = stack.pop();
stack.push(num1+num2);
} else if (token.equals("-")){
num1 = stack.pop();
num2 = stack.pop();
stack.push(num2-num1);
} else if (token.equals("*")){
num1 = stack.pop();
num2 = stack.pop();
stack.push(num1*num2);
} else if (token.equals("/")){
num1 = stack.pop();
num2 = stack.pop();
stack.push(num2/num1);
} else{
stack.push(Integer.valueOf(token));
}
}
return stack.pop();
}
}
---------------------------------------以下是队列的相关题目---------------------------------------------------------
2.LeetCode 239. 滑动窗口最大值
题目链接:https://leetcode.cn/problems/sliding-window-maximum/description/
文章链接:https://www.programmercarl.com/0239.%E6%BB%91%E5%8A%A8%E7%AA%97%E5%8F%A3%E6%9C%80%E5%A4%A7%E5%80%BC.html#%E7%AE%97%E6%B3%95%E5%85%AC%E5%BC%80%E8%AF%BE
视频链接:https://www.bilibili.com/video/BV1XS4y1p7qj
思路:
由于是滑窗,左边出,右边进,因此可以使用队列。
难点1:如何求得滑窗内的最大值?
可以使用单调队列获取最大值,该队列中的数值单调递增或单调递减,最左边数值是最小值或最大值。只要poll()或peek()就可以获取。
难点2:如何设计单调队列?(单调递减队列)
①当滑窗中添加一个数值时,要和单调队列中结尾的数值进行比较,若大于结尾数值,则删除结尾数值,并继续与新的结尾数值比较,直到单调队列中只存在比当前待添加的数值大的数值或者单调队列为空,此时将数值添加到队列中;若小于结尾数值,则直接添加到队列中,因为它符合单调原则。这样,单调队列中的最左边始终都是当前滑窗的最大值。
②当滑窗中减少一个数值时,要和单调队列中开头的数值进行比较,若相同,则将队列的开头数值一并删除,说明新的滑窗不存在上一个滑窗的最大值了;若不相同,则不删除,说明新的滑窗仍有可能存在上一个滑窗的最大值,之所以是有可能,是因为新添加的数值可能成为新的最大值。
注意:不要把滑窗当作单调队列,单调队列只是用来获取滑窗中的某几个数值。滑窗只是表面滑动操作,有进有出的动作,而单调队列才是滑窗内部用于获取最大值的核心。
class MyQueue {//滑窗
Deque<Integer> mydeque = new ArrayDeque<>();//单调队列,该队列中数值单调递减
//滑窗移除数值
public void poll(int val){//滑窗每移动一下,会移除一个左边数值,这里检查该数值是否与单调队列中的头数值相同,若相同,则移除单调队列中的头数值
if(!mydeque.isEmpty() && mydeque.peek() == val){
mydeque.poll();
}
}
//滑窗添加数值
public void offer(int val){
while(!mydeque.isEmpty() && mydeque.getLast() < val) {//将要添加的值不断地与单调队列的结尾数值进行比较,若大于结尾数值,则删除结尾数值,直到出现一个比val值大的结尾数值为止。这样保证单调队列中始终是从大到小排列。最左边的始终是滑窗中最大的数值。
mydeque.removeLast();
}
mydeque.offer(val);
}
public Integer peek(){//获取滑窗最大值
return mydeque.peek();
}
}
class Solution {
超时了
// public int[] maxSlidingWindow(int[] nums, int k) {
// List<Integer> list=new ArrayList<>();
// Deque<Integer> deque=new ArrayDeque<>();
// for(int num:nums){
// deque.offer(num);
// if (deque.size()==k){
// list.add(Max(deque));
// deque.poll();
// }
// }
// return list.stream()
// .mapToInt(Integer::intValue)
// .toArray();
// }
// public int Max(Deque<Integer> deque){
// int max = Integer.MIN_VALUE;
// for (int value : deque) {
// max = Math.max(max, value);
// }
// return max;
// }
public int[] maxSlidingWindow(int[] nums, int k) {
if(nums.length == 1){
return nums;
}
int len = nums.length - k + 1;//最终输出的结果数组的长度,即,有多少个最大值
int[] res = new int[len];//结果数组
MyQueue mydeque = new MyQueue();//单调队列,其最左边始终是当前滑窗的最大值
for(int i=0;i<k;i++){
mydeque.offer(nums[i]);
}//获取前k个数值的单调队列
res[0] = mydeque.peek();//获取当前滑窗的最大值
for(int i=k;i<nums.length;i++){
mydeque.offer(nums[i]);//添加的元素
mydeque.poll(nums[i-k]);//移除的元素
res[i-k+1] = mydeque.peek();//获取当前滑窗最大值
}
return res;
}
}
3.LeetCode 347.前 K 个高频元素
题目链接:https://leetcode.cn/problems/top-k-frequent-elements/description/
文章链接:https://www.programmercarl.com/0347.%E5%89%8DK%E4%B8%AA%E9%AB%98%E9%A2%91%E5%85%83%E7%B4%A0.html#%E7%AE%97%E6%B3%95%E5%85%AC%E5%BC%80%E8%AF%BE
视频链接:https://www.bilibili.com/video/BV1Xg41167Lz
思路:
使用优先级队列PriorityQueue对每个元素根据其出现的频率进行由高到低排序,然后poll()出前k个元素。
解法:
class Solution {
public int[] topKFrequent(int[] nums, int k) {
Map<Integer,Integer> maps = new HashMap<>();
for(int num:nums){//统计每个整数出现的次数
maps.put(num,maps.getOrDefault(num,0)+1);
}
//优先级队列
PriorityQueue<int[]> priorityQueue = new PriorityQueue<>((a1,a2) -> a2[1]-a1[1]);
for(Map.Entry<Integer, Integer> entry : maps.entrySet()){
priorityQueue.offer(new int[]{entry.getKey(),entry.getValue()});
}
//获取出现频率前 k 高的元素
int[] res = new int[k];
for(int i=0;i<k;i++){
res[i]=priorityQueue.poll()[0];
}
return res;
}
}