滑动窗口解法:最短子数组长度代码解释与优化

📅 2026/6/26 4:21:12
滑动窗口解法:最短子数组长度代码解释与优化
目录一、代码逐行解释滑动窗口解法最短子数组长度原代码完整拆解原代码存在的 BUG 缺陷二、标准优化版滑动窗口双指针优化思路三、优化点对比说明四、逻辑流程演示举例五、补充二分前缀和解法进阶 O (nlogn)一、代码逐行解释滑动窗口解法最短子数组长度题目LeetCode 209 长度最小的子数组 给定正整数数组nums和目标值target找出总和 ≥ target 的连续子数组的最小长度不存在返回 0。原代码完整拆解class Solution { public int minSubArrayLen(int target, int[] nums) { // 记录最小窗口长度初始为最大值代表没找到合法窗口 int min Integer.MAX_VALUE; // 当前窗口 [left, right] 的元素和 int sum 0; int left 0; // 窗口左边界 int right 0;// 窗口右边界 int length nums.length; sum nums[0]; // 先把第一个元素加入窗口 // 第一个元素直接大于target最短长度就是1直接返回 if(sumtarget){ return 1; } // 外层循环右指针最多走到倒数第二个元素 while (rightlength-1){ // 内层1窗口和不足target不断右移右指针扩大窗口 while (sumtargetrightlength-1){ right; sum nums[right]; } // 内层2窗口和满足条件不断右移左指针缩小窗口更新最小长度 while (sumtarget){ if(minright - left1){ min right - left 1; } sum - nums[left]; left; } } // 如果min没更新过说明无合法子数组返回0否则返回最小长度 return min Integer.MAX_VALUE?0:min; } }原代码存在的 BUG 缺陷边界初始化缺陷数组为空、数组长度 1 时会报错nums[0]数组越界提前写死sum nums[0]破坏滑动窗口统一初始化逻辑。外层循环限制错误right length -1导致右指针无法走到数组最后一位最后一个元素永远无法纳入窗口测试用例极易出错。冗余特判if(sumtarget) return 1滑动窗口内部逻辑完全可以覆盖该场景属于多余代码。逻辑耦合、可读性差三层嵌套循环结构臃肿标准滑动窗口只需要一层外层循环控制右指针。变量命名尚可但流程不标准二、标准优化版滑动窗口双指针优化思路统一初始化sum0left0右指针从头遍历到尾消除数组越界去掉多余特判一套逻辑覆盖所有场景单层外层循环控制右指针满足和≥target 时收缩左边界增加数组判空鲁棒性更强简化长度更新代码时间复杂度 O (n)每个元素仅被左右指针各访问一次。class Solution { public int minSubArrayLen(int target, int[] nums) { // 边界空数组直接返回0 if (nums null || nums.length 0) { return 0; } int n nums.length; int minLen Integer.MAX_VALUE; int sum 0; int left 0; // 右指针从头到尾遍历一层循环即可 for (int right 0; right n; right) { sum nums[right]; // 扩大右边界 // 当窗口和满足条件持续收缩左边界更新最小长度 while (sum target) { minLen Math.min(minLen, right - left 1); sum - nums[left]; left; } } // 未找到合法子数组返回0 return minLen Integer.MAX_VALUE ? 0 : minLen; } }三、优化点对比说明问题优化方案访问 nums [0] 越界sum 初始 0循环内逐个加 nums [right]兼容空 / 长度 1 数组right 走不到末尾for 循环 right n完整遍历全部元素多余 if 特判单个元素while 收缩窗口自动处理单元素满足 target 场景三层循环嵌套臃肿外层单层 for内层仅收缩窗口的 while逻辑清晰手动比较更新 min使用Math.min简化代码无空数组防护开头增加 nums 判空线上不会 NPE / 数组越界四、逻辑流程演示举例target7nums[2,3,1,2,4,3]right 不断右移累加 sum直到 sum≥7right3 sum8进入收缩循环窗口 [0,3] 长度 4min4sum-26left1 退出收缩right4 sum10收缩[1,4] 长度 4 → min 不变sum-37 left2[2,4] 长度 3 → min3sum-16 left3 退出right5 sum9收缩[3,5] 长度 3 → min 不变sum-27 left4[4,5] 长度 2 → min2sum-43 left5 退出 最终返回 2正确答案。五、补充二分前缀和解法进阶 O (nlogn)如果题目允许还可以用前缀和 二分查找适合数据量极大场景class Solution { public int minSubArrayLen(int target, int[] nums) { int n nums.length; int[] preSum new int[n 1]; for (int i 0; i n; i) { preSum[i 1] preSum[i] nums[i]; } int min Integer.MAX_VALUE; for (int i 1; i n; i) { int aim preSum[i] - target; // 二分找最大j满足preSum[j] aim int l 0, r i; while (l r) { int mid l r 1; if (preSum[mid] aim) l mid 1; else r mid; } if (l 0) { min Math.min(min, i - l 1); } } return min Integer.MAX_VALUE ? 0 : min; } }日常刷题优先滑动窗口 O (n)效率更高、代码更简洁。