algorithm-base/animation-simulation/单调队列单调栈/滑动窗口的最大值.md
2021-07-28 02:26:32 +08:00

109 lines
5.2 KiB
Java
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
}
```