挑战LeetCode热题100(TS)
打卡第八天
滑动窗口
给你一个整数数组 nums,有一个大小为 k **的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回 滑动窗口中的最大值 。
1.滑动窗口最大值
示例 1:
输入: 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
示例 2:
输入: nums = [1], k = 1
输出: [1]
思路一:暴力破解
function maxSlidingWindow(nums: number[], k: number): number[] {
// 循环
// const n = nums.length
// const res = []
// for(let i=0;i<=n-k;i++) {
// let j = i
// let max = nums[j]
// while(j<i+k) {
// max = Math.max(nums[j], max)
// j++
// }
// res.push(max)
// }
// return res
//
};
- 时间复杂度:O(n*n)
思路二:双端队列;
function maxSlidingWindow(nums: number[], k: number): number[] {
const result: number[] = [];
const deque: number[] = [];
for (let i = 0; i < nums.length; i++) {
// 如果双端队列中的元素超出了窗口范围,将其移出队列
if (deque.length > 0 && deque[0] < i - k + 1) {
deque.shift();
}
// 移除队列中比当前元素小的元素,因为它们不可能成为最大值
while (deque.length > 0 && nums[deque[deque.length - 1]] < nums[i]) {
deque.pop();
}
// 将当前元素的索引加入队列
deque.push(i);
// 如果窗口的起始索引已经在合法范围内,将队列头部元素作为最大值添加到结果中
if (i >= k - 1) {
result.push(nums[deque[0]]);
}
}
return result;
}
思路三:优先队列
- 初始时,我们将数组 nums 的前 kkk 个元素放入优先队列中。每当我们向右移动窗口时,我们就可以把一个新的元素放入优先队列中,此时堆顶的元素就是堆中所有元素的最大值。然而这个最大值可能并不在滑动窗口中,在这种情况下,这个值在数组 nums 中的位置出现在滑动窗口左边界的左侧。因此,当我们后续继续向右移动窗口时,这个值就永远不可能出现在滑动窗口中了,我们可以将其永久地从优先队列中移除。
- 我们不断地移除堆顶的元素,直到其确实出现在滑动窗口中。此时,堆顶元素就是滑动窗口中的最大值。为了方便判断堆顶元素与滑动窗口的位置关系,我们可以在优先队列中存储二元组 (num,index),,表示元素 num 在数组中的下标为 index。
class Solution {
maxSlidingWindow(nums: number[], k: number): number[] {
const n = nums.length;
const maxHeap: [number, number][] = [];
for (let i = 0; i < k; i++) {
maxHeap.push([-nums[i], i]);
}
maxHeap.sort((a, b) => a[0] - b[0]);
const ans: number[] = [-maxHeap[0][0]];
for (let i = k; i < n; i++) {
maxHeap.push([-nums[i], i]);
while (maxHeap[0][1] <= i - k) {
maxHeap.shift();
}
ans.push(-maxHeap[0][0]);
}
return ans;
}
}
const solution = new Solution();
const nums = [1, 3, -1, -3, 5, 3, 6, 7];
const k = 3;
const result = solution.maxSlidingWindow(nums, k);
console.log(result); // 输出 [3, 3, 5, 5, 6, 7]
总结
如果使用优先队列方式构建大顶堆,采用暴力破解很耗时,虽然内存开销较小。但优先队列不太容易理解,还需要先掌握树,队列,堆,栈等相关概念后,再基于ts去实现后。再做此题很容易想到有限队列