开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 21 天,点击查看活动详情
题目:LeetCode
给定一个含有 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
提示:
解题思路
根据题意分析:
for循环遍历输入数组nums的元素,控制决定每次左边界(起点)
- start=0,子数组有[2 .....]的组合
- start=1,子数组有[3 .....]的组合
每次固定好左边界,循环内部利用二分查找找到第一个使得子数组的和(结束点~起点 范围) >=target 的下标位置
-
利用前缀和数组sums,子数组和 = sums[结束点+1] - sums[起点]
- 如数组[2, 3, 1, 2, 4, 3],求其[3, 1, 2]子数组的和,即前4个元素的和 - 前1个元素的和, sums[4] - sums[1]=8-2=6
-
二分方式
- 如子数组和sum<target,还可以扩大右边界,因此往右边区间二分
- 如子数组和sum>=target,往左边区间逼近
- 注意过程中可能最后都找不到满足target的子数组和,所以最后还要确认一遍子数组和,如果满足>=target就更新结果最小值
代码实现
public int minSubArrayLen(int target, int[] nums) {
int res = Integer.MAX_VALUE;
int[] sums = new int[nums.length + 1];
// sums[1] - sum of the first element
// sums[2] - sum of all first 2 elements
for (int i = 1; i < sums.length; i++) {
sums[i] = sums[i - 1] + nums[i - 1];
}
for (int start = 0; start < nums.length; start++) {
int left = start, right = nums.length - 1;
while (left < right) {
int mid = left + (right - left) / 2;
int sum = sums[mid + 1] - sums[start];
if (sum < target) {
// move to the right interval
left = mid + 1;
} else {
right = mid;
}
}
//double check - in case the target hasn't been found
if (sums[right + 1] - sums[start] >= target) {
res = Math.min(res, right - start + 1);
}
}
return res == Integer.MAX_VALUE ? 0 : res;
}
运行结果
复杂度分析
- 空间复杂度:
- 时间复杂度:
在掘金(JUEJIN) 一起分享知识, Keep Learning!