题目
给定一个含有 n ****个正整数的数组和一个正整数 target 。
找出该数组中满足其总和大于等于 ****target ****的长度最小的 子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度 。 如果不存在符合条件的子数组,返回 0 。
示例 1:
输入: target = 7, nums = [2,3,1,2,4,3]
输出: 2
解释: 子数组 [4,3] 是该条件下的长度最小的子数组。
题解
方式一:滑动窗口
public int minSubArrayLen(int target, int[] nums) {
int l = 0; // 左边界
int sum = 0;
int result = Integer.MAX_VALUE;
for (int r = 0; r < nums.length; r++) { // 右边界
sum += nums[r];
while (sum >= target && l <= r) {
// 满足条件时,不断缩小窗口,知道不满足条件
result = Math.min(result, r - l + 1);
sum -= nums[l++];
}
}
return result == Integer.MAX_VALUE ? 0 : result;
}
方式二:前缀和 + 二分
public int minSubArrayLen(int target, int[] nums) {
int n = nums.length;
int[] preSum = new int[n + 1];
for (int i = 0; i < n; i++) {
// 前缀和数组一定有序,所以能使用二分
preSum[i + 1] = preSum[i] + nums[i];
}
int result = Integer.MAX_VALUE;
for (int i = 0; i < n; i++) {
// 找到差值大于等于target的下标
int j = binary(preSum, preSum[i] + target);
if (j != -1) {
// 如果存在,更新结果
result = Math.min(result, j - i);
}
}
return result == Integer.MAX_VALUE ? 0 : result;
}
public int binary(int[] preSum, int target) {
int l = 0;
int r = preSum.length - 1;
int result = -1;
while (l <= r) {
int mid = l + (r - l) / 2;
if (preSum[mid] < target) {
l = mid + 1;
} else {
result = mid;
r = mid - 1;
}
}
return result;
}
总结
算法:双指针、前缀和、二分