题目
题目传送门(点击即可)
给定一个含有 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 = 4, nums = [1,4,4]
输出:1
题解
法1:暴力法
暴力法很简单,大部分人几乎都能想到。通过两个for循环不断找出满足符合条件的子序列。这样时间复杂度为 O ( n 2 ) O(n^2) O(n2)。由于这种方法过于简单,就不在赘述。下面主要讲指双针法(也称之为滑动窗口法)。
法2:双指针法
双指针法就是通过两个指针来指示一个序列,本题中就是求和的序列。原理很简单:
- initial:起初两指针均为起点
- step1:移动右指针使两个指针范围内和大于target。
- step2:因为这个区间内和大于目标值,因此我们可以缩小该区间,即又移左指针。当区间内值小于target就需停止移动
- 不断重复step1和step2,直到右指针遍历完数组。
上述过程可能有点抽象,因此画图来具体说明,以示例1为例子。
开始
初始两指针均指向数组0号位置。
upPtr移动
upPtr移动,使得两指针范围内和大于target(7)。可以看到此时两区间范围内为数字和为8,此时停止移动。
lowPtr移动
lowPtr移动,从而缩小整个区间。移动后值缩小了
upPtr移动
lowPtr移动
lowPtr移动
upPtr移动
lowPtr移动
lowPtr移动
upPtr移动–执行完毕
上述流程对应下面的代码。java版代码如下
public static int minSubArrayLen(int target, int[] nums) {
/**
*@Description:双指针做法,两根指针范围区间即是求和区间
*/
int sum = 0;
int lowPtr = 0;
int shortestLen = nums.length+1;//这是一个取不到的值
for (int upPtr = 0; upPtr < nums.length; upPtr++) {
sum += nums[upPtr];//右指针不断移动
while (sum>=target){//和大了,可以缩小区间了
shortestLen = Math.min(shortestLen,upPtr-lowPtr+1);
sum -= nums[lowPtr++];//缩小区间
}
}
return shortestLen == nums.length+1 ? 0:shortestLen;
}
上述代码注意事项
- shortestLen 初始化值这里设置的数组长度+1,因为这是一个在例子中取不到的最大值,当然也可以用maxvalue。
- 结果返回时需要注意特殊情况,即数组内所有元素和相加仍小于target