模版题-数组专题-长度最小的子数组 ( 滑动窗口 )

管理员
暴力解法 - 超时 ```python class Solution: # 找出该数组中满足其总和大于等于 target 的长度最小的 子数组 # 1 <= target <= 10e9 # 1 <= nums.length <= 10e5 # 1 <= nums[i] <= 10e4 # 子数组 是数组中连续的 非空 元素序列。 def minSubArrayLen(self, target: int, nums: List[int]) -> int: MAX = 100_000 ans = MAX s = 0 n = len( nums ) for i in range( n ): s = 0 for j in range( i, n ): s = s + nums[ j ] if s >= target: if ans > j - i + 1: ans = j - i + 1 break return 0 if ans == MAX else ans ``` --- **滑动窗口** **滑动窗口,就是不断的调节子序列的起始位置和终止位置,从而得出想要的结果。** 在暴力解法中, - 一个for循环滑动窗口的起始位置, - 一个for循环为滑动窗口的终止位置, 用两个for循环 完成了一个不断搜索区间的过程。 现在:滑动窗口如何用一个for循环来完成这个操作? ``` 如果用一个for循环,应该表示滑动窗口的起始位置,还是终止位置。 实现滑动窗口,主要确定如下三点: - 窗口内是什么? - 如何移动窗口的起始位置? - 如何移动窗口的结束位置? 窗口就是满足 其和大于等于target 的长度最小的连续子数组。 窗口的起始位置如何移动:如果当前窗口的值大于等于target,窗口要向前移动了(即缩小窗口)。 窗口的结束位置如何移动:窗口的结束位置就是遍历数组的指针,也就是for循环里的索引。 ``` **代码** ```python class Solution: # 找出该数组中满足其总和大于等于 target 的长度最小的 子数组 # 1 <= target <= 10e9 # 1 <= nums.length <= 10e5 # 1 <= nums[i] <= 10e4 # 子数组 是数组中连续的 非空 元素序列。 def minSubArrayLen(self, target: int, nums: List[int]) -> int: n = len( nums ) ans = MAX = 100_010 # 滑动窗口内容:和大于等于target的长度最小的连续子数组。 w_len = 0 # 滑动窗口长度 w_sum = 0 # 滑动窗口总和 start = 0 for end in range( n ): w_sum += nums[ end ] # 调整滑动窗口的大小 并更新最小长度 while w_sum >= target: w_len = end - start + 1 if w_len < ans: ans = w_len w_sum -= nums[ start ] start += 1 # !important:变化窗口的起始位置 return 0 if ans == MAX else ans ``` 滑动窗口的精妙之处在于根据当前子序列和大小的情况,不断调节子序列的起始位置。从而将O(n^2)降为O(n) **时间复杂度分析** ``` for里放一个while就以为是O(n^2),其实不然: 主要是看每一个元素被操作的次数,每个元素在滑动窗后进来操作一次,出去操作一次, 每个元素都是被操作两次,所以时间复杂度是 2 × n 也就是O(n)。 ``` --- **滑动窗口模版** ``` start, end # 变化窗口终止位置 for end: # 根据窗口内容调整窗口起始位置 while( 判断条件 ): # 判断是否修改起始位置 judgeChangeStart() # 按要求返回值 return 结果值 ```
评论 0

发表评论 取消回复

Shift+Enter 换行  ·  Enter 发送
还没有评论,来发表第一条吧