一 读懂题目
二. 分析,推导解法,产生思路。
1 n 滑动窗口: 先右指针找到满足条件的连续子数组后,再移动左指针,直到未出现满足条件的连续子数组,再移动右指针;注意左指针移动时用while并判断是否存在更小的连续子组;
2 nlogn 前缀和+二分查找:
注意前缀和的第一个为0;二分查找条件与边界设置l<r & if大则r=mid & if小l=mid+1;
3 n*n 暴力搜索:双循环;注意if判断的位置,才能判断出不同的子组和;
三 代码实现
class Solution(object):
def minSubArrayLen(self, target, nums):
"""
:type target: int
:type nums: List[int]
:rtype: int
"""
# 1 滑动窗口 n
right = 0
left = 0
temp_sum = 0
nums_len = len(nums)
min_len = nums_len+1
while right < nums_len:
temp_sum += nums[right]
# print(left, right, temp_sum, min_len)
# 当右指针找到满足条件的连续子数组后,移动左指针,直到未出现满足条件的连续子数组,再移动右指针
while temp_sum >= target : # 重点为while
# 判断是否为长度最小的连续子数组
min_len = min(min_len, right-left+1)
temp_sum -= nums[left]
left += 1
right += 1
return 0 if min_len == nums_len+1 else min_len
# 复杂化了:检验滑动窗口中是否存在更小子组是正确的,但代码太复杂;
# 思路错误:没有必要维持较大的窗口,再找滑动窗口中是否存在更小子组,因为找的是最小子组
# def checksub(l,r, min_len, cur_len,cur_sum):
# # 当新增一个数字后,子组大于target时,用于检验滑动窗口内是否存在更小的子组大于target
# while l <= r:
# if cur_sum >= target: # 存在更小的子组
# if cur_len < min_len:
# min_len = cur_len
# cur_sum = cur_sum-nums[l]
# cur_len = cur_len-1
# l = l+1
# return min_len
# l,r = 0,0 # 初始化子组开始,结束指针
# cur_sum = nums[r]
# min_len, cur_len = float("inf"), 1 # 子组长度
# while True:
# if cur_sum >= target: # 当前子数组和与target长度判断
# # 若子数组和大于target,则比较最小子组长度
# if cur_len < min_len:
# # 若当前子组长度小于最小子组长度,则记录最新最小子组长度,并减去开始指针对应整数且更新开始指针
# min_len = cur_len
# cur_sum = cur_sum-nums[l]
# cur_len = cur_len -1
# l = l+1
# # 判断子组是否存在更小的子组
# # print(min_len)
# min_len = checksub(l,r,min_len,cur_len,cur_sum) # 考察哪些参数可以不传过去
# # print(min_len,submin_len)
# if r == len(nums)-1:
# break
# # r后移及操作
# r = r+1
# cur_sum = cur_sum + nums[r]
# cur_len = cur_len + 1
# if min_len == float("inf"):
# return 0
# return min_len
# 测试用例:18/21
# 报错用例:上千的数据量的用例无法通过; 报错原因:超出时间限制;由于每次都要遍历多次子组
# l,r = 0,-1 # 初始化子组开始,结束指针
# cur_sum = 0
# min_len, cur_len = float("inf"), 0 # 子组长度
# end_flag = True
# while l < len(nums): # 遍历数组
# print(l,r,min_len, cur_len,cur_sum)
# if r == len(nums)-1: end_flag = False# r移到最右边了
# if r < len(nums)-1 and end_flag:
# r = r+1 #若r未移动到末尾则cur_sum加上结束整数且cur_len加1,r移动
# cur_sum = cur_sum + nums[r]
# cur_len = cur_len + 1
# else: #若r移动到末尾则cur_sum减去开始整数且cur_len减1,l移动
# cur_sum = cur_sum-nums[l]
# cur_len = cur_len-1
# l = l+1
# if cur_sum >= target: # 当前子数组和与target长度判断
# # 若子数组和大于target,则比较最小子组长度
# if cur_len < min_len:
# # 若当前子组长度小于最小子组长度,则记录最新最小子组长度,并减去开始指针对应整数且更新开始指针
# min_len = cur_len
# if end_flag: # 若r移到最右边了,则不能重复移动l
# cur_sum = cur_sum-nums[l]
# cur_len = cur_len -1
# l = l+1
# if min_len == float("inf"):
# return 0
# return min_len
# 之前的思路;滑动窗口来遍历子组;
# 1) 均从下标0开始,固定l,移动r,直到找到第一个符合条件的子组;再移动一位l且移动一位r即改变窗口;
# 2)重复上面的过程,直到r到len-1,再仅移动l;
# 测试用例:16/21
# 报错用例:[5,1,3,5,10,7,4,9,2,8] 报错原因:因为10比较大;未考虑到新增加一个数字后,前面的整个子组可能有符合条件的更小子组;
class Solution(object):
def minSubArrayLen(self, target, nums):
"""
:type target: int
:type nums: List[int]
:rtype: int
"""
# 2 前缀和 + 二分查找 nlogn
min_len = len(nums)+1
sums = [0]
sum_t = 0
for i in range(len(nums)): # 计算并保留前缀和(第一项为0)
sum_t += nums[i]
sums.append(sum_t)
# 二分查找得到大于或等于 i 的最小下标mid
for i in range(len(nums)+1):
l,r = 0, len(nums)+1
while(l<r):
mid = (l+r)/2
if sums[mid]-sums[i] >= target: # 找到满足条件的子组
if min_len > mid-i:
min_len = mid-i
r = mid
else:
l = mid +1
return 0 if min_len == len(nums)+1 else min_len
class Solution(object):
def minSubArrayLen(self, target, nums):
"""
:type target: int
:type nums: List[int]
:rtype: int
"""
# n*n 的做法:暴力枚举法
if not nums:
return 0
n = len(nums)
min_len = n+1
for i in range(n):
cur_sum = 0
for j in range(i,n): # 计算字串[i,n]之和
cur_sum += nums[j]
if cur_sum >= target: # 重点为在每次加法后判断,这样才能验证每个字串
if min_len > j-i+1 :
min_len = j-i+1
return 0 if min_len == n+1 else min_len
# 测试用例:18/21
# 报错用例:上千的数据量的用例无法通过; 报错原因:python超出时间限制;由于每次都要遍历多次子组