leetcode209. 长度最小的子数组
给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的连续子数组,并返回其长度。如果不存在符合条件的连续子数组,返回 0。
示例:
输入: s = 7, nums = [2,3,1,2,4,3]
输出: 2
解释: 子数组 [4,3] 是该条件下的长度最小的连续子数组。
方法:双指针滑窗
思路:
因为是子数组,本题可以想到的一种方法是使用双指针维护一个窗口,来求得窗口内的和,进而找到最短长度的子数组。
我刚开始想到的是,左右指针分别在nums开头和结尾,也就是说刚开始的窗口是整个数组,如果小于s,那么肯定不对,之后不断的缩小窗口,判断左右指针指向的元素,抛弃小的那个元素;但是如果左右指针指向的元素相同,那么不好判断,可能需要进一步判断两个指针内层的元素,才能找到丢弃哪一个对整个窗口的影响较小,代码不好写,计算量也大;而且刚开始求整个数组的和,已经O(N)了,算是额外的计算量。
正确的方法是这样的:刚开始两个指针都在开头位置,相当于开始维护的窗口是只有第一个元素的子数组,如果小于s,就right开始向右扩张,直到窗口内大于等于s,这时,更新ans长度,然后将左指针left开始向右缩,直到窗口和小于s,缩的同时也更新ans;小于了之后,继续重复上述过程,right向右扩张…left向右缩…直到遍历完数组。
最后返回ans即可,初始将ans设为无穷大,如果最后ans还是无穷大,说明没有符合条件的子数组,返回0。
最坏的情况左右指针都遍历了一遍,O(2N),渐进时间复杂度为O(N)。空间复杂度为O(1)。
代码:
class Solution:
def minSubArrayLen(self, s: int, nums: List[int]) -> int:
n = len(nums)
if not n:
return 0
#ans为满足条件的最小长度
ans = float('inf')
#初始化左右指针,刚开始维护的窗口是nums的第一个元素
left = right = 0
#初始化temp,temp变量维护当前窗口的元素和
temp = 0
while right < n:
temp += nums[right]
#已经大于等于s的话,缩小窗口,更新ans
while temp >= s:
ans = min(ans,right-left+1)
temp -= nums[left]
left += 1
#temp小于s的话,扩大窗口
right += 1
return ans if ans != float('inf') else 0
结果: