Skip to content

Commit

Permalink
fix: 239 用 deque
Browse files Browse the repository at this point in the history
  • Loading branch information
lucifer committed Nov 30, 2020
1 parent b971fca commit 8285fc2
Showing 1 changed file with 14 additions and 17 deletions.
31 changes: 14 additions & 17 deletions problems/239.sliding-window-maximum.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ https://leetcode-cn.com/problems/sliding-window-maximum/
示例:
输入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3
输出: [3,3,5,5,6,7]
解释:
输出: [3,3,5,5,6,7]
解释:
滑动窗口的位置 最大值
--------------- -----
Expand All @@ -45,7 +45,7 @@ https://leetcode-cn.com/problems/sliding-window-maximum/

- 队列
- 滑动窗口

## 公司

- 阿里
Expand All @@ -61,7 +61,7 @@ https://leetcode-cn.com/problems/sliding-window-maximum/
JavaScript:

```js
var maxSlidingWindow = function(nums, k) {
var maxSlidingWindow = function (nums, k) {
// bad 时间复杂度O(n * k)
if (nums.length === 0 || k === 0) return [];
let slideWindow = [];
Expand All @@ -76,6 +76,7 @@ var maxSlidingWindow = function(nums, k) {
return ret;
};
```

Python3:

```python
Expand All @@ -91,17 +92,15 @@ class Solution:
但是如果真的是这样,这道题也不会是 hard 吧?这道题有一个 follow up,要求你用线性的时间去完成。
我们可以用双端队列来完成,思路是用一个双端队列来保存`接下来的滑动窗口可能成为最大值的数`。具体做法:


- 入队列

- 移除失效元素,失效元素有两种

1. 一种是已经超出窗口范围了,比如我遍历到第4个元素,k = 3,那么i = 0的元素就不应该出现在双端队列中了
具体就是`索引大于 i - k + 1的元素都应该被清除`
1. 一种是已经超出窗口范围了,比如我遍历到第 4 个元素,k = 3,那么 i = 0 的元素就不应该出现在双端队列中了
具体就是`索引大于 i - k + 1的元素都应该被清除`

2. 小于当前元素都没有利用价值了,具体就是`从后往前遍历(双端队列是一个递减队列)双端队列,如果小于当前元素就出队列`


如果你仔细观察的话,发现双端队列其实是一个递减的一个队列。因此队首的元素一定是最大的。用图来表示就是:

![](https://tva1.sinaimg.cn/large/007S8ZIlly1ghltxg29buj30hb0di757.jpg)
Expand All @@ -114,11 +113,10 @@ class Solution:

## 代码


JavaScript:

```js
var maxSlidingWindow = function(nums, k) {
var maxSlidingWindow = function (nums, k) {
// 双端队列优化时间复杂度, 时间复杂度O(n)
const deque = []; // 存放在接下来的滑动窗口可能成为最大值的数
const ret = [];
Expand Down Expand Up @@ -147,17 +145,16 @@ Python3:
```python
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
deque, res, n = [], [], len(nums)
deque, res, n = collections.deque(), [], len(nums)
for i in range(n):
while deque and deque[0] < i - k + 1:
deque.pop(0)
deque.popleft()
while deque and nums[i] > nums[deque[-1]]:
deque.pop(-1)
deque.pop()
deque.append(i)
if i >= k - 1: res.append(nums[deque[0]])
if i >= k - 1:
res.append(nums[deque[0]])
return res


```

**复杂度分析**
Expand All @@ -168,8 +165,8 @@ class Solution:
## 扩展

### 为什么用双端队列
因为删除无效元素的时候,会清除队首的元素(索引太小了)或者队尾(元素太小了)的元素。 因此需要同时对队首和队尾进行操作,使用双端队列是一种合乎情理的做法。

因为删除无效元素的时候,会清除队首的元素(索引太小了)或者队尾(元素太小了)的元素。 因此需要同时对队首和队尾进行操作,使用双端队列是一种合乎情理的做法。

大家对此有何看法,欢迎给我留言,我有时间都会一一查看回答。更多算法套路可以访问我的 LeetCode 题解仓库:https://github.com/azl397985856/leetcode 。 目前已经 37K star 啦。
大家也可以关注我的公众号《力扣加加》带你啃下算法这块硬骨头。
Expand Down

0 comments on commit 8285fc2

Please sign in to comment.