文章目录
- 题目链接:
- 题目描述:
- 解法
- C++ 算法代码:
- 图解
题目链接:
209. 长度最小的子数组
题目描述:
解法
解法一:暴力求解(会超时)
暴力枚举出所有子数组的和。
查找子数组n2,求和n
一共O(n3)
优化:
求和的时候,可以把上次求和的结果存起来,往后加一位的时候直接把那一位的值加到上次的和里面。
解法二:滑动窗口O(n)
利用
单调性
,使用同向双指针来优化。(同向双指针也叫滑动窗口)
left=0,right=0
,标记窗口的左右端点- 进窗口
- 判断,更新结果🌟,出窗口
2-3
步是一直循环的
例如:nums=[2,3,1,2,4,3]
移动到sum>=target
然后left
右移,因为如果left
不动,right
继续往后得到的都不是长度最小的数组了。
sum<target,right
右移
依次类推
然后窗口的长度可以用len
来记录,每次判断后先更新结果,然后出窗口。
C++ 算法代码:
解法一:暴力求解(会超时)
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
// 记录结果
int ret = INT_MAX;
int n = nums.size();
// 枚举出所有满足和大于等于 target 的子数组[start, end
// 由于是取到最小,因此枚举的过程中要尽量让数组的长度最小
// 枚举开始位置
for (int start = 0; start < n; start++)
{
int sum = 0; // 记录从这个位置开始的连续数组的和
// 寻找结束位置
for (int end = start; end < n; end++)
{
sum += nums[end]; // 将当前位置加上
if (sum >= target) // 当这段区间内的和满足条件时
{
// 更新结果,start 开头的最短区间已经找到
ret = min(ret, end - start + 1);
break;
}
}
}
// 返回最后结果
return ret == INT_MAX ? 0 : ret;
}
};
解法二:
class Solution
{
public:
int minSubArrayLen(int target, vector<int>& nums)
{
int n = nums.size(), sum = 0, len = INT_MAX;
for(int left = 0, right = 0; right < n; right++)
{
sum += nums[right]; // 进窗口
while(sum >= target) // 判断
{
len = min(len, right - left + 1); // 更新结果
sum -= nums[left++]; // 出窗口
}
}
return len == INT_MAX ? 0 : len;
}
};
图解
nums=[2,3,1,2,4,3]
target=7
n=6,sum=0,right=0,left=0,target=7,len=INT_MAX(确保min使用的时候不会把len的初始值当作最小值)
-
sum=2
sum<target,right++
-
sum=5
sum<target,right++
-
sum=5
sum<target,right++
-
sum=8
sum>target,len=4
sum=sum-nums[left++]=8-2=6
-
sum=6
sum<target,right++
-
sum=10
sum>target,len=4
sum=sum-nums[left++]=10-3=7
-
sum=7
sum=target,len=3
sum=sum-nums[left++]=7-1=6
-
sum=6
sum<target,right++
-
sum=9
sum>target,len=3
sum=sum-nums[left++]=9-2=7
-
sum=7
sum=target,len=2
sum=sum-nums[left++]=7-4=3
-
sum=3
sum<target,right++
-
跳出
for
循环,return len == INT_MAX ? 0 : len;
,这里返回2
-
程序结束