题目链接:209. 长度最小的子数组 - 力扣(LeetCode)
给定一个含有 n
个正整数的数组和一个正整数 target
。
找出该数组中满足其和 ≥ target
的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr]
,并返回其长度。如果不存在符合条件的子数组,返回 0
。
一 超时的做法
思路见注释,滑动窗口的思想是正确的,但是中间的判断方式太复杂
class Solution:
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
# 滑动窗口来解决这个问题
# 窗口前端,窗口后端,最小长度
# 当窗口中所有数的总和 >= 目标值:与最小长度比较更新最小长度
# 从前端开始剔除值直至小于目标值。
# 当窗口中的数小于目标值,后端向后移动直至大于等于目标值
# 当第一次找到时(前端为0)直接替换最小长度的值,不然最小长度一直是0
head = 0
tail = 0
min_length = 0
n = len(nums)
while tail<n:
if sum(nums[head:tail+1]) >= target:
while sum(nums[head:tail+1]) >= target:
if head == 0:min_length = tail - head + 1
else:
min_length = min(tail-head+1, min_length)
head+=1
else:
tail+=1
return min_length
二 合格的做法
思路没变,判断条件改变,选用一个变量total来表示滑动窗口中的总值,而不是使用sum()
节省了大量时间,最小长度 的初始值也做出了变化,减少了判断次数。
class Solution:
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
# 滑动窗口来解决这个问题
# 窗口前端,窗口后端,最小长度
# 当窗口中所有数的总和 >= 目标值:与最小长度比较更新最小长度
# 从前端开始剔除值直至小于目标值。
# 当窗口中的数小于目标值,后端向后移动直至大于等于目标值
# 开始时设置 最小值为列表长度 +1(往后出现的任何一种符合的情况都可以跟他替换)
# 到最后如果发现最小长度仍为 列表长度+1,证明不存在符合的情况
head = 0
tail = 0
total = 0
n = len(nums)
min_length = n + 1
while tail<n:
total += nums[tail]
while total >= target:
min_length = min(tail - head + 1, min_length)
total -= nums[head]
head += 1
tail += 1
return 0 if min_length == n+1 else min_length
三 总结
滑动窗口内的元素数量大时,不要使用聚合函数进行条件的判断
而是选择变量暂存结果,能节省大量聚合函数的执行时间