提交 885350c5 编写于 作者: L luzhipeng

feat: #239

上级 6b7b6f9f
......@@ -136,6 +136,7 @@ leetcode 题解,记录自己的 leetcode 解题之路。
- 🆕 [128.longest-consecutive-sequence](./problems/128.longest-consecutive-sequence.md)
- [145.binary-tree-postorder-traversal](./problems/145.binary-tree-postorder-traversal.md)
- [146.lru-cache](./problems/146.lru-cache.md)
- 🆕 [239.sliding-window-maximum](./problems/239.sliding-window-maximum.md)
- 🆕 [295.find-median-from-data-stream.md](./problems/295.find-median-from-data-stream.md)
- [301.remove-invalid-parentheses](./problems/301.remove-invalid-parentheses.md)
......
<mxfile modified="2019-04-25T03:46:49.398Z" host="www.draw.io" agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36" etag="9O6h0S1KGXXQD0X-YjUP" version="10.6.5" type="device"><diagram id="eWjeoaqTePDURmZ7jabo" name="第 1 页">7Zpdb5swFIZ/DZetwOYrl0nWbJq2qVI3deqdC05ABUzBWdL9+tnFJIFDpk1JaqviKnD8gf28x+QcYwvP8+3HipTJVxbTzEJ2vLXwBwshByFX/EjLS2PxQ7sxrKo0VpX2hrv0N1XGtto6jWndqcgZy3hado0RKwoa8Y6NVBXbdKstWdZ9aklWFBjuIpJB630a86SxhijY2z/RdJW0T3b8SVOSk7aymkmdkJhtDkz4xsLzijHeXOXbOc0kvJZL025xpHQ3sIoW/F8a3N6y7z9KEno/H54+0+nDnK6nV7KB7OYXydZqxmq0/KVFULF1EVPZi23h2SZJOb0rSSRLN0J0YUt4nok7R1zWvGJPdM4yVr22xouFbyNflCzTLBuyqwHQitPt0ak5O2DC0yjLKa9eRJW2QestysmQr+43e8kCZUoO1MITZSTKS1a7rvcgxYVi+R9cHYDVOY3rOSihLqUJhOQNQPIuxQi6HtbPKDCLEQaMrvQ7EjLMkTwISb8nIcM8yQeQPO2MsGGOFBj4RsKG+VEIGPnaGbmG+dEEMAr0MzLMj9qQzegQyfF0U4KBpP5XUp/SLlnTRgmGkgaESf1YEgXo2tMMCsaTJ7pTL6tbhhGNoqE88DH0XM++kAMaQNaFLqh/pfYjdezqXqkDsbp5K1U/Jhitv4d1qp8rjPBPzIKM4OraurmePSswgquHdHM9eyZhBtfQ1cu1Hc97ew8M7Hu/LVcj05XANEowCo/ps7jskxJz5n/7vFKwgvZ8T5lIlq4KcRsJRlTYZ5JgGpFsqgryNI7lYwb5dxVasoIfOPDUD+1ZqOzqg50I684ild9VyvFhVO8OKIUuphQMV0elhpTa/d9rUwpGzKNSg0qFoWalYAw+KjWkFHYnmpWCUf2o1JBSboA0KwXzhFGpQaXaDXVdSmGYeYxKDSnlYZgjvq1SMJcZlRpUaqI5SscIKGUhP+Nq9pY8HdiC8Z/X8sDdTOboy9cTaAcmfyV/K1q3zcVwmh6aklH6/gcFP4C59NtqD3NpoFKL9gt5pNktq1OeMon4kXHO8q5+fRk4K3eqtgdAnSH92JpnaSGUb8+hSmViUic7mQZr1Akp5TDz7UoeoL0mmxrH168nV7/dw30l257NF0g+vy6bTpbpVj4BiH3MKcCG1K7LM7hHf6vFxzDZ8HzoHu0KPr97wM9yp7wainU+vhuOie95vd0b+2L/C+J2f3D6tezg+Dm++QM=</diagram></mxfile>
\ No newline at end of file
## 题目地址
https://leetcode.com/problems/sliding-window-maximum/description/
## 题目描述
```
Given an array nums, there is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves right by one position. Return the max sliding window.
Example:
Input: nums = [1,3,-1,-3,5,3,6,7], and k = 3
Output: [3,3,5,5,6,7]
Explanation:
Window position Max
--------------- -----
[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
Note:
You may assume k is always valid, 1 ≤ k ≤ input array's size for non-empty array.
Follow up:
Could you solve it in linear time?
```
## 思路
符合直觉的想法是直接遍历 nums, 然后然后用一个变量 slideWindow 去承载 k 个元素,
然后对 slideWindow 求最大值,这是可以的,时间复杂度是 O(n \* k).代码如下:
```js
/**
* @param {number[]} nums
* @param {number} k
* @return {number[]}
*/
var maxSlidingWindow = function(nums, k) {
// bad 时间复杂度O(n * k)
if (nums.length === 0 || k === 0) return [];
let slideWindow = [];
const ret = [];
for (let i = 0; i < nums.length - k + 1; i++) {
for (let j = 0; j < k; j++) {
slideWindow.push(nums[i + j]);
}
ret.push(Math.max(...slideWindow));
slideWindow = [];
}
return ret;
};
```
但是如果真的是这样,这道题也不会是 hard 吧?这道题有一个 follow up,要求你用线性的时间去完成。
我们可以用双端队列来完成,思路是用一个双端队列来保存`接下来的滑动窗口可能成为最大值的数`。具体做法:
- 入队列
- 移除失效元素,失效元素有两种
1. 一种是已经超出窗口范围了,比如我遍历到第4个元素,k = 3,那么i = 0的元素就不应该出现在双端队列中了
具体就是`索引大于 i - k + 1的元素都应该被清除`
2. 小于当前元素都没有利用价值了,具体就是`从后往前遍历(双端队列是一个递减队列)双端队列,如果小于当前元素就出队列`
如果你仔细观察的话,发现双端队列其实是一个递减的一个队列。因此队首的元素一定是最大的。用图来表示就是:
![239.sliding-window-maximum](../assets/problems/239.sliding-window-maximum.png)
## 关键点解析
- 递归简化操作
- 如果树很高,建议使用栈来代替递归
- 这道题目对顺序没要求的,因此队列数组操作都是一样的,无任何区别
## 代码
```js
/*
* @lc app=leetcode id=239 lang=javascript
*
......@@ -46,17 +130,31 @@
* @return {number[]}
*/
var maxSlidingWindow = function(nums, k) {
// bad 时间复杂度O(n^2)
if (nums.length === 0 || k === 0) return [];
let slideWindow = [];
// 双端队列优化时间复杂度, 时间复杂度O(n)
const deque = []; // 存放在接下来的滑动窗口可能成为最大值的数
const ret = [];
for (let i = 0; i < nums.length - k + 1; i++) {
for (let j = 0; j < k; j++) {
slideWindow.push(nums[i + j]);
for (let i = 0; i < nums.length; i++) {
// 清空失效元素
while (deque[0] < i - k + 1) {
deque.shift();
}
while (nums[deque[deque.length - 1]] < nums[i]) {
deque.pop();
}
deque.push(i);
if (i >= k - 1) {
ret.push(nums[deque[0]]);
}
ret.push(Math.max(...slideWindow));
slideWindow = [];
}
return ret;
// 双端队列优化时间复杂度
};
```
## 扩展
### 为什么用双端队列
因为删除无效元素的时候,会清除队首的元素(索引太小了
)或者队尾(元素太小了)的元素。 因此需要同时对队首和队尾进行操作,使用双端队列是一种合乎情理的做法。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册