LeetCode 209.长度最小的子数组
题目描述
给定一个正整数数组 nums
和一个正整数 target
,找出连续子数组的最小长度,使得子数组的和大于或等于 target
。如果不存在符合条件的子数组,返回 0。
Java 实现代码
public class Solution {public int minSubArrayLen(int target, int[] nums) {int n = nums.length;int left = 0, sum = 0, minLength = Integer.MAX_VALUE;for (int right = 0; right < n; right++) {sum += nums[right]; // 扩展窗口,加入当前元素// 窗口内的和大于等于 target 时,尝试缩小窗口while (sum >= target) {minLength = Math.min(minLength, right - left + 1);sum -= nums[left]; // 移动左指针,缩小窗口left++;}}return minLength == Integer.MAX_VALUE ? 0 : minLength;}
}
解题思路
滑动窗口:使用两个指针
left
和right
来表示当前窗口的边界,窗口的右边界逐步扩展,直到窗口内的和大于等于target
。窗口收缩:每当当前窗口的和大于等于
target
时,尝试通过移动左指针(即收缩窗口)来找到最小的符合条件的子数组。每次更新最小长度。返回结果:在遍历完数组后,若未找到符合条件的子数组,则返回 0;否则返回最小长度。
复杂度分析
- 时间复杂度:O(n),其中 n 是数组的长度。由于每个元素最多被访问两次(一次是右指针扩展,另一次是左指针收缩),因此时间复杂度是 O(n)。
- 空间复杂度:O(1),只用了常数级别的额外空间。
举例说明执行过程
假设输入数组
nums = [2, 3, 1, 2, 4, 3]
,target = 7
。
初始化:
left = 0, sum = 0, minLength = Integer.MAX_VALUE
遍历右指针:
right = 0
,sum = 0 + nums[0] = 2
,sum = 2
,不满足条件sum >= 7
,继续扩展。right = 1
,sum = 2 + nums[1] = 5
,sum = 5
,不满足条件sum >= 7
,继续扩展。right = 2
,sum = 5 + nums[2] = 6
,sum = 6
,不满足条件sum >= 7
,继续扩展。right = 3
,sum = 6 + nums[3] = 8
,sum = 8
,满足条件sum >= 7
,此时子数组为[2, 3, 1, 2]
,长度为 4,更新minLength = 4
。收缩窗口:
- 由于满足
sum >= target
,我们尝试通过移动left
来缩小窗口:left = 0
,sum = 8
,缩小窗口,sum -= nums[0] = 8 - 2 = 6
,left = 1
,sum = 6
,不满足sum >= 7
,继续扩展右指针。继续遍历:
right = 4
,sum = 6 + nums[4] = 10
,满足sum >= 7
,此时子数组为[3, 1, 2, 4]
,长度为 4,但minLength
仍然保持 4。收缩窗口:
left = 1
,sum = 10
,继续缩小窗口,sum -= nums[1] = 10 - 3 = 7
,此时sum >= target
,子数组为[1, 2, 4]
,长度为 3,更新minLength = 3
。继续遍历:
right = 5
,sum = 7 + nums[5] = 10
,满足sum >= 7
,此时子数组为[1, 2, 4, 3]
,长度为 4,但minLength
保持为 3。收缩窗口:
left = 2
,sum = 10
,继续缩小窗口,sum -= nums[2] = 10 - 1 = 9
,仍然满足sum >= 7
,子数组为[2, 4, 3]
,长度为 3,minLength
保持为 3。left = 3
,sum = 9
,继续缩小窗口,sum -= nums[3] = 9 - 2 = 7
,满足sum >= 7
,子数组为[4, 3]
,长度为 2,更新minLength = 2
。结束遍历:
- 右指针已经遍历完整个数组,最终得到
minLength = 2
。