[豪の算法奇妙冒险] 代码随想录算法训练营第十一天 | 150-逆波兰表达式求值、239-滑动窗口最大值、347-前k个高频元素
代码随想录算法训练营第十一天 | 150-逆波兰表达式求值、239-滑动窗口最大值、347-前k个高频元素
LeetCode150 逆波兰表达式求值
题目链接:https://leetcode.cn/problems/evaluate-reverse-polish-notation/description/
文章讲解:https://programmercarl.com/0150.逆波兰表达式求值.html
视频讲解:https://www.bilibili.com/video/BV1kd4y1o7on/?vd_source=b989f2b109eb3b17e8178154a7de7a51
逆波兰表达式是后缀表达式,数字先,运算符号后
所以可以用栈来存数字,遇到运算符再pop两个出来进行相应的运算,再将运算结果放回栈中,这样遍历完表达式,最后栈内留存的结果即为最终的运算结果

class Solution {
public int evalRPN(String[] tokens) {
Stack<Integer> stack = new Stack<>();
for(String cur : tokens){
if("+".equals(cur)){
stack.push(stack.pop() + stack.pop());
}else if("-".equals(cur)){
stack.push(-stack.pop() + stack.pop());
}else if("*".equals(cur)){
stack.push(stack.pop() * stack.pop());
}else if("/".equals(cur)){
int num2 = stack.pop();
int num1 = stack.pop();
stack.push(num1 / num2);
}else{
stack.push(Integer.parseInt(cur));
}
}
return stack.pop();
}
}
LeetCode239 滑动窗口最大值
题目链接:https://leetcode.cn/problems/sliding-window-maximum/
文章讲解:https://programmercarl.com/0239.滑动窗口最大值.html
视频讲解:https://www.bilibili.com/video/BV1XS4y1p7qj/?vd_source=b989f2b109eb3b17e8178154a7de7a51
这题有难度,看了Carl哥的讲解才恍然大悟
解这题的思路是使用单调队列,这里采用双端队列Deque实现单调递减队列
为了确保队首元素是最大的,且整个队列单调递减,需要对 poll(int val) 和 offer(int val) 进行重新设计,索性自己再定义一个类
poll(int val)应遵守:如果窗口移除的元素value等于单调队列的队首元素,那么队列弹出元素,否则不做任何操作
offer(int val)应遵守:如果push的元素value大于队尾元素的数值,那么就将队列队尾的元素弹出,直到push元素的数值小于等于队列入口元素的数值为止,以保证队列的整体单调递减
同时,涉及到栈操作,要确保不能弹出空栈
自定义类设计完成后,回到解题主程序,先将nums数组前k个元素offer进myDeque中,设置cnt=0,记录此时myDeque的队首元素数值到result[cnt++]中
接着就是从nums数组第k个元素(下标从0开始)往后遍历,poll第i-k个元素,offer第i个元素,记录每次的队首元素数值到result[cnt++]中,遍历完成后最终答案即为result数组

class Solution {
class MyDeque{
Deque<Integer> que = new LinkedList<>();
void poll(int val){
if(!que.isEmpty() && val == que.peekFirst()){
que.pollFirst();
}
}
void offer(int val){
while(!que.isEmpty() && val > que.peekLast()){
que.pollLast();
}
que.offerLast(val);
}
int peek(){
return que.peekFirst();
}
}
public int[] maxSlidingWindow(int[] nums, int k) {
int[] result = new int[nums.length - k + 1];
int cnt = 0;
MyDeque myDeque = new MyDeque();
for(int i = 0;i < k;i++){
myDeque.offer(nums[i]);
}
result[cnt++] = myDeque.peek();
for(int i = k;i < nums.length;i++){
myDeque.poll(nums[i-k]);
myDeque.offer(nums[i]);
result[cnt++] = myDeque.peek();
}
return result;
}
}
LeetCode347 前k个高频元素
题目链接:https://leetcode.cn/problems/top-k-frequent-elements/description/
先用HashMap记录下nums数组中出现的元素及其次数,然后再采用优先队列按照元素出现次数(value)升序排序,维护一个大小为k的小顶堆
遍历HashMap中键值对,若队列size小于k,则加入队列;若队列size等于k,则将当前队列中次数最少的元素(队首)与当前遍历元素的次数进行比较,将更大的那个留在队列中
遍历完成后,优先队列中存储的k个键值对即为目标,再遍历一遍用result数组接key,即为题目要求答案
这题要注意定义优先队列时,Comparator规则不要写反了,return pair1[1] - pair2[1]为升序排序,实现的是小顶堆,后续只需维护k个元素;return pair2[1] - pair1[1]为降序排序,实现的是大顶堆,需要维护n个元素


class Solution {
public int[] topKFrequent(int[] nums, int k) {
HashMap<Integer,Integer> records = new HashMap<>();
for(int cur : nums){
int value = records.getOrDefault(cur, 0) + 1;
records.put(cur, value);
}
PriorityQueue<int[]> priorityQueue = new PriorityQueue<>(new Comparator<int[]>(){
@Override
public int compare(int[] pair1, int[] pair2) {
return pair1[1] - pair2[1];
}
});
for(Map.Entry<Integer, Integer> cur : records.entrySet()){
if(priorityQueue.size() < k){
priorityQueue.add(new int[]{cur.getKey(), cur.getValue()});
}else{
if(cur.getValue() > priorityQueue.peek()[1]){
priorityQueue.poll();
priorityQueue.add(new int[]{cur.getKey(), cur.getValue()});
}
}
}
int[] result = new int[k];
for(int i = 0;i < k;i++){
result[i] = priorityQueue.poll()[0];
}
return result;
}
}

浙公网安备 33010602011771号