给定一个含有 n 个正整数的数组和一个正整数 target 。
找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
示例 1:
输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。
示例 2:
输入:target = 4, nums = [1,4,4]
输出:1
示例 3:
输入:target = 11, nums = [1,1,1,1,1,1,1,1]
输出:0
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/2VG8Kg
【python快速版】算法思想:前缀和数组 + 二分法求最近下标
class Solution:
#二分法
def bisearch(self ,ls :List[int] ,target : int) -> int:
i = 0
j = len(ls)
while i < j:
mid = (i+j) >>1
if ls[mid] < target: i = mid +1
else: j = mid
return i
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
n = len(nums)
#方法一:使用前缀和 二分查找
sums = [0] #存放前缀和数组
#计算前缀和数组
for el in nums:
sums.append(sums[-1]+el)
#保存最小长度
minlen = n+1
#遍历前缀和数组
for i in range(1,n+1):
findnum = target + sums[i-1] #查找离第一个元素最近的目标值 >= target ,
#这里为什么加sums[i-1]? 因为目标元素的前缀和包含当前元素的前缀和,这里需要减掉
#使用二分法,找到目标元素
# findnumIndex = bisect.bisect_left(sums,findnum) #python内置二分查找方法
findnumIndex = self.bisearch(sums,findnum)
if findnumIndex != len(sums): #当找到的下标不是sum的长度,说明找到
minlen = min(minlen,(findnumIndex-i+1))
return 0 if minlen == n+1 else minlen
时间复杂度:O(nlogn) ;空间复杂度:O(n)
方法二:滑动窗口
算法思想:使用双指针作为可变大小的滑动窗口,从左至右滑动
class Solution:
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
n = len(nums)
#初始化两个指针 start , end
start = end = 0
#初始记录最小长度 , 滑窗元素和
minlen = n+1
su = 0
#当尾指针小于n时,循环
while end < n:
#当滑窗和<target时,end指针右移, >target时 ,start指针右移, 过程都要记录minlen
#先将end指针后移
su += nums[end]
while su >= target:
#当su>=target时,更新minlen
minlen = min(minlen,end-start+1)
#将start指针右移
su -= nums[start]
start += 1
end +=1
return 0 if minlen == n+1 else minlen
时间复杂度:O(n),其中 nn 是数组的长度。指针 start 和 end 最多各移动 n 次。
空间复杂度:O(1)。