Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit dd52597

Browse files
committed
Update 01.Array-Sliding-Window.md
1 parent 5662489 commit dd52597

File tree

1 file changed

+137
-43
lines changed

1 file changed

+137
-43
lines changed

‎Contents/01.Array/05.Array-Sliding-Window/01.Array-Sliding-Window.md

Lines changed: 137 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,18 @@
22

33
在计算机网络中,滑动窗口协议(Sliding Window Protocol)是传输层进行流控的一种措施,接收方通过通告发送方自己的窗口大小,从而控制发送方的发送速度,从而达到防止发送方发送速度过快而导致自己被淹没的目的。我们所要讲解的滑动窗口算法也是利用了同样的特性。
44

5-
> 滑动窗口(Sliding Window):在给定数组 / 字符串上维护一个固定长度或不定长度的窗口。可以对窗口进行滑动操作、缩放操作,以及维护最优解操作。
5+
> **滑动窗口算法(Sliding Window)**:在给定数组 / 字符串上维护一个固定长度或不定长度的窗口。可以对窗口进行滑动操作、缩放操作,以及维护最优解操作。
66
7-
- 滑动操作:窗口可按照一定方向进行移动。最常见的是向右侧移动。
8-
- 缩放操作:对于不定长度的窗口,可以从左侧缩小窗口长度,也可以从右侧增大窗口长度。
7+
- **滑动操作**:窗口可按照一定方向进行移动。最常见的是向右侧移动。
8+
- **缩放操作**:对于不定长度的窗口,可以从左侧缩小窗口长度,也可以从右侧增大窗口长度。
99

10-
滑动窗口利用了双指针中的快慢指针技巧,我们可以将滑动窗口看做是快慢指针两个指针中间的区间,也可以可以将滑动窗口看做是快慢指针的一种特殊形式
10+
滑动窗口利用了双指针中的快慢指针技巧,我们可以将滑动窗口看做是快慢指针两个指针中间的区间,也可以将滑动窗口看做是快慢指针的一种特殊形式
1111

1212
## 2. 滑动窗口适用范围
1313

1414
滑动窗口算法一般用来解决一些查找满足一定条件的连续区间的性质(长度等)的问题。该算法可以将一部分问题中的嵌套循环转变为一个单循环,因此它可以减少时间复杂度。
1515

16-
根据问题,我们可以将滑动窗口分为以下两种:
16+
按照窗口长度的固定情况,我们可以将滑动窗口题目分为以下两种:
1717

1818
- **固定长度窗口**:窗口大小是固定的。
1919
- **不定长度窗口**:窗口大小是不固定的。
@@ -66,26 +66,46 @@ while right < len(nums):
6666

6767
#### 3.3.2 题目大意
6868

69-
给你一个整数数组 `arr` 和两个整数 `k``threshold`
69+
**描述**:给定一个整数数组 `arr` 和两个整数 `k``threshold`
7070

71-
要求:返回长度为 `k` 且平均值大于等于 `threshold` 的子数组数目。
71+
**要求**:返回长度为 `k` 且平均值大于等于 `threshold` 的子数组数目。
72+
73+
**说明**:
74+
75+
- 1ドル \le arr.length \le 10^5$。
76+
- 1ドル \le arr[i] \le 10^4$。
77+
- 1ドル \le k \le arr.length$。
78+
- 0ドル \le threshold \le 10^4$。
79+
80+
**示例**:
81+
82+
```Python
83+
输入:arr = [2,2,2,2,5,5,5,8], k = 3, threshold = 4
84+
输出:3
85+
解释:子数组 [2,5,5],[5,5,5] 和 [5,5,8] 的平均值分别为 4,56 。其他长度为 3 的子数组的平均值都小于 4 (threshold 的值)。
86+
87+
88+
输入:arr = [11,13,17,23,29,31,7,5,2,3], k = 3, threshold = 5
89+
输出:6
90+
解释:前 6 个长度为 3 的子数组平均值都大于 5 。注意平均值不是整数。
91+
```
7292

