1.题目描述
剑指 Offer II 008. 和大于等于 target 的最短子数组
给定一个含有 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
2.解题思路与代码
2.1 解题思路
这道题目使用双指针解答非常简单,难度在于双指针的边界如何确定。我们使用 r 表示窗口的有边界,l 表示窗口的左边界,并初始化让两个值为 0。然后开始让整个窗口在数组上面进行移动。我们以题目示例 target = 7, nums = [2,3,1,2,4,3] 为例进行图解。
首先我们需要在数组上找到比 7 大的并且最接近 7 的窗口,右边界 r 指向 nums[0],这个时候需要将 0 位置的 2 选中并统计总和,此时[l, r] 窗口内的总和为 2,小于 7 于是让右边界 r 继续移动。
r 移动到 nums[1] 窗口为 [0, 1],此时窗口内总和为 5 小于 7 依然让右边界继续移动
重复这样的步骤直到 r 指向 num[3] 时此时窗口内的总和为 8 大于 7 ,此时我们找到了第一个大于等于 7 的窗口,那么就开始从左边界开始缩小窗口。
我们让左边界开始依次缩小,直到窗口内的总和小于 7 为止。先计算一次当前窗口的大小,此时大小为 4 ,然后开始移动左边界。左边界移动一次之后发现此时窗口 [1, 3] 内的总和已经小于 7 了,那么就需要继续移动右边界,重复这一系列动作后,直到找到最小窗口为止。
2.2 代码
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int l = 0;
int r = 0;
int sum = 0;
int min = 0;
while (r < nums.length) {
// 移动右边界
sum += nums[r];
// 当窗口内总和大于等于 target 时开始统计窗口大小并移动左边界,直到窗口内总和小于 target 为止
while (sum >= target) {
min = min == 0 ? r - l + 1 : Math.min(min, r - l + 1);
sum -= nums[l++];
}
r++;
}
return min;
}
}
2.3 测试结果
通过测试
3.总结
- 使用滑动窗口进行解答
- 当右边界移动到第一个大于等于 target 的窗口时,计算窗口大小,然后开始缩小左边界直到窗口内总和小于 target 为止