题目描述
给定一个含有 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 <= 109
1 <= nums.length <= 105
1 <= nums[i] <= 105
进阶:
- 如果你已经实现
O(n)
时间复杂度的解法, 请尝试设计一个O(n log(n))
时间复杂度的解法。
解题思路
使用滑动窗口技术,我们可以在一个循环中解决问题,而无需多重循环。这样做的关键是维护一个窗口 [i, j)
(包括 i
,不包括 j
),这个窗口内的数值和至少为 target
。
算法步骤
-
初始化变量:
n
为数组nums
的长度。minWindow
初始化为一个大于可能的最大窗口长度的值,这里是n+1
。sum
初始化为数组的第一个元素nums[0]
。i
和j
分别作为窗口的起始和结束指针,初始值分别设为0
和1
。
-
滑动窗口遍历:
- 使用一个
while
循环,让j
从1
遍历到n
(注意这里j
允许等于n
以处理边界情况)。 - 窗口扩展或收缩:
- 如果当前窗口内元素的和
sum
大于等于target
,尝试通过移动窗口左边界i
来缩小窗口,即sum -= nums[i++]
。同时更新最小窗口长度minWindow
。 - 如果
sum
小于target
且j
未超出数组长度,扩展窗口右边界,即sum += nums[j++]
。
- 如果当前窗口内元素的和
- 使用一个
-
返回结果:
- 使用
minWindow % (n + 1)
来判断是否找到了有效的窗口。如果minWindow
仍然是初始值n+1
,说明没有找到符合条件的子数组,根据题目要求应返回0
。
- 使用
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int n = nums.size();
int minWindow = n + 1;
int sum = nums[0];
int i = 0, j = 1;
while (j <= n) {
if (sum >= target) {
if (minWindow > j - i) {
minWindow = j - i;
}
sum -= nums[i++];
} else if (j < n) {
sum += nums[j++];
} else {
break;
}
}
return minWindow % (n + 1);
}
};