7393
#### 3.3.3 解题思路
7494

95+
##### 思路 1:滑动窗口(固定长度)
96+
7597
这道题目是典型的固定窗口大小的滑动窗口题目。窗口大小为 `k`。具体做法如下:
7698

7799
1. `ans` 用来维护答案数目。`window_sum` 用来维护窗口中元素的和。
78100
2. `left``right` 都指向序列的第一个元素,即:`left = 0`,`right = 0`
79-
3. 当窗口元素个数不足 `k` 个时,不断移动 `right`,先将 `k` 个元素填入窗口中。
80-
4. 当窗口元素个数为 `k` 时,即:`right - left + 1 >= k` 时,判断窗口内的元素和平均值是否大于等于阈值。
101+
3. 向右移动 `right`,先将 `k` 个元素填入窗口中。
102+
4. 当窗口元素个数为 `k` 时,即:`right - left + 1 >= k` 时,判断窗口内的元素和平均值是否大于等于阈值`threshold`
81103
1. 如果满足,则答案数目 + 1。
82104
2. 然后向右移动 `left`,从而缩小窗口长度,即 `left += 1`,使得窗口大小始终保持为 `k`
83-
5. 向右移动 `right`,将元素填入窗口中
84-
6. 重复 3 ~ 5 步,直到 `right` 到达数组末尾
105+
5. 重复 3 ~ 4 步,直到 `right` 到达数组末尾
106+
6. 最后输出答案数目
85107

86-
最后输出答案数目。
87-
88-
#### 3.3.4 代码
108+
##### 思路 1:代码
89109

90110
```Python
91111
class Solution:
@@ -109,6 +129,11 @@ class Solution:
109129
return ans
110130
```
111131

132+
##### 思路 1:复杂度分析
133+
134+
- **时间复杂度**:$O(n)$。
135+
- **空间复杂度**:$O(n)$。
136+
112137
## 4. 不定长度窗口
113138

114139
### 4.1 不定长度窗口求解步骤
@@ -146,23 +171,42 @@ while right < len(nums):
146171

147172
#### 4.3.2 题目大意
148173

149-
给定一个字符串 `s`
174+
**描述**:给定一个字符串 `s`
175+
176+
**要求**:找出其中不含有重复字符的最长子串的长度。
177+
178+
**说明**:
150179

151-
要求:找出其中不含有重复字符的 最长子串 的长度。
180+
- 0ドル \le s.length \le 5 * 10^4$。
181+
- `s` 由英文字母、数字、符号和空格组成。
182+
183+
**示例**:
184+
185+
```Python
186+
输入: s = "abcabcbb"
187+
输出: 3
188+
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3
189+
190+
191+
输入: s = "bbbbb"
192+
输出: 1
193+
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1
194+
```
152195

153196
#### 4.3.3 解题思路
154197

155-
用滑动窗口 `window` 来记录不重复的字符个数,`window` 为哈希表类型。
198+
##### 思路 1:滑动窗口(不定长度)
156199

157-
设定两个指针:`left``right`,分别指向滑动窗口的左右边界,保证窗口中没有重复字符
200+
用滑动窗口 `window` 来记录不重复的字符个数,`window` 为哈希表类型
158201

