Skip to content

Commit e4b82a7

Browse files
committed
max window
1 parent 7626581 commit e4b82a7

File tree

1 file changed

+54
-105
lines changed

1 file changed

+54
-105
lines changed

13-《进阶》单调栈和窗口.md

Lines changed: 54 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434

3535
3、我们窗口结构一直被维护,双端队列右边进,左边出。那么窗口的最大值就是我们双端队列最左侧(头部)的值
3636

37-
==双端队列结构实质上指的是:如果此时形成的窗口状况,不想让R往右动了,而让L往右动。谁会以此成为最大值的优先级。为什么弹出的数不再找回,原因是在窗口滑动的过程中,被弹出的数的优先级已经被后来的大数取代了,这就是尾端加入,前一个数比当前数小则弹出,比当前数大就加入当前数的道理==
37+
双端队列结构实质上指的是:如果此时形成的窗口状况,不想让R往右动了,而让L往右动。谁会以此成为最大值的优先级。为什么弹出的数不再找回,原因是在窗口滑动的过程中,被弹出的数的优先级已经被后来的大数取代了,这就是尾端加入,前一个数比当前数小则弹出,比当前数大就加入当前数的道理
3838

3939

4040
> 反之,如果我们要窗口内最小值,只需要维护我们的双端队列单调递增的,既由小到大的即可
@@ -44,129 +44,78 @@
4444

4545
### 1.1.4 高频题:求滑动窗口最大值
4646

47-
假设一个固定大小为W的窗口,以此划过arr,返回每一次划出状况的最大值
47+
假设一个固定大小为W的窗口,依次划过arr,返回每一次划出状况的最大值
4848

4949
例如,`arr=[4, 3, 5, 4, 3, 3, 6, 7]`
5050

5151
返回:`[5, 5, 5, 4, 6, 7]`
5252

5353
分析:窗口起始是4,3,5,窗口内最大值是5。窗口向右滑动变为3,5,4最大值5......
5454

55-
```Java
56-
57-
package class01;
55+
```Go
56+
package main
5857

