长度最小的子数组
给定一个含有 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
解题思路
因为有子数组,滑动窗口(双指针):left 指针和 right 指针,开始时均指向数组的开头。
每当 right 指针指向一个新元素时,就用进行 sum 求和。
1.当 sum >= target 时,记录当前窗口的大小,并且 left 指针向右移动一位(因为,当前 right 指针指向的位置所得到的 sum 值已经不满足条件了,即使加上它后面的元素仍然不满足条件,因为 nums[i] >= 1)所以,left 指针右移并且让 right 指针与 left 指针指向同一位置,sum 值修改为 0,重新进行判断。
2.当 sum < target 时,直接令 right 指针右移一位,并且将 right 指针新指向的元素累加到 sum 中。
代码
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int n = nums.length;
int left = 0, right = 0;
int MinLength = Integer.MAX_VALUE;
int sum = 0;
while (right < n) {
sum += nums[right];
if (sum >= target) {
MinLength = Math.min(MinLength, right - left + 1);
left++;
right = left;
sum = 0;
} else {
right++;
}
}
return MinLength == Integer.MAX_VALUE ? 0 : MinLength;
}
}
时间复杂度:因为只遍历了一次 nums 数组且长度为 n,所以复杂度为O(n)
空间复杂度:因为没有开辟任何新的空间,所以复杂度为O(1)
优化
将 while 循环中的 if 改成 while,这样 sum 不需要在不符合条件时,重新修改为 0,将之前已经添加过的元素再重新添加一遍,节省了代码执行的时间。
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int n = nums.length;
int left = 0, right = 0;
int MinLength = Integer.MAX_VALUE;
int sum = 0;
while (right < n) {
sum += nums[right];
while (sum >= target) {
MinLength = Math.min(MinLength, right - left + 1);
sum -= nums[left];
left++;
}
right++;
}
return MinLength == Integer.MAX_VALUE ? 0 : MinLength;
}
}
滑动窗口类型的题目中的 while 中的判断条件有时候用 while 比用 if 好一些!!