文章目录
引言
滑动窗口也是一种双指针(索引)的方式,顾名思义。使用双索引来表示一个滑动的窗口。
一、LeetCode—209
209.Minimum Size Subarray Sum
给定一个整型数组和一个数字s,找到数组中最短的一个连续子数组,使得连续子数组的数字和sum>=s,返回这个最短的连续子数组的长度值
给定数组[2,3,1,2,4,3],s=7
输出[4,3],返回2
- 连续子数组
- 如果没有解怎么办?返回0
- 有多个解的话该怎么办?返回一个还是多个?
解法一:暴力法
遍历所有连续子数组,计算其和sum(O(n)),验证sum>=s。
时间复杂度O(n^3)
如果将计算所有连续数组的sum转变为cumsum(提前计算好),则优化后的暴力解法的时间复杂度为O(n^2)
很明显,遍历计算所有连续子数组的过程中存在着大量的重复计算。
解法二:滑动窗口
两个指针left和right,left代表滑窗的左边框,right代表滑窗的右边框。两者分别向右滑动,前者能使窗口之间的和减小,后者能使窗口之间的和增大。开始时两者重合,窗口的和就是重合点所在的数。
- right向右移动,使和变大。当恰好大于等于s时,记录滑窗所包括的子数组的长度ans,若ans已有数值,需判断新值是否小于旧值,若是,则更新ans
- left向右滑动,判断是否仍大于等于s
- 若是,重复步骤2.若否,更新ans并转步骤1。直到右边框到达最右边。
通俗点来说,即没有大于s时,right往右移动,大于s时,left向右移动
class Solution:
def findminarray(self, nums, s):
return self.minSubArrayLen(nums, s)
def minSubArrayLen(self, nums, s):
#
left, right, ans = 0, 0, len(nums) + 1
# 创建一个累加和数组,将求和的时间复杂度从O(n)变为O(1)
cumsum = []
for num in nums:
if not cumsum:
cumsum.append(num)
else:
cumsum.append(cumsum[-1] + num)
array_dict = {}
while left < len(nums) and right < len(nums):
if cumsum[right] - cumsum[left] + nums[left] < s:
right += 1
else:
if right + 1 - left < ans:
ans = right + 1 - left # 更新数组长度
array_dict[ans] = nums[left:right + 1]
left += 1
# 跳出循环的条件是right = len(nums)
if ans != len(nums) + 1:
return ans, array_dict[ans]
else:
return 0
def main():
nums = [2, 3, 1, 2, 4, 3]
s = 7
ss = Solution()
solution = ss.findminarray(nums, s)
print('返回连续子数组及最小长度:', solution)
if __name__ == '__main__':
main()