59-
import java.util.LinkedList;
60-
61-
public class Code01_SlidingWindowMaxArray {
58+
import (
59+
"container/list"
60+
"fmt"
61+
)
6262

63-
public static int[] getMaxWindow(int[] arr, int w) {
64-
if (arr == null || w < 1 || arr.length < w) {
65-
return null;
66-
}
67-
68-
// Java中LinkedList就是双端队列,双向链表
69-
// 其中放的是下标位置,头代表 (大->小)尾
70-
LinkedList<Integer> qmax = new LinkedList<Integer>();
71-
// 窗口在滑动的过程中,最终会生成arr长度-窗口起始宽度+1个值
72-
int[] res = new int[arr.length - w + 1];
73-
int index = 0;
74-
// L...R
75-
// R
76-
for (int R = 0; R < arr.length; R++) { // 当前让 i -> [i] 进窗口 , i 就是 r
77-
// R 位置的值 可以放在比他大的数后,或者空
78-
// 双端队列不为空,且双端队列尾部的值小于当前要进入窗口的值
79-
while (!qmax.isEmpty() && arr[qmax.peekLast()] <= arr[R]) {
80-
// 双端队列从尾部弹出
81-
qmax.pollLast();
82-
}
83-
// 经过上述的while,最终把当前进入窗口的数放入双端队列的尾部
84-
qmax.addLast(R);
85-
// 数进来了
86-
// 如果窗口没有形成W的长度之前,不弹出数字的
87-
// 当前下标是R, R-W就是需要过期的下标。
88-
// 如果双端队列的头部保存的下标等于R-W,就头部弹出。实质R-W就是我们原始结构的L下标
89-
if (qmax.peekFirst() == R - w) {
90-
qmax.pollFirst();
91-
}
92-
// 以上窗口更新做完了
93-
// 窗口没有形成W长度之前,不收集答案。形成W长度后,每一次收集一个答案
94-
if (R >= w - 1) {
95-
res[index++] = arr[qmax.peekFirst()];
96-
}
97-
}
98-
return res;
63+
// getMaxWindow arr 是数据样本 w是窗口大小
64+
func getMaxWindow(arr []int, w int) []int {
65+
if len(arr) == 0 || w < 1 || len(arr) < w {
66+
return nil
9967
}
10068

101-
// for test
102-
public static int[] rightWay(int[] arr, int w) {
103-
if (arr == null || w < 1 || arr.length < w) {
104-
return null;
105-
}
106-
int[] res = new int[arr.length - w + 1];
107-
int index = 0;
108-
int L = 0;
109-
int R = w - 1;
110-
while (R < arr.length) {
111-
int max = arr[L];
112-
for (int i = L + 1; i <= R; i++) {
113-
max = Math.max(max, arr[i]);
114-
69+
// 双向链表
70+
// 其中放的是下标位置,头代表 (大->小)尾
71+
qmax := list.List{}
72+
// 窗口在滑动的过程中,最终会生成arr长度-窗口起始宽度+1个值
73+
res := make([]int, len(arr) - w + 1)
74+
index := 0
75+
// 双端队列的头部元素
76+
var fe = &list.Element{}
77+
// 双端队列的尾部元素
78+
var ee = &list.Element{}
79+
// L...R
80+
// R
81+
for R := 0; R < len(arr); R++ { // 当前让 i -> [i] 进窗口 , i 就是 r
82+
// R 位置的值 可以放在比他大的数后,或者空
83+
// 双端队列不为空,且双端队列尾部的值小于当前要进入窗口的值
84+
for qmax.Len() != 0 && arr[qmax.Back().Value.(int)] <= arr[R] {
85+
// 双端队列从尾部弹出
86+
qmax.Remove(ee)
87+
if qmax.Len() > 0 {
88+
ee = qmax.Back()
89+
fe = qmax.Front()
11590
}
116-
res[index++] = max;
117-
L++;
118-
R++;
11991
}
120-
return res;
121-
}
122-
123-
// for test
124-
public static int[] generateRandomArray(int maxSize, int maxValue) {
125-
int[] arr = new int[(int) ((maxSize + 1) * Math.random())];
126-
for (int i = 0; i < arr.length; i++) {
127-
arr[i] = (int) (Math.random() * (maxValue + 1));
92+
// 经过上述的while,最终把当前进入窗口的数放入双端队列的尾部
93+
qmax.PushBack(R)
94+
fe = qmax.Front()
95+
ee = qmax.Back()
96+
// 数进来了
97+
// 如果窗口没有形成W的长度之前,不弹出数字的
98+
// 当前下标是R, R-W就是需要过期的下标。
99+
// 如果双端队列的头部保存的下标等于R-W,就头部弹出。实质R-W就是我们原始结构的L下标
100+
if qmax.Front().Value.(int) == R - w {
101+
qmax.Remove(fe)
128102
}
129-
return arr;
130-
}
131103

132-
// for test
133-
public static boolean isEqual(int[] arr1, int[] arr2) {
134-
if ((arr1 == null && arr2 != null) || (arr1 != null && arr2 == null)) {
135-
return false;
136-
}
137-
if (arr1 == null && arr2 == null) {
138-
return true;
139-
}
140-
if (arr1.length != arr2.length) {
141-
return false;
142-
}
143-
for (int i = 0; i < arr1.length; i++) {
144-
if (arr1[i] != arr2[i]) {
145-
return false;
146-
}
104+
// 以上窗口更新做完了
105+
// 窗口没有形成W长度之前,不收集答案。形成W长度后,每一次收集一个答案
106+
if R >= w -1 {
107+
res[index] = arr[qmax.Front().Value.(int)]
108+
index++
147109
}
148-
return true;
149110
}
150-
151-
public static void main(String[] args) {
152-
int testTime = 100000;
153-
int maxSize = 100;
154-
int maxValue = 100;
155-
System.out.println("test begin");
156-
for (int i = 0; i < testTime; i++) {
157-
int[] arr = generateRandomArray(maxSize, maxValue);
158-
int w = (int) (Math.random() * (arr.length + 1));
159-
int[] ans1 = getMaxWindow(arr, w);
160-
int[] ans2 = rightWay(arr, w);
161-
if (!isEqual(ans1, ans2)) {
162-
System.out.println("Oops!");
163-
}
164-
}
165-
System.out.println("test finish");
166-
}
167-
111+
return res
168112
}
169113

114+
func main() {
115+
arr := []int{4, 3, 5, 4, 3, 3, 6, 7}
116+
w := 3
117+
fmt.Println(getMaxWindow(arr, w))
118+
}
170119
```
171120

172121
### 1.1.5 高频题二:达标子数组数量问题

0 commit comments

Comments
 (0)