159-
- 一开始,`left``right` 都指向 `0`
160-
- 将最右侧字符 `s[right]` 加入当前窗口 `window` 中,记录该字符个数。
161-
- 如果该窗口中该字符的个数多于 1 个,即 `window[s[right]] > 1`,则不断右移 `left`,缩小滑动窗口长度,并更新窗口中对应字符的个数,直到 `window[s[right]] <= 1`
162-
- 维护更新无重复字符的最长子串长度。然后右移 `right`,直到 `right >= len(nums)` 结束。
163-
- 输出无重复字符的最长子串长度。
202+
1. 设定两个指针:`left``right`,分别指向滑动窗口的左右边界,保证窗口中没有重复字符。
203+
2. 一开始,`left``right` 都指向 `0`
204+
3. 向右移动 `right`,将最右侧字符 `s[right]` 加入当前窗口 `window` 中,记录该字符个数。
205+
4. 如果该窗口中该字符的个数多于 1 个,即 `window[s[right]] > 1`,则不断右移 `left`,缩小滑动窗口长度,并更新窗口中对应字符的个数,直到 `window[s[right]] <= 1`
206+
5. 维护更新无重复字符的最长子串长度。然后继续右移 `right`,直到 `right >= len(nums)` 结束。
207+
6. 输出无重复字符的最长子串长度。
164208

165-
####4.3.4 代码
209+
##### 思路 1:代码
166210

167211
```Python
168212
class Solution:
@@ -188,6 +232,11 @@ class Solution:
188232
return ans
189233
```
190234

235+
##### 思路 1:复杂度分析
236+
237+
- **时间复杂度**:$O(n)$。
238+
- **空间复杂度**:$O(| \sum |)$。其中 $\sum$ 表示字符集,$| \sum |$ 表示字符集的大小。
239+
191240
### 4.4 长度最小的子数组
192241

193242
#### 4.4.1 题目链接
@@ -196,23 +245,43 @@ class Solution:
196245

197246
#### 4.4.2 题目大意
198247

199-
给定一个只包含正整数的数组 `nums` 和一个正整数 `target`
248+
**描述**:给定一个只包含正整数的数组 `nums` 和一个正整数 `target`
249+
250+
**要求**:找出数组中满足和大于等于 `target` 的长度最小的「连续子数组」,并返回其长度。如果不存在符合条件的子数组,返回 `0`
200251

201-
要求:找出数组中满足和大于等于 `target` 的长度最小的「连续子数组」,并返回其长度。如果不存在符合条件的子数组,返回 `0`
252+
**说明**:
253+
254+
- 1ドル \le target \le 10^9$。
255+
- 1ドル \le nums.length \le 10^5$。
256+
- 1ドル \le nums[i] \le 10^5$。
257+
258+
**示例**:
259+
260+
```Python
261+
输入:target = 7, nums = [2,3,1,2,4,3]
262+
输出:2
263+
解释:子数组 [4,3] 是该条件下的长度最小的子数组。
264+
265+
266+
输入:target = 4, nums = [1,4,4]
267+
输出:1
268+
```
202269

203270
#### 4.4.3 解题思路
204271

272+
##### 思路 1:滑动窗口(不定长度)
273+
205274
最直接的做法是暴力枚举,时间复杂度为 $O(n^2)$。但是我们可以利用滑动窗口的方法,在时间复杂度为 $O(n)$ 的范围内解决问题。
206275

207276
用滑动窗口来记录连续子数组的和,设定两个指针:`left``right`,分别指向滑动窗口的左右边界,保证窗口中的和刚好大于等于 `target`
208277

209-
- 一开始,`left``right` 都指向 `0`
210-
- 向右移动 `right`,将最右侧元素加入当前窗口和 `window_sum` 中。
211-
- 如果 `window_sum >= target`,则不断右移 `left`,缩小滑动窗口长度,并更新窗口和的最小值,直到 `window_sum < target`
212-
- 然后继续右移 `right`,直到 `right >= len(nums)` 结束。
213-
- 输出窗口和的最小值作为答案。
278+
1. 一开始,`left``right` 都指向 `0`
279+
2. 向右移动 `right`,将最右侧元素加入当前窗口和 `window_sum` 中。
280+
3. 如果 `window_sum >= target`,则不断右移 `left`,缩小滑动窗口长度,并更新窗口和的最小值,直到 `window_sum < target`
281+
4. 然后继续右移 `right`,直到 `right >= len(nums)` 结束。
282+
5. 输出窗口和的最小值作为答案。
214283

