一、题目描述
给定一个含有 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
提示:
1 <= target <= 10^9
1 <= nums.length <= 10^5
1 <= nums[i] <= 10^5
二、解题思路
这是一个典型的滑动窗口问题。滑动窗口是一种常用的处理数组或链表问题的技术,它通过两个指针(通常称为快指针和慢指针)来维护一个窗口。在这个问题中,我们使用滑动窗口来找到长度最小的子数组,其元素之和大于等于目标值 target
。
步骤如下:
- 初始化两个指针
left
和right
,它们都指向数组的开始位置。 - 初始化一个变量
sum
用于记录当前窗口内的元素和。 - 初始化一个变量
minLength
用于记录满足条件的最小子数组长度,初始值可以设为Integer.MAX_VALUE
。 - 使用
right
指针遍历数组,每次将nums[right]
加到sum
上。 - 当
sum
大于等于target
时,更新minLength
为当前窗口大小(即right - left + 1
),然后尝试通过将left
指针向右移动来缩小窗口,同时更新sum
。 - 当
right
指针遍历完数组后,如果minLength
仍然是Integer.MAX_VALUE
,说明没有找到满足条件的子数组,返回 0;否则返回minLength
。
三、具体代码
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int left = 0;
int sum = 0;
int minLength = Integer.MAX_VALUE;
for (int right = 0; right < nums.length; right++) {
sum += nums[right]; // 将当前元素加到sum上
// 当sum大于等于target时,尝试缩小窗口
while (sum >= target) {
minLength = Math.min(minLength, right - left + 1); // 更新最小长度
sum -= nums[left]; // 从sum中减去left指针指向的元素
left++; // left指针右移
}
}
// 如果minLength没有被更新,返回0;否则返回minLength
return minLength == Integer.MAX_VALUE ? 0 : minLength;
}
}
四、时间复杂度和空间复杂度
1. 时间复杂度
right
指针遍历数组一次,其操作是线性的,时间复杂度为 O(n),其中 n 是数组nums
的长度。- 对于每个
right
指针的位置,left
指针最多只会从数组的起始位置移动到right
指针的位置,因此对于每个right
指针的位置,left
指针的操作也是线性的。 - 由于
left
指针在遍历过程中不会超过right
指针,因此left
指针的总移动次数不会超过 n,即left
指针的总操作次数是 O(n)。 - 综合以上两点,总的时间复杂度是 O(n) + O(n) = O(n)。
2. 空间复杂度
left
、right
、sum
和minLength
都是固定数量的整型变量,它们占用常数空间,空间复杂度为 O(1)。- 该算法没有使用任何与输入数组大小相关的数据结构,如额外的数组或集合。
- 因此,总的空间复杂度是 O(1)。
五、总结知识点
-
数组遍历:
- 使用
for
循环来遍历数组nums
的所有元素。
- 使用
-
指针操作:
- 使用两个指针
left
和right
来表示滑动窗口的左右边界。 right
指针用于扩展窗口,left
指针用于收缩窗口。
- 使用两个指针
-
累加和:
- 使用变量
sum
来存储当前窗口内所有元素的和。
- 使用变量
-
最小值更新:
- 使用
Math.min()
方法来更新minLength
,以找到满足条件的最小子数组长度。
- 使用
-
条件判断:
- 使用
while
循环来判断当前窗口的元素和是否大于等于target
,并在满足条件时收缩窗口。
- 使用
-
整数比较:
- 使用
Integer.MAX_VALUE
来初始化minLength
,这是一个常用的技巧,用于在没有找到满足条件的子数组时返回 0。
- 使用
-
逻辑运算:
- 使用三元运算符
?:
来决定返回值,如果minLength
没有被更新(仍然是Integer.MAX_VALUE
),则返回 0;否则返回minLength
。
- 使用三元运算符
以上就是解决这个问题的详细步骤,希望能够为各位提供启发和帮助。