1. 题目
给定一个含有 n
个正整数的数组和一个正整数 target
。
找出该数组中满足其总和大于等于 target
的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr]
,并返回其长度。如果不存在符合条件的子数组,返回 0
。
2. 解题思路
(1) 直觉上是一个寻找子数组的题目。任何一个子数组都可以表示为左右端点,只要左右端点内的数值满足条件,就是正确的子数组。而找到长度最小的连续数组,就是一个不断更新最小长度过程。遍历完数组时,此时最新的长度,就是最小长度。
(2)如何去遍历数组?
可以固定子数组的长度,遍历数组。不满足条件则增加子数组长度,直到满足总和大于target。此时子数组长度是最小的。时间复杂度是
也可以固定子数组的左区间,增加子数组长度,直到满足总和大于target,记录此时的长度。但此时的长度不能保证是最小的。需要更新左区间,重复以上操作,比较新的长度与记录的长度,以此更新最小值。当数组被遍历一遍时,所有可能的子数组已经被比较完毕。时间复杂度是,也就是。
3. 代码
(1)两个for循环嵌套 (leetcode中判定为超时)。
(2)滑动窗口:
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
// 滑动窗口法
// 起点 终点
int i = 0;
int sum = 0;
int sublen = 0;
int res = INT32_MAX;
for (int j = 0; j < nums.size(); j++ ) {
sum += nums[j];
while (sum >= target) {
// 记录子数组长度
sublen = j - i + 1;
// 比较最短纪录和目前子数组长度
res = sublen < res ? sublen : res;
// 移动起点边界
sum -= nums[i++];
}
}
return res == INT32_MAX ? 0 : res;
}
};
tips
1. 更新最小值
更新最小值时,需给最小值初始化为一个最大的值。因此,在开始记录的时候,不论最小值为多少,都能够成功的记录。如果此时最小值初始化为0,任何大于等于1的最小值都无法被记录,这是违背原意的。
同样的道理,如果是更新最大值,最大值应该更新为一个比可行解下限更小的值。
2. 三元运算符
condition ? expression1 : expression2
如果条件满足,为表达式1,否则为表达式2。