215-
####4.4.4 代码
284+
##### 思路 1:代码
216285

217286
```Python
218287
class Solution:
@@ -236,6 +305,11 @@ class Solution:
236305
return ans if ans != size + 1 else 0
237306
```
238307

308+
##### 思路 1:复杂度分析
309+
310+
- **时间复杂度**:$O(n)$。
311+
- **空间复杂度**:$O(1)$。
312+
239313
### 4.5 乘积小于K的子数组
240314

241315
#### 4.5.1 题目链接
@@ -244,25 +318,40 @@ class Solution:
244318

245319
#### 4.5.2 题目大意
246320

247-
给定一个正整数数组 `nums`和整数 `k`
321+
**描述**:给定一个正整数数组 `nums`和整数 `k`
248322

249-
要求:找出该数组内乘积小于 `k` 的连续的子数组的个数。
323+
**要求**:找出该数组内乘积小于 `k` 的连续的子数组的个数。
250324

251-
#### 4.5.3 解题思路
325+
**说明**:
252326

253-
滑动窗口求解。
327+
- 1ドル \le nums.length \le 3 * 10^4$。
328+
- 1ドル \le nums[i] \le 1000$。
329+
- 0ドル \le k \le 10^6$。
254330

255-
设定两个指针:`left``right`,分别指向滑动窗口的左右边界,保证窗口内所有数的乘积 `window_product` 都小于 `k`。使用 `window_product` 记录窗口中的乘积值,使用 `count` 记录符合要求的子数组个数。
331+
**示例**:
256332

257-
- 一开始,`left``right` 都指向 `0`
333+
```Python
334+
输入:nums = [10,5,2,6], k = 100
335+
输出:8
336+
解释:8 个乘积小于 100 的子数组分别为:[10]、[5]、[2],、[6]、[10,5]、[5,2]、[2,6]、[5,2,6]。需要注意的是 [10,5,2] 并不是乘积小于 100 的子数组。
258337

259-
- 将最右侧元素加入当前子数组乘积 `window_product` 中。
260338

261-
- 如果 `window_product >= k` ,则不断右移 `left`,缩小滑动窗口长度,并更新当前乘积值 `window_product` 直到 `window_product < k`
262-
- 记录累积答案个数 += 1,向右移动 `right`,直到 `right >= len(nums)` 结束。
263-
- 输出累积答案个数。
339+
输入:nums = [1,2,3], k =0
340+
输出:0
341+
```
264342

265-
#### 4.5.4 代码
343+
#### 4.5.3 解题思路
344+
345+
##### 思路 1:滑动窗口(不定长度)
346+
347+
1. 设定两个指针:`left``right`,分别指向滑动窗口的左右边界,保证窗口内所有数的乘积 `window_product` 都小于 `k`。使用 `window_product` 记录窗口中的乘积值,使用 `count` 记录符合要求的子数组个数。
348+
2. 一开始,`left``right` 都指向 `0`
349+
3. 向右移动 `right`,将最右侧元素加入当前子数组乘积 `window_product` 中。
350+
4. 如果 `window_product >= k` ,则不断右移 `left`,缩小滑动窗口长度,并更新当前乘积值 `window_product` 直到 `window_product < k`
351+
5. 记录累积答案个数加 `1`,继续右移 `right`,直到 `right >= len(nums)` 结束。
352+
6. 输出累积答案个数。
353+
354+
##### 思路 1:代码
266355

267356
```Python
268357
class Solution:
@@ -290,6 +379,11 @@ class Solution:
290379
return count
291380
```
292381

382+
##### 思路 1:复杂度分析
383+
384+
- **时间复杂度**:$O(n)$。
385+
- **空间复杂度**:$O(1)$。
386+
293387
## 参考资料
294388

295389
- 【答案】[TCP 协议的滑动窗口具体是怎样控制流量的? - 知乎](https://www.zhihu.com/question/32255109/answer/68558623)

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /