文章目录
- 一、题目
- 二、解析
- 1、暴力算法
- (1)纯暴力
- (2)前缀和 + 循环
- 2、滑动窗口
一、题目
209. 长度最小的子数组
给定一个含有
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
二、解析
1、暴力算法
(1)纯暴力
纯暴力的话,就是用两个循环变量,代表一个区间的左端点和右端点,然后再用一个指针去循环这个区间得到这个区间的区间和。最终得到最小的长度区间。时间复杂度:O(n³)
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
// 记录满足条件的区间最小长度
int len = INT_MAX;
// 用两个循环得到这个nums的所有子区间
for (int l = 0; l < nums.size(); l++)
{
for (int r = l; r < nums.size(); r++)
{
int sum = 0;
// 获得区间和
for (int i = l; i <= r; i++)
sum += nums[i];
// 寻找满足条件的区间
if (sum >= target) len = min(len, r - l + 1);
}
}
// 返回答案
return len == INT_MAX ? 0 : len;
}
};
(2)前缀和 + 循环
我们通过优化掉两个循环中的获取区间和的循环,降低了一层循环。时间复杂度:O(n²)
我们在双重循环之前先求出该数组的前缀和,这样的话获得区间和的操作就是O(1)
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
// 前缀和
vector<int> s(nums.size(), 0);
s[0] = nums[0];
for (int i = 1; i < nums.size(); i++)
s[i] = s[i - 1] + nums[i];
// 记录满足条件的区间最小长度
int len = INT_MAX;
// 用两个循环得到这个nums的所有子区间
for (int l = 0; l < nums.size(); l++)
{
for (int r = l; r < nums.size(); r++)
{
// 获得区间和
// 如果s是从下标0开始存储的话:区间和sum = s[r] - s[l] + nums[l]
// 如果s是从下标1开始存储的话:区间和sum = s[r] - s[l - 1]
// 上述的结论可以自行体会
int sum = s[r] - s[l] + nums[l];
// 寻找满足条件的区间
if (sum >= target) len = min(len, r - l + 1);
}
}
// 返回答案
return len == INT_MAX ? 0 : len;
}
};
2、滑动窗口
根据上面的步骤,我们真的需要每次都需要j从i的位置开始遍历吗?
其实是不需要的,因为当区间和大于等于target的时候,我们将左边界向右移动,这时该区间和一定小于之前,我们只需要继续往右移动。
时间复杂度:O(n)
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
// 定义区间边界
int l = 0, r = 0, n = nums.size();
int sum = 0;
int len = INT_MAX;
// 持续更新右边界
while (r < n) {
// 进入窗口
sum += nums[r++];
// 判断,是否需要滑出窗口
while (sum >= target) {
len = min(len, r - l);
sum -= nums[l++];
}
}
// 更新
if (len == INT_MAX) return 0;
return len;
}
};