
public int minSubArrayLen(int target, int[] nums) {
int left=0;
int right=0;
int sum=nums[left];
if(sum>=target){
return 1;
}
else right++;
sum+=nums[right];
int len=right-left+1;
while(sum>=target){
sum-=nums[left];
left++;
if(len<=right-left+1){
len=right-left+1;
}
while (sum<target){
right++;
sum+=nums[right];
if(len<=right-left+1){
len=right-left+1;
}
}
}
return len;
}
其核心内容是 "长度最小的子数组"问题 的算法笔记。以下从题目分析、算法分析和代码编写三个方面进行总结:
题目分析
-
问题 :给定一个含有
n个正整数 的数组和一个正整数target,找出该数组中满足其和 ≥ target 的长度最小的连续子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。 -
输入 :一个正整数数组
nums,一个正整数target。 -
输出:最小子数组的长度。
-
示例 :笔记中以数组
[2,3,1,2,4,3]和target = 7为例。符合条件的子数组有[4,3]和[2,4,3],最小长度为 2。
算法分析
笔记中对比了两种解法:
-
暴力枚举法:
-
思路 :枚举所有可能的子数组(通过双重循环确定左右边界),计算每个子数组的和,判断是否 ≥
target并记录最小长度。 -
缺点:时间复杂度为 O(n²)(若每次求和都重新计算,则为 O(n³)),效率低下。
-
-
滑动窗口(双指针)法(最优解):
-
核心思想 :利用数组元素均为正数的单调性 ,使用两个同向移动的指针(
left和right)构成一个窗口。通过动态调整窗口大小,在 O(n) 时间内找到最小窗口。 -
步骤:
-
初始化 :
left = 0,right = 0,sum = 0,minLen = 无穷大(如INT_MAX)。 -
进窗口 :将
nums[right]加到sum中,然后right右移。 -
判断 :当
sum >= target时,说明当前窗口满足条件。-
更新结果 :计算当前窗口长度
right - left,并更新minLen。 -
出窗口 :从
sum中减去nums[left],然后left右移,以尝试缩小窗口,寻找更小的满足条件的窗口。
-
-
重复步骤 2 和 3,直到
right到达数组末尾。
-
-
优点:每个元素最多被访问两次(进窗口和出窗口各一次),时间复杂度为 O(n),空间复杂度为 O(1)。
-
代码编写
以下是修正和完善图片中代码逻辑后的 Java 实现:
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int n = nums.length;
int left = 0; // 窗口左边界
int right = 0; // 窗口右边界
int sum = 0; // 窗口内元素的和
int minLen = Integer.MAX_VALUE; // 最小长度,初始化为最大值
while (right < n) {
// 1. 进窗口:右指针向右移动,扩大窗口
sum += nums[right];
// 2. 判断:当窗口内元素和满足条件时,尝试收缩窗口以找到更小的窗口
while (sum >= target) {
// 3. 更新结果:计算当前窗口长度并更新最小值
int currentLen = right - left + 1;
minLen = Math.min(minLen, currentLen);
// 4. 出窗口:左指针向右移动,缩小窗口
sum -= nums[left];
left++;
}
// 继续移动右指针,扩大窗口
right++;
}
// 如果 minLen 没有被更新过,说明没有符合条件的子数组,返回 0
return (minLen == Integer.MAX_VALUE) ? 0 : minLen;
}
}
代码说明:
-
初始化 :
left和right都从 0 开始,sum初始为 0,minLen初始为Integer.MAX_VALUE。 -
主循环 :
while (right < n)控制右指针遍历整个数组。 -
进窗口 :每次循环先将当前
right指向的元素加入sum。 -
内层循环 :当
sum >= target时,说明当前窗口满足条件。此时:-
计算当前窗口长度
right - left + 1,并更新minLen。 -
然后从
sum中减去nums[left],并将left右移一位,以尝试寻找更小的满足条件的窗口。 -
这个内层循环会持续到
sum < target,确保我们找到了以当前right为右边界的最小满足条件的窗口。
-
-
移动右指针 :内层循环结束后,
right右移,继续探索下一个元素。 -
返回值 :如果
minLen从未被更新,则返回 0;否则返回minLen。
此解法是解决"长度最小的子数组"问题的标准滑动窗口方法,高效且易于理解。