0%

leetcode每日一题2020.1.2

239. 滑动窗口最大值

一、题目

给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。

返回滑动窗口中的最大值。

示例 1:

1
2
3
4
5
6
7
8
9
10
11
输入: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:

1
2
输入:nums = [1], k = 1
输出:[1]

示例 3:

1
2
输入:nums = [1,-1], k = 1
输出:[1,-1]

示例 4:

1
2
输入:nums = [9,11], k = 2
输出:[11]

示例 5:

1
2
输入:nums = [4,-2], k = 2
输出:[4]

提示

  • 1 ≤ nums.length ≤ 105
  • -104 ≤ nums[i] ≤ 104
  • 1 ≤ k ≤ nums.length

二、题解

方法1: 暴力法

  • 时间复杂度:O((n-k-1) * k),n 是 nums 的长度。总共 n-k-1 个滑动窗口,每个滑动窗口的找最大值的复杂度为 O(k),这种方式超出了题的时间限制。
  • 空间复杂度:O(1)
1
2
3
4
5
6
7
var maxSlidingWindow = function (nums, k) {
const res = [];
for (let i = 0; i <= nums.length - k; i++) {
res.push(Math.max(...nums.slice(i, i + k)));
}
return res;
};

方法2:滑动窗口 + 双端队列

1
2
3
4
5
题解:

双端队列:
每次push元素时,将队列中更小元素删除,直到不小时
每次pop元素时,如果是更小的元素在push时就已经删除了,只需要判断是否是头部最大值,是再删除一遍头部元素即可
  • 时间复杂度:O(n)
  • 空间复杂度:O(n)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
var maxSlidingWindow = function (nums, k) {
class slideWindow {
constructor() {
this.deque = [];
}
push(val) { // 队列从尾部开始,把小于val的数都去掉,然后将val加入队列末尾
while (this.deque.length > 0 && this.deque[this.deque.length - 1] < val) {
this.deque.pop()
}
this.deque.push(val)
}
pop(val) { // 判断以下队首元素是不是val(最大值),是就删除,不是就跳过
if (this.deque.length > 0 && this.deque[0] === val) {
this.deque.shift()
}
}
max() {
return this.deque[0]
}
}
let window = new slideWindow();
let res = [];
const n = nums.length;
for (let i = 0; i < n; i++) {
if (i < k - 1) {
window.push(nums[i])
} else {
window.push(nums[i]);
res.push(window.max())
window.pop(nums[i - k + 1]) // 判断滑动窗口的左边元素是不是window的左边元素,是的话就弹掉
}
}
return res;
};
万一真有土豪呢