Medium
题目描述
给定一个含有 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^91 <= nums.length <= 10^51 <= nums[i] <= 10^4
进阶: 如果你已经实现 O(n) 时间复杂度的解法, 请尝试设计一个 O(n log(n)) 时间复杂度的解法。
解题思路
这道题要求找到和大于等于目标值的最短连续子数组,有两种主要解法:
方法一:滑动窗口(推荐)
滑动窗口是这类问题的最优解法。我们维护一个窗口 [left, right],不断扩大右边界来增加窗口和,当窗口和达到目标值时,尝试缩小左边界来寻找更短的子数组。
具体步骤:
- 初始化左指针
left = 0,窗口和sum = 0,最小长度minLen = ∞ - 遍历右指针
right,将nums[right]加入窗口和 - 当窗口和
≥ target时,更新最小长度,然后收缩左边界 - 重复步骤 2-3 直到遍历完成
方法二:前缀和 + 二分查找
由于数组元素都是正数,前缀和数组严格递增,可以用二分查找优化。对于每个位置,计算以该位置为起点的最短子数组长度。
时间复杂度 O(n log n),空间复杂度 O(n)。虽然理论上较慢,但在某些场景下可能更直观。
推荐使用滑动窗口解法,代码简洁且效率最高。
代码实现
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int left = 0, sum = 0, minLen = INT_MAX;
for (int right = 0; right < nums.size(); right++) {
sum += nums[right];
while (sum >= target) {
minLen = min(minLen, right - left + 1);
sum -= nums[left++];
}
}
return minLen == INT_MAX ? 0 : minLen;
}
};
class Solution:
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
left = 0
sum_val = 0
min_len = float('inf')
for right in range(len(nums)):
sum_val += nums[right]
while sum_val >= target:
min_len = min(min_len, right - left + 1)
sum_val -= nums[left]
left += 1
return 0 if min_len == float('inf') else min_len
public class Solution {
public int MinSubArrayLen(int target, int[] nums) {
int left = 0, sum = 0, minLen = int.MaxValue;
for (int right = 0; right < nums.Length; right++) {
sum += nums[right];
while (sum >= target) {
minLen = Math.Min(minLen, right - left + 1);
sum -= nums[left++];
}
}
return minLen == int.MaxValue ? 0 : minLen;
}
}
var minSubArrayLen = function(target, nums) {
let left = 0;
let sum = 0;
let minLen = Infinity;
for (let right = 0; right < nums.length; right++) {
sum += nums[right];
while (sum >= target) {
minLen = Math.min(minLen, right - left + 1);
sum -= nums[left];
left++;
}
}
return minLen === Infinity ? 0 : minLen;
};
复杂度分析
| 复杂度类型 | 滑动窗口 | 前缀和+二分 |
|---|---|---|
| 时间复杂度 | O(n) | O(n log n) |
| 空间复杂度 | O(1) | O(n) |
说明:
- 滑动窗口:每个元素最多被访问两次(一次加入窗口,一次移出窗口)
- 前缀和+二分:需要 O(n) 空间存储前缀和,每个位置进行二分查找需要 O(log n) 时间
相关题目
. Minimum Window Substring (Hard)
. Maximum Size Subarray Sum Equals k (Medium)
. K Radius Subarray Averages (Medium)
. Maximum Product After K Increments (Medium)