239. 滑动窗口最大值
- 题目链接:239. 滑动窗口最大值
- 解题思路:这道题刚拿到时除了暴力搜索排序没有别的思路,看了题解之后了解到可以使用单调队列的结构来解决,考的是队列的应用,通过维护一个单调的队列,保证队列的出口处永远是最大的元素来完成题目要求。
- 主要难点:队列的应用,自己维护一个单调队列
- 解题步骤:
- 首先自己维护一个单调队列类,应提供弹出与添加两种方法,具体逻辑为:弹出时,若弹出元素于队列出口元素相同则弹出,添加时,如果要添加的元素比当前出口的元素大,就把比他小的先弹出,保证队列出口为最大值
- 在实现阶段,新建一个单调队列,并新建一个数组用来存储结果,开始的时候先将k个元素放进队列,然后开始滑动窗口移动过程。移动过程中,每移动一位,需要把滑动窗口最前端元素弹出,再把最后的元素加入,这两步操作都调用自己维护的单调队列中的方法。同时,每次从滑动窗口里取入口处的最大值作为结果放入结果数组。
- 返回结果数组即可
- 解题时间:49+5
- 代码:
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
if(nums.length==1){
return nums;
}
int len = nums.length-k+1;
int[] res = new int[len];
int num = 0;
MyQueue myQueue = new MyQueue();
for(int i=0;i<k;i++){
myQueue.add(nums[i]);
}
res[num++]=myQueue.peek();
for(int i=k;i<nums.length;i++){
myQueue.poll(nums[i - k]);
myQueue.add(nums[i]);
res[num++] = myQueue.peek();
}
return res;
}
}
class MyQueue{
Deque<Integer> deque = new LinkedList<>();
void poll(int val){
if(!deque.isEmpty() && val==deque.peek()){
deque.poll();
}
}
void add(int val){
while(!deque.isEmpty() && val>deque.getLast()){
deque.removeLast();
}
deque.add(val);
}
int peek(){
return deque.peek();
}
}
347.前 K 个高频元素
- 题目链接:347.前 K 个高频元素
- 解题思路:这道题一共要干三件事,统计每个数字的出现频率,把这些出现频率排序,返回出现频率最高的前k个数字,可以使用大/小顶堆来实现,在代码中可以借用优先级队列的结构来实现堆结构
- 主要难点:堆结构的使用和理解,以及在代码中可以使用优先级队列来模拟堆结构
- 解题时间:40+5
- 代码:
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<int[]> pq = new PriorityQueue<>((pair1,pair2)->pair1[1]-pair2[1]);
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()});
}
}
}
int[] ans = new int[k];
for(int i=k-1;i>=0;i--){
ans[i] = pq.poll()[0];
}
return ans;
}
}
总结
- 今天的两道题比较难,涉及到的思路之前没见过,分别是自定义单调队列和大小顶堆的应用,一刷的时候主要理解了题解思路,后面再刷的时候尽量能自己写出来代码