Given an array of positive integers nums
and a positive integer target
, return the minimal length of a contiguous subarray [numsl, numsl+1, ..., numsr-1, numsr]
of which the sum is greater than or equal to target
. If there is no such subarray, return 0
instead.
Example 1:
Input: target = 7, nums = [2,3,1,2,4,3] Output: 2 Explanation: The subarray [4,3] has the minimal length under the problem constraint.
Example 2:
Input: target = 4, nums = [1,4,4] Output: 1
Example 3:
Input: target = 11, nums = [1,1,1,1,1,1,1,1] Output: 0
Constraints:
1 <= target <= 109
1 <= nums.length <= 105
1 <= nums[i] <= 105
Follow up: If you have figured out the O(n)
solution, try coding another solution of which the time complexity is O(n log(n))
.
题目大意是从一个数组中找到一个最小长度的子数组,使得子数组的和大于等于目标数。一个数组最短长度子数组就是只含一个元素,最长子数组就是数组本身。因此本题的暴力解法就是从长度为1到长度为n的所有子数组从短到长挨个求和,遇到的第一个和大于等于目标数的子数组就是满足条件的最短子数组。
很明显可以用二分查找法来提高查找效率,就是取一个中间长度mid,判断所有长度为mid的子数组是否有和大于等于目标数,如果有则继续查找更短长度的即[left, mid - 1]区间,如没有则继续查找更长长度的即[mid + 1, right]区间。
另外关于子数组求和需要引入数组前缀和的概念,即把每一个元素到第一个元素的和存到一个数组里,有了前缀和数组就可以立即求得任意长度的子数组的和。
class Solution:
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
n = len(nums)
preSum = [0] * (n + 1)
for i in range(n):
if nums[i] >= target:
return 1
preSum[i + 1] = preSum[i] + nums[i]
if preSum[-1] < target:
return 0
l, r = 1, n
while l <= r:
mid = l + (r - l) // 2
flag = False
for i in range(n - mid +1):
if preSum[i + mid] - preSum[i] >= target:
flag = True
break
if flag:
r = mid - 1
else:
l = mid + 1
return l