LeetCode 209 题:长度最小的子数组 (Minimum Size Subarray Sum)
LeetCode 第209题要求给定一个正整数数组 nums
和一个正整数 target
,找出具有最小长度的连续子数组,使得子数组的和大于或等于 target
。如果不存在这样的子数组,返回0。
题目描述
给定一个正整数数组 nums
和一个正整数 target
,找出具有最小长度的连续子数组,使得子数组的和大于或等于 target
。如果不存在这样的子数组,返回0。
示例 1:
输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 的和大于或等于 target 7,并且长度最小。
示例 2:
输入:target = 4, nums = [1,4,4]
输出:1
示例 3:
输入:target = 11, nums = [1,1,1,1,1,1,1,1]
输出:0
解题思路
-
暴力解法:
- 一个简单的暴力解法是使用双重循环,遍历所有可能的子数组并检查它们的和。这种方法的时间复杂度是 O ( n 2 ) O(n^2) O(n2),对于较大的输入,效率较低。
-
滑动窗口法:
- 通过滑动窗口来优化上述暴力解法。具体来说:
- 使用两个指针,
left
和right
,分别表示窗口的左边界和右边界。 - 扩展右边界,逐步增大窗口的和。
- 当窗口的和大于或等于
target
时,记录当前窗口的长度,并尝试缩小窗口的左边界以求最小长度。 - 最终返回最小的符合条件的窗口长度。
- 使用两个指针,
- 通过滑动窗口来优化上述暴力解法。具体来说:
-
复杂度分析:
- 时间复杂度: O ( n ) O(n) O(n),因为左右指针分别从头到尾遍历数组。
- 空间复杂度: O ( 1 ) O(1) O(1),仅使用了常量空间来存储相关变量。
C语言代码实现
以下是使用滑动窗口法的代码实现:
#include <stdio.h>
#include <stdlib.h>int minSubArrayLen(int target, int* nums, int numsSize) {int left = 0, sum = 0, minLength = numsSize + 1;for (int right = 0; right < numsSize; right++) {sum += nums[right];// 当窗口和大于等于 target 时,尝试缩小窗口while (sum >= target) {minLength = (right - left + 1) < minLength ? (right - left + 1) : minLength;sum -= nums[left++];}}// 如果找到的最小长度大于数组长度,说明没有符合条件的子数组return minLength == numsSize + 1 ? 0 : minLength;
}int main() {int nums[] = {2, 3, 1, 2, 4, 3};int target = 7;int result = minSubArrayLen(target, nums, 6);printf("最小长度为:%d\n", result); // 输出:2return 0;
}
逐行解释代码
函数 minSubArrayLen
int left = 0, sum = 0, minLength = numsSize + 1;
left
:滑动窗口的左边界。sum
:当前窗口内所有元素的和。minLength
:记录符合条件的最小窗口长度,初始值为numsSize + 1
,表示未找到符合条件的子数组。
for (int right = 0; right < numsSize; right++) {sum += nums[right];
right
是滑动窗口的右边界。- 我们通过扩展
right
边界,将nums[right]
加到sum
中,从而增大窗口的和。
while (sum >= target) {minLength = (right - left + 1) < minLength ? (right - left + 1) : minLength;sum -= nums[left++];
}
- 当窗口的和大于或等于
target
时,进入while
循环,尝试缩小窗口以找到最小的符合条件的子数组。 - 更新最小长度
minLength
,计算当前窗口的大小right - left + 1
。 - 将
nums[left]
从sum
中减去,并将left
向右移动,缩小窗口。
return minLength == numsSize + 1 ? 0 : minLength;
- 如果
minLength
仍然等于numsSize + 1
,说明没有找到符合条件的子数组,返回 0。 - 否则,返回找到的最小长度。
测试代码 main
int nums[] = {2, 3, 1, 2, 4, 3};
int target = 7;
int result = minSubArrayLen(target, nums, 6);
printf("最小长度为:%d\n", result); // 输出:2
- 定义一个测试用例
nums = {2, 3, 1, 2, 4, 3}
和target = 7
。 - 调用
minSubArrayLen
函数计算结果并打印。
测试结果
运行代码后输出:
最小长度为:2
复杂度分析
-
时间复杂度: O ( n ) O(n) O(n)
- 滑动窗口法的时间复杂度是 O ( n ) O(n) O(n),因为每个元素最多被访问两次(一次通过
right
扩展窗口,一次通过left
收缩窗口)。
- 滑动窗口法的时间复杂度是 O ( n ) O(n) O(n),因为每个元素最多被访问两次(一次通过
-
空间复杂度: O ( 1 ) O(1) O(1)
- 我们只用了常量空间来存储一些临时变量(
left
,sum
,minLength
),因此空间复杂度为 O ( 1 ) O(1) O(1)。
- 我们只用了常量空间来存储一些临时变量(