一、问题描述
Category | Difficulty | Likes | Dislikes |
---|---|---|---|
algorithms | Medium (48.18%) | 967 | - |
给定一个含有 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
提示:
1 <= target <= 109
1 <= nums.length <= 105
1 <= nums[i] <= 105
进阶:
- 如果你已经实现
O(n)
时间复杂度的解法, 请尝试设计一个O(n log(n))
时间复杂度的解法。
二、xin麒的思路
本题解使用了滑动窗口法,
摘要:
- 滑动窗口法的精髓就是在于外层循环不断遍历,寻找出一个符合题目要求的子数组,内层循环将子数组优化:剔除重复的元素。
前提引入:
-
- 定义sum变量保存累加的数组,方便与target比较;
-
- 使用变量count保存合适的长度(初始值为
nums.lengh
方便后面的比较) - 使用变量note来记录,解决没有子数组的情况(如果note始终为0,那么说明nums里找不到符合的子数组)
- start指针从0开始
- 使用变量count保存合适的长度(初始值为
分析:
首先使用end作为指针遍历,遍历时,不断进行
sum += nums[end]
使得sum增加;
- 待sum大于或等于target时,这时候**
(end - start + 1 )
的数值一定是该end值对应的子数组的长度吗?如果sum[end]远大于target,那么显然此时的(end - start + 1 )
对应的数值偏大了,于是需要让start**增大,同时sum的数值适当减小(减小到刚刚sum < target
即可)于是构造一层内部的while循环,该循环实现功能有:
- 使得每次sum都要不断减小
- 同时start增大到合适的值
根据上述分析,可知循环条件为
sum >= target
由于内层循环退出后需要让count保存此刻子数组的长度,那么子数组的长度**
(end - start + 1 )
还是(end - start + 2 )
呢?显然,由于此时退出循环时sum已经小于target了,那么此时end对应的子数组应该是由索引在区间[start-1,end]的元素构成,那么长度就是(end - start + 2 )
**;每次找到不同的长度,就通过与count比较,取小的作为count
三、xin麒的题解:
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int start = 0;
int size = nums.length;
int count = size;
int sum = 0;
int note = 0;
for (int end = 0; end < size; end++) {
sum += nums[end];
if (sum >= target){
note = 1;
while (sum >= target){
sum -= nums[start++];
}
int number = end - start + 2;
if (count > number){
count = number;
}
}
}
if (note == 0){
return 0;
}
return count;
}
}