leetcode 算法-长度最小的子数组
题目
给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的连续子数组。如果不存在符合条件的连续子数组,返回 0。
示例:
输入: s = 7, nums = [2,3,1,2,4,3]
输出: 2
解释: 子数组 [4,3] 是该条件下的长度最小的连续子数组。
解题思路
我们使用变量min来记录满足条件的最小的连续子数组的长度,使用sum来记录和,n来记录当前连续数组的长度。
首先我们还是遍历原数组,先处理特殊情况:
当当前元素值>=s的时候,直接返回1,因为长度不可能小于1;
当当前元素值<s的时候,sum累加元素值,n++;如果sum>=s,可以确定nums[i]之前的n-1个元素的和是小于s的,但是我们无法确定累加的开始元素到当前元素的长度是不是最小,因为有可能不需要开始元素sum也可能大于s,有可能是因为当前元素非常大。
因此我们首先需要判断sum-nums[j]是否大于等于s,如果满足,每次让sum减去nums[j++],判断减去之后的sum是否还大于等于s,如果依然符合条件,则更新min值,继续判断,直到sum-nums[j]<s,则结束。
如果我们发现sum-nums[j]<s,那么可以直接和min比较,然后决定是否更新min值,更新结束之后,之后我们下一个寻找的肯定是min-1,如何才能最快找到min-1个元素的和大于等于s呢?
我们可以利用已有的min个元素中的后min-2个元素,然后外加下一个元素,这样就可以最快找到min-1个元素的和大于等于s。
代码
class Solution {
public int minSubArrayLen(int s, int[] nums) {
int min = Integer.MAX_VALUE,sum=0,n=0;
for (int i = 0; i <nums.length; i++) {
if(nums[i]>=s)return 1;
sum+=nums[i];
n++;
if(sum>=s){
int j=i-n+1;
if(sum-nums[j]>=s){
do{
sum -= nums[j++];
min = Math.min(min, --n);
}while (sum - nums[j] >= s);
}else{
if(n<min)min=n;
while(i-j>min-3){
sum -= nums[j++];
n--;
}
}
}
}
return min==Integer.MAX_VALUE?0 : min;
}
}