今天两个题目整体难度都更大,使用队列时,一般会考虑优先级队列和单调队列
239. 滑动窗口最大值
单调队列(前面的数字不可能比后面的数字还小),有思路,但要注意细节!!!
/**
* @param {number[]} nums
* @param {number} k
* @return {number[]}
*/
var maxSlidingWindow = function(nums, k) {
// 构造一个单调队列
class MonoQueue {
queue;
constructor () {
this.queue = [];
}
front() {
return this.queue[0];
}
// 入队 会把前面小于新元素的旧元素给全部弹出
enqueue(value) {
// 队尾元素
let back = this.queue[this.queue.length - 1];
// 新元素大于之前的元素
// 【注意】必须得写成 back !== undefined
while (back !== undefined && value > back) {
this.queue.pop();
back = this.queue[this.queue.length - 1];
}
this.queue.push(value);
}
// 出队
dequeue(value) {
let front = this.front();
if (value === front) {
this.queue.shift();
}
}
}
let monoQueue = new MonoQueue();
// 结果数组
let resArr = [];
let i = 0, j = 0;
// 让一个k窗口内的元素先进来
while (j < k) {
monoQueue.enqueue(nums[j]);
j++;
}
resArr.push(monoQueue.front());
// 遍历完 nums 剩下的元素
while (j < nums.length) {
monoQueue.enqueue(nums[j]);
monoQueue.dequeue(nums[i]);
resArr.push(monoQueue.front());
j++;
i++;
}
return resArr;
};
347. 前 K 个高频元素
难点是:优先级队列(小顶堆)的数据结构与api
/**
* @param {number[]} nums
* @param {number} k
* @return {number[]}
*/
var topKFrequent = function(nums, k) {
const map = new Map();
const res = [];
// 统计频次
for (const n of nums) {
map.set(n, (map.get(n) || 0) + 1)
}
//先创建一个小顶堆
const heap = new PriorityQueue({
compare: (a, b) => a.value - b.value
})
// 频次排序
for (const [key, value] of map) {
heap.enqueue({key, value});
if (heap.size() > k) {
heap.dequeue();
}
}
// 输出结果答案
while (heap.size()) {
res.push(heap.dequeue().key);
}
return res;
};