思路
首先我们可以简单粗暴的求解,遍历数组,从每次遍历数组时依次向后累加元素,再与target比较。
暴力求解
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int j = 0;
int size = nums.size();
int ret = INT32_MAX;//INT32_MAX表示int类型的最大值
//同理INT32_MIN表示int类型的最小值
for (int i = 0; i < size; ++i)
{
int sum = 0;
for (int j = i; j < size; ++j)
{
sum += nums[j];
if (sum >= target)
{
ret = j - i + 1 < ret ? j - i + 1 : ret;//比原ret小才替换
}
}
}
return ret == INT32_MAX ? 0 : ret;
//判断ret是否改变,若ret没改变说符合条件的子数组,要返回0
}
};
解析
以下图为例
i=0时,2+3+1+4=10>target,此时j=3,j-i+1=4对应该连续数组的长度,后面在依次用i遍历,找出最短的数组大于target的数组。
此代码的空间复杂度为O(n^2),空间复杂度为O(1),由于时间复杂度太高,所以leetcode上跑不过去。
滑动窗口
暴力求解中,我们使用了循环累加的方法,而滑动窗口的主要思想就是通过不断调节左右数组的边界,来找到其合适的位置,通过循环来控制窗口的右边界,再通过一个while来调整窗口的左边界。
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int size = nums.size();
int ret = INT32_MAX;
int left = 0;
int sum = 0;
for (int right = 0; right < size; ++right)
{
sum += nums[right];
while (sum >= target)
{
ret = right - left + 1 < ret ? right - left + 1 : ret;
sum -= nums[left++];
}
}
return ret == INT32_MAX ? 0 : ret;
}
};
解析
仍然以上图为例,我们不断调整left和right的边界,就像是在移动这个红色的窗口一样。
起始位置left=0,循环过程中当right=3时,sum=8>target,记录下此时子数组的长度,这时候我们就开始要“微操”了,我们尝试让sum减去nums[0]看sum是否仍然比target大,若大于或等于target正好更新子数组的长度,若比target小则开始扩展右窗口(即继续for循环)。
此时时间复杂度为O(n),空间复杂度为O(1)。