题目描述
Given an array of positive integers nums
and a positive integer target
, return the minimal length of a subarray whose sum is greater than or equal to target
. If there is no such subarray, return 0
instead.
Example 1:
1 | Input: target = 7, nums = [2,3,1,2,4,3] |
Example 2:
1 | Input: target = 4, nums = [1,4,4] |
Example 3:
1 | Input: target = 11, nums = [1,1,1,1,1,1,1,1] |
Constraints:
1 <= target <= 10^9
1 <= nums.length <= 10^5
1 <= nums[i] <= 10^4
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))
.
解题方法
双指针
思路解析:
- 滑动窗口:使用两个指针
left
和right
来维护一个窗口,right
用来扩展窗口,left
用来缩小窗口。 - 窗口内求和:随着
right
的移动,我们将元素加入窗口,并计算窗口内的和。当窗口内的和大于等于target
时,尝试移动left
来缩小窗口,并更新最小长度。 - 不断更新最小长度:每次找到满足条件的窗口后,记录该窗口的长度,并继续尝试找到更短的窗口。
具体步骤:
- 初始化:
left
指针设为 0,right
指针从 0 开始,sum
初始化为 0,min_length
初始化为正无穷大。 - 扩展窗口:遍历数组,每次将
nums[right]
加到sum
中。 - 缩小窗口:当
sum
大于等于target
时,更新min_length
为right - left + 1
,并尝试通过移动left
来缩小窗口,同时减少sum
的值。 - 重复步骤 2 和 3,直到遍历完整个数组。
- 最后,如果
min_length
仍为正无穷大,说明没有找到符合条件的子数组,返回 0;否则,返回min_length
。
1 | class Solution: |
时间复杂度:$O(n)$
空间复杂度:$O(1)$
二分查找
使用二分查找可以将问题的时间复杂度提升到 O(n log n)
。这种方法基于前缀和(Prefix Sum)与二分查找的结合。
思路解析:
- 前缀和数组:
- 首先,构建一个前缀和数组
prefix_sums
,其中prefix_sums[i]
表示数组nums
前i
个元素的和。即prefix_sums[i] = nums[0] + nums[1] + ... + nums[i-1]
。 - 因此,任何子数组
nums[i...j]
的和可以表示为prefix_sums[j+1] - prefix_sums[i]
。
- 首先,构建一个前缀和数组
- 二分查找:
- 对于每一个起点
i
,我们希望找到最小的j
使得prefix_sums[j+1] - prefix_sums[i] >= target
。这等价于在prefix_sums
中找到最小的j
,使得prefix_sums[j+1] >= prefix_sums[i] + target
。 - 通过二分查找,可以在
prefix_sums
数组中快速找到这个j
。
- 对于每一个起点
- 更新最小长度:
- 对每一个起点
i
,如果找到了满足条件的j
,我们更新最小子数组长度为j - i + 1
。
- 对每一个起点
具体步骤:
- 构建前缀和数组
prefix_sums
,长度为n + 1
,其中prefix_sums[0] = 0
。 - 遍历数组
nums
的每一个起点i
,计算当前需要查找的目标和target_sum = prefix_sums[i] + target
。 - 使用二分查找在
prefix_sums
中查找最小的j
使得prefix_sums[j] >= target_sum
。 - 更新最小子数组长度为
j - i
,如果找到了符合条件的j
。 - 最后返回最小子数组长度,如果没有找到则返回 0。
1 | class Solution: |
时间复杂度:$O(nlogn)$
空间复杂度:$O(n)$