代码:
//时间复杂度 O(N) ,空间复杂度 O(1)
class Solution {
//采用滑动窗口的方法解决
public int minSubArrayLen(int target, int[] nums) {
int numsLength=nums.length;
int minLength=Integer.MAX_VALUE;
int left=0;
int right=0;
int sum=0;
while (right<numsLength){
sum+=nums[right];
while (sum>=target){
//sum 符合要求
//以当前 left 指针指向的数的最小子数组已经找到
minLength=Math.min(minLength,right-left+1);
sum-=nums[left++];
}
//sum 不符合要求
right++;
}
if(minLength==Integer.MAX_VALUE){
minLength=0;
}
return minLength;
}
}
题解:
该题我们可以采用滑动窗口的方法来解决,对于子数组,字串的题都经常用到滑动窗口的解决方法
我们要想获得长度最小的子数组,首先就能够想到一种暴力方法,就是去获取数组中的所有子数组,再进行遍历找到符合条件且长度最小的子数组,而滑动窗口的解决方法是基于该思想实现的,但是进行了优化
我们以题目中的示例 1 作为例子,输⼊: target = 7, nums = [2,3,1,2,4,3]
1.首先我们用两个指针 L 和 R 指向下标为 0 的位置,用来进行遍历(它们两个遍历的规则不同),现在 L 和 R 指针之间便是我们此时要讨论的子数组,我们定义一个 sum 变量来表示此时子数组的长度,sum+= nums[ R ] ,此时子数组的和为 2 小于 target,所以我们需要扩大子数组
2 3 1 2 4 3
L
R
2.将 R 指针向后移一位后,子数组的总和相比于之前多了 3,sum+= nums[ R ] =5 < target,于是我们还需要将 R 指针向后移,直到子数组的总和符合条件为止
2 3 1 2 4 3
L
R
3.当 R 指针一直移动到如下位置时,L 指针和 R 指针之间子数组的总和为 2+3+1+2 > target,符合条件,于是取变量 minLength 和当前子数组长度的最小值进行保存,由于这是得到的第一个最小长度,所以 minLength 记录此时的长度4,这里有个细节,记录此时的长度以后我们还需要让 R 指针继续向右移动吗 ?答案是不需要,因为我们已经获得了以 L 指针指向的数据为开头且符合条件的长度最小的子数组,当我们让 R 继续向右移动,由于 nums 是一个正整数的数组,所以得到的子数组是一定符合条件的,但是长度增加了 1 ,而我们要的是最小的子数组长度,这里长度增加 1 是完全没有必要的,所以肯定不会是我们要获取的答案
2 3 1 2 4 3
L
R
4.以当前 L 指针为开头的最小子数组长度我们已经获取到了,所以可以让 L 指针向右移动,讨论以下一个数据为开头的最小子数组长度,sum -= nums[ L ] = 6,这里有个细节,我们需要让 R 指针回到 L 指针所在的位置进行遍历吗?答案是不需要,因为当 R 指针指向当前位置并且加上 L 指针之前指向的数据才符合要求,所以当 L 指针移动后,R指针至少要在当前位置才可能符合要求,此时 sum = 6 < target ,于是需要 R 指针向右移动扩大子数组的总和
2 3 1 2 4 3
L
R
5.接下来就是循环的操作了,当 R 指针指向 nums.length 的位置时循环结束