【每日算法】长度最小的子数组
题目描述
这是 LeetCode 上的 209. 长度最小的子数组,
难度为 【困难】
给定一个含有 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
提示:
1 <= target <= 10^9
1 <= nums.length <= 10^5
1 <= nums[i] <= 10^5
暴力解法
首先最容易想到的是暴力求解,首先定义一个数组,用于记录'连续'元素累加的和,使用两层循环,
外层是参与运算的个数,连着1个数,连着2个数,连接3个数等等,内层是把连着的数累加,并找到最终的结果。
内层从后往前累加,因为后面的结果要用到前面计算的结果
以nums=[2,3,1,2,4,3]
为例
定义一个数组:sums=[0]*len(nums)
sums=[0,0,0,0,0,0]
当i=0时,表示有连着1个数字求和
j=5: sums[5]=sums[5]+nums[5]
j=4: sums[4]=sums[4]+nums[4]
...
j=0: sums[0]=sums[0]+nums[0]
sums=[2,3,1,2,4,3]
当i=1时,表示有连着2个数字求和,连着2个时,sums中只能计算到1
j=5: sums[5]=sums[5]+nums[4]
j=4: sums[4]=sums[4]+nums[3]
...
j=1: sums[1]=sums[1]+nums[0]
sums=[..,5,4,3,6,7]
当i=2时,表示有连着3个数字求和,连着3个时,sums中只能计算到2
j=5: sums[5]=sums[5]+nums[3]
j=4: sums[4]=sums[4]+nums[2]
...
j=2: sums[2]=sums[2]+nums[0]
sums=[..,...,6,5,10,9]
可以得出sums[j]=sums[j]+nums[j-i]
def minSubArrayLen(self, target, nums):
n=len(nums)
sums=[0]*n
for i in range(n):
for j in range(n-1,i-1,-1):
sums[j]=sums[j]+nums[j-i]
if sums[j]>=target:
return i+1
return 0
虽然暴力解法的能通过,但是速度着实很慢,有没有别的解法呢,我猜大概率是有的
双指针法
能不能用双指针法,左右两个指针,圈定满足条件的数据(其和 ≥ target)
的数据范围,移动右边的指针,使其和越来越大,当>=target满足条件时,用左右指针索引计算个数,然后再向右移动左指针,使其值逐渐减小,如果还是满足>=targer的条件,用左右指针索引计算个数,然后向右再移动左指针,再判断target...,一直这样判断,直到右指针到尾。
def minSubArrayLen(self, target, nums):
n=len(nums)
lo,hi=0,0#左右指针
tot,res=0,99999999#
while hi<n:
tot+=nums[hi]
hi+=1#移动右边的指针
#如果满足条件,则移动左指针,减小结果
while tot>=target:
res=min(res,hi-lo)
tot-=nums[lo]
lo+=1
return 0 if 99999999==res else res
结果很漂亮。