给你一个整数数组nums
,有一个大小为k
的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的k
个数字。滑动窗口每次只向右移动一位。
返回滑动窗口中的最大值。
说一下我的解法
首先第一个窗口的最大值和最大值的下标i,一个循环即可找出 窗口前移一个位置时,我们可以假设第一个窗口的最大值还在窗口范围内,那么只需要比较一下最大值和新进入窗口的这个值,会有两种情况
为什么需要维护坐标,因为随着窗口移动,之前的最大值可能被移出窗口,移出窗口的时候,我们要重新查找一下窗口内的最大值和其坐标
这个解法的好处是,大部分时候都不用重新查找,只需要一次简单的比较,即可知道下个窗口内的最大值;而且这个解法不受窗口大小影响,暴力解法会超时,是因为如果窗口大小是nums.length的一半的时候,复杂度会变成O(n^2/4),我这个解法,窗口大,那么重复查找窗口最大值的次数就会少,窗口小,查找窗口最大值的代价就小
具体做法是,用nums.length - k + 1长度的数组,记录每个窗口的最大值和坐标 然后循环每个窗口,按照上面的方法去比较大小。
在数值比较随机的时候,整体的复杂度略大于n,大概需要给n乘上一个系数,但是这个系数会很小
/**
* @param {number[]} nums
* @param {number} k
* @return {number[]}
*/
var maxSlidingWindow = function(nums, k) {
// let total = 0;
const slides = nums.length - k + 1;
const s = [];
let maxNumber = Number.NEGATIVE_INFINITY;
let maxIndex = -1;
for (let i = 0; i < k; i++) {
if (nums[i] >= maxNumber) {
maxNumber = nums[i];
maxIndex = i;
}
// total++;
}
s[0] = [maxNumber, maxIndex];
// console.log(s);
for (let i = 1; i < slides; i++) {
let [max, index] = s[i - 1];
if (index < i) {
// 最大值不在窗口内了,重新计算num, index
max = Number.NEGATIVE_INFINITY;
index = -1;
for (let j = i; j < k + i; j++) {
if (nums[j] >= max) {
max = nums[j];
index = j;
}
// total++;
}
s[i] = [max, index];
} else {
// 只需要比较上个窗口最大值和下一个数字
if (nums[k + i - 1] >= max) {
max = nums[k + i - 1];
index = k + i - 1;
}
s[i] = [max, index];
// total++;
}
}
// console.log(s, total);
return s.map(el => el[0]);
};