algorithm-base/animation-simulation/单调队列单调栈/滑动窗口的最大值.md
2023-05-07 11:18:42 +08:00

109 lines
5.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈
>
> 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。
>
> 另外希望手机阅读的同学可以来我的 <u>[**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)</u> 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击<u>[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)</u>进入。
#### [剑指 Offer 59 - I. 滑动窗口的最大值](https://leetcode-cn.com/problems/hua-dong-chuang-kou-de-zui-da-zhi-lcof/)
这个题目,算是很经典的类型,我们的滑动窗口主要分为两种,一种的可变长度的滑动窗口,一种是固定长度的滑动窗口,这个题目算是固定长度的代表。今天我们用双端队列来解决我们这个题目,学会了这个题目的解题思想你可以去解决一下两道题目 [剑指 Offer 59 - II. 队列的最大值](https://leetcode-cn.com/problems/dui-lie-de-zui-da-zhi-lcof/)[155. 最小栈](https://leetcode-cn.com/problems/min-stack/),虽然这两个题目和该题类型不同,但是解题思路是一致的,都是很不错的题目,我认为做题,那些考察的很细的,解题思路很难想,即使想到,也不容易完全写出来的题目,才是能够大大提高我们编码能力的题目,希望能和大家一起进步。
这个题目我们用到了**双端队列**,队列里面保存的则为每段滑动窗口的最大值,我给大家做了一个动图,先来看一下代码执行过程吧。
我们先来了解下双端队列吧,队列我们都知道,是先进先出,双端队列呢?既可以从队头出队,也可以从队尾出队,则不用遵循先进先出的规则。
下面我们通过一个动图来了解一下吧。
![](https://img-blog.csdnimg.cn/20210319154950406.gif)
好啦,我们了解双端队列是什么东东了,下面我们通过一个动画,来看一下代码的执行过程吧,相信各位一下就能够理解啦。
我们就通过题目中的例子来表述。nums = [1,3,-1,-3,5,3,6,7], k = 3
![](https://img-blog.csdnimg.cn/20210319162114967.gif)
不知道通过上面的例子能不能给各位描述清楚,如果不能的话,我再加把劲,各位看官,请接着往下看。
我们将执行过程进行拆解。
1.想将我们第一个窗口的所有值存入单调双端队列中,单调队列里面的值为单调递减的。如果发现队尾元素小于要加入的元素,则将队尾元素出队,直到队尾元素大于新元素时,再让新元素入队,目的就是维护一个单调递减的队列。
2.我们将第一个窗口的所有值,按照单调队列的规则入队之后,因为队列为单调递减,所以队头元素必为当前窗口的最大值,则将队头元素添加到数组中。
3.移动窗口,判断当前**窗口前的元素**是否和队头元素相等,如果相等则出队。
4.继续然后按照规则进行入队,维护单调递减队列。
5.每次将队头元素存到返回数组里。
5.返回数组
是不是懂啦,再回去看一遍视频吧。祝大家新年快乐,天天开心呀!
```java
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
int len = nums.length;
if (len == 0) {
return nums;
}
int[] arr = new int[len - k + 1];
int arr_index = 0;
//我们需要维护一个单调递增的双向队列
Deque<Integer> deque = new LinkedList<>();
for (int i = 0; i < k; i++) {
while (!deque.isEmpty() && deque.peekLast() < nums[i]) {
deque.removeLast();
}
deque.offerLast(nums[i]);
}
arr[arr_index++] = deque.peekFirst();
for (int j = k; j < len; j++) {
if (nums[j - k] == deque.peekFirst()) {
deque.removeFirst();
}
while (!deque.isEmpty() && deque.peekLast() < nums[j]) {
deque.removeLast();
}
deque.offerLast(nums[j]);
arr[arr_index++] = deque.peekFirst();
}
return arr;
}
}
```
GO Code:
```go
func maxSlidingWindow(nums []int, k int) []int {
l := len(nums)
if l == 0 {
return nums
}
arr := []int{}
// 维护一个单调递减的双向队列
deque := []int{}
for i := 0; i < k; i++ {
for len(deque) != 0 && deque[len(deque) - 1] < nums[i] {
deque = deque[:len(deque) - 1]
}
deque = append(deque, nums[i])
}
arr = append(arr, deque[0])
for i := k; i < l; i++ {
if nums[i - k] == deque[0] {
deque = deque[1:]
}
for len(deque) != 0 && deque[len(deque) - 1] < nums[i] {
deque = deque[:len(deque) - 1]
}
deque = append(deque, nums[i])
arr = append(arr, deque[0])
}
return arr
}
```