239. 滑动窗口最大值 (一刷至少需要理解思路)
之前讲的都是栈的应用,这次该是队列的应用了。
本题算比较有难度的,需要自己去构造单调队列,建议先看视频来理解。
题目
给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回 滑动窗口中的最大值。
输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
输出:[3,3,5,5,6,7]
解释:
滑动窗口的位置 最大值
--------------- -----
[1 3 -1] -3 5 3 6 7 3
1 [3 -1 -3] 5 3 6 7 3
1 3 [-1 -3 5] 3 6 7 5
1 3 -1 [-3 5 3] 6 7 5
1 3 -1 -3 [5 3 6] 7 6
1 3 -1 -3 5 [3 6 7] 7
答案
暴力解题的话会超时,思路是先找到滑动窗口内的数值,然后找到窗口内的最大值。
/**
* @param {number[]} nums
* @param {number} k
* @return {number[]}
*/
var maxSlidingWindow = function(nums, k) {
const getMaxNum = function(arr) {
let max = arr[0];
for(item of arr) {
if (item > max) max = item;
}
return max;
}
const queue = [], res = [];
for(item of nums) {
if (queue.length < k) queue.push(item)
if (queue.length === k) {
res.push(getMaxNum(queue));
queue.shift();
}
}
return res;
};
正确思路:维护一个递减的队列。在入队列时进行判断,如果新增的数值大于队尾的值,就将队尾的值干掉。
/**
* @param {number[]} nums
* @param {number} k
* @return {number[]}
*/
var maxSlidingWindow = function(nums, k) {
class MonoQueue {
queue;
constructor() {
this.queue = [];
}
enqueue(value) {
// 和队尾比较,如果比队尾大,就把队尾干掉
let back = this.queue[this.queue.length - 1];
while(back !== undefined && back < value) {
this.queue.pop();
back = this.queue[this.queue.length - 1];
}
this.queue.push(value);
}
dequeue(value) {
if (this.front() === value) this.queue.shift();
};
front() {
return this.queue[0];
};
};
let helpQueue = new MonoQueue();
let i = 0, j = 0, res = [];
while(j < k) {
helpQueue.enqueue(nums[j++]);
}
res.push(helpQueue.front());
while(j < nums.length) {
helpQueue.enqueue(nums[j++]);
helpQueue.dequeue(nums[i++]);
res.push(helpQueue.front());
}
return res;
};
347.前 K 个高频元素 (一刷至少需要理解思路)
大/小顶堆的应用, 在C++中就是优先级队列
本题是 大数据中取前k值 的经典思路,了解想法之后,不算难。
题目链接/文章讲解/视频讲解:https://programmercarl.com/0347.%E5%89%8DK%E4%B8%AA%E9%AB%98%E9%A2%91%E5%85%83%E7%B4%A0.html
总结
栈与队列做一个总结吧,加油
https://programmercarl.com/%E6%A0%88%E4%B8%8E%E9%98%9F%E5%88%97%E6%80%BB%E7%BB%93.html