目录
150. 逆波兰表达式求值
题目链接:https://leetcode.cn/problems/evaluate-reverse-polish-notation/description/


解题分析
逆波兰表达式相当于二叉树的后续遍历,可直接用栈来顺序处理:
- 遇到数字,入栈
- 遇到运算符,取出栈顶两个数字进行计算,并将结果压入栈中
所有运算结束弹出栈的数字作为返回值。
本题代码
class Solution {
public int evalRPN(String[] tokens) {
Deque<Integer> stack = new LinkedList();
for(String s : tokens){
if("+".equals(s)){ //遇到运算符,注意使用equals()比较
stack.push(stack.pop() + stack.pop());
}else if("-".equals(s)){
stack.push(-stack.pop() + stack.pop());
}else if("*".equals(s)){
stack.push(stack.pop() * stack.pop());
}else if("/".equals(s)){
int temp1 = stack.pop();
int temp2 = stack.pop();
stack.push(temp2 / temp1);
}else{ //遇到数字
stack.push(Integer.valueOf(s)); //String转成Integer类型:Integer.valueOf()
}
}
return stack.pop();
}
}
239. 滑动窗口最大值
题目链接:https://leetcode.cn/problems/sliding-window-maximum/description/
文章讲解:https://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

解题分析
其实队列没有必要维护窗口里的所有元素,只需要维护有可能成为窗口里最大值的元素就可以了,同时保证队列里的元素数值是由大到小的。
比如:对于窗口里的元素{2, 3, 5, 1 ,4},单调队列里只维护{5, 4} 就够了,保持单调队列里单调递减,此时队列出口元素就是窗口里最大元素。

设计单调队列的时候,pop,和push操作要保持如下规则:
- push(value):如果push的元素value 大于 队列入口元素的值,弹出队列入口元素,直到push元素值小于等于队列入口元素值,放入value
- pop(value):如果窗口移除的元素value 等于 单调队列的出口元素,弹出,否则不用任何操作
代码思路:
- 可创建一个MyQueue类,创建队列,并包含add()、poll()、peek()方法;
- 另一个Solution类进行调用。创建滑动窗口队列和返回数组:
滑动窗口队列前k个元素直接添加,找到返回数组的第一个值,然后开始滑动,进行add()、poll()的操作,并调用peek()获取每次的最大值赋给返回数组。
本题代码
class MyQueue{
Deque<Integer> deque = new LinkedList<>();
public void add(int value){
while(!deque.isEmpty() && value > deque.getLast()){ //注意这里是while循环,getLast()是获取队列最后一个元素
deque.removeLast();
}
deque.add(value);
}
public void poll(int value){
if(!deque.isEmpty() && value == deque.peek()){
deque.poll(); //无参
}
}
public int peek(){
return deque.peek();
}
}
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
int len = nums.length - k + 1;
int[] res = new int[len]; //注意滑动窗口的长度
int num = 0; //需创建一个int变量,记录返回数组的角标
MyQueue myQueue = new MyQueue();
for(int i = 0; i < k; i++){ //先将前k个元素放入滑动窗口
myQueue.add(nums[i]);
}
res[num++] = myQueue.peek();
for(int i = k; i < nums.length; i++){ //开始滑动
myQueue.poll(nums[i-k]); //注意是i-k
myQueue.add(nums[i]);
res[num++] = myQueue.peek();
}
return res;
}
}
347.前 K 个高频元素
题目链接:https://leetcode.cn/problems/top-k-frequent-elements/description/
文章讲解:https://programmercarl.com/0347.%E5%89%8DK%E4%B8%AA%E9%AB%98%E9%A2%91%E5%85%83%E7%B4%A0.html

解题分析
这道题目主要涉及到如下三块内容:
- 统计元素出现频率:使用map来进行统计
- 对频率排序:用小顶堆,因为要统计最大前k个元素,只有小顶堆每次将最小的元素弹出,最后小顶堆里积累的才是前k个最大元素
- 找出前K个高频元素
代码思路:
1.统计元素出现频率:
创建map,记录数组每个元素(key),及出现频率(value)
2.对频率排序:
1)实现小顶堆,元素类型为长度为2数组,放元素和元素出现次数
实现方式——创建优先级队列,实现Comparator接口,数值小的在前
2)将map的键值对放入队列中:
- 小顶堆个数小于k时,直接放入
- 小顶堆个数大于k时,比较map键值对的value与小顶堆栈顶数组第二个元素,若栈顶的小,则弹出栈顶,加入大的
3.找出前K个高频元素:
创建返回数组,长度为k的一维数组;遍历小顶堆,将每个数组的首个元素(即元素本身)放入数组
因为小顶堆栈顶是最小数,所以倒叙遍历小顶堆
本题代码
class Solution {
public int[] topKFrequent(int[] nums, int k) {
//1.创建map,记录数组每个元素(key),及出现频率(value)
Map<Integer,Integer> map = new HashMap<>();
for(int num: nums){
map.put(num,map.getOrDefault(num,0) + 1);
}
//2.实现小顶堆,元素类型为长度为2数组,放元素和元素出现次数
//实现方式——创建优先级队列,实现Comparator接口,数值小的在前
PriorityQueue<int[]> pq = new PriorityQueue<>(new Comparator<int[]>(){
public int compare(int[] m, int[] n){
return m[1] - n[1];
}
});
//3.将map的键值对放入队列中
//1)小顶堆个数小于k时,直接放入
//2)小顶堆个数大于k时,比较map键值对的value与小顶堆栈顶数组第二个元素,若栈顶的小,则弹出栈顶,加入大的
for(Map.Entry<Integer,Integer> entry : map.entrySet()){
if(pq.size() < k){
pq.add(new int[]{entry.getKey(),entry.getValue()});
}else{
if(entry.getValue() > pq.peek()[1]){
pq.poll();
pq.add(new int[]{entry.getKey(),entry.getValue()});
}
}
}
//4.创建返回数组,长度为k的一维数组;遍历小顶堆,将每个数组的首个元素(即元素本身)放入数组
//因为小顶堆栈顶是最小数,所以倒叙遍历小顶堆
int[] res = new int[k];
for(int i = k-1; i >= 0; i--){
res[i] = pq.poll()[0];
}
return res;
}
}

被折叠的 条评论
为什么被折叠?



