209. Minimum Size Subarray Sum
题目描述
Given an array of n positive integers and a positive integer s, find the minimal length of a contiguous subarray of which the sum ≥ s. If there isn't one, return 0 instead.
For example, given the array [2,3,1,2,4,3]
and s = 7
, the subarray [4,3]
has the minimal length under the problem constraint.
More practice:
If you have figured out the O(n) solution, try coding another solution of which the time complexity is O(n log n).
分析
O(n)解法:
要求在数组中寻找含有最少元素的连续子数组,满足其和为s。
- 使用left和right两个指针,分别作为欲寻找子数组的两端,初始化时,均指向第一个元素;
- 然后将数组中的元素依次加入结果数组,记录和,
- 若和total大于等于s,或者 right 达到数组末尾,此时我们更新最短距离,并且将 left 像右移一位,然后在 sum 中减去移去的值。
- 若和total小于s,则右端点左移。
- 然后重复上面的步骤,直到 right 到达末尾,且 left 到达临界位置,即要么到达边界,要么再往右移动,和就会小于给定值。
class Solution(object):
def minSubArrayLen(self, s, nums):
"""
:type s: int
:type nums: List[int]
:rtype: int
"""
# O(n)解法
if not s or nums == []:
return 0
total = 0
left = 0
res = len(nums)+1
# 右指针从左向右依次遍历数组中的元素
for right,n in enumerate(nums):
total += n
# 循环右移左指针
# 并且需要符合和大于s,左指针小于右指针
while total>=s and left<=right:
res = min(res, right-left+1)
total -= nums[left]
left += 1
# 注意返回值的过滤方式
return res if res<=len(nums) else 0
O(nlogn)解法:
采用分治法,在区间中寻找适当的可以构成答案的子区间。
1. 每两个相邻元素求和,结果保存在较大索引中,最终每个索引中存储的是从头到该索引的所有数字之和;
2. 当当前的求和大于目标值时,需要更新左起点;调用二分查找的子函数来更新。
3. 更新最小距离,并按照判断条件进行返回。
class Solution(object):
def minSubArrayLen(self, s, nums):
"""
:type s: int
:type nums: List[int]
:rtype: int
"""
result=len(nums)+1
for idx, n in enumerate(nums[1:], 1):
nums[idx] = nums[idx - 1] + n #每两个相邻值求和,‘和’保存在较大索引的数里,nums[idx]为nums数组前idx+1个数的和
left=0
for right,n in enumerate(nums):
if n >= s: #当前索引下的求和大于欲寻找的元素和,则需要更新起点(左端点)
left=self.find_left(left,right,nums,s,n)
result=min(result,right-left+1)
return result if result<=len(nums) else 0
#分治法/二分搜索
def find_left(self,left,right,nums,s,n):
while left<right: #终止条件:left>=right
mid=(left+right)//2 #寻找区间的中点
if n-nums[mid] >= s: #若当前和-区间前半部分的和仍大于欲寻找的和,欲寻找的左端点在区间的右半部分
left=mid+1 #更新起点(左端点)
else: #若当前和-区间前半部分的和小于欲寻找的和,欲寻找的左端点在区间的左半部分
right=mid #更新终点(右端点)
return left #返回起点