题目描述
Given an array of positive integers nums and a positive integer target, return the minimal length of a subarray whose sum is greater than or equal to target. If there is no such subarray, return 0 instead.
Example 1:
1 | Input: target = 7, nums = [2,3,1,2,4,3] |
Example 2:
1 | Input: target = 4, nums = [1,4,4] |
Example 3:
1 | Input: target = 11, nums = [1,1,1,1,1,1,1,1] |
Constraints:
1 <= target <= 10^91 <= nums.length <= 10^51 <= nums[i] <= 10^4
Follow up: If you have figured out the O(n) solution, try coding another solution of which the time complexity is O(n log(n)).
解题方法
双指针
思路解析:
- 滑动窗口:使用两个指针
left和right来维护一个窗口,right用来扩展窗口,left用来缩小窗口。 - 窗口内求和:随着
right的移动,我们将元素加入窗口,并计算窗口内的和。当窗口内的和大于等于target时,尝试移动left来缩小窗口,并更新最小长度。 - 不断更新最小长度:每次找到满足条件的窗口后,记录该窗口的长度,并继续尝试找到更短的窗口。
具体步骤:
- 初始化:
left指针设为 0,right指针从 0 开始,sum初始化为 0,min_length初始化为正无穷大。 - 扩展窗口:遍历数组,每次将
nums[right]加到sum中。 - 缩小窗口:当
sum大于等于target时,更新min_length为right - left + 1,并尝试通过移动left来缩小窗口,同时减少sum的值。 - 重复步骤 2 和 3,直到遍历完整个数组。
- 最后,如果
min_length仍为正无穷大,说明没有找到符合条件的子数组,返回 0;否则,返回min_length。
1 | class Solution: |
时间复杂度:$O(n)$
空间复杂度:$O(1)$
二分查找
使用二分查找可以将问题的时间复杂度提升到 O(n log n)。这种方法基于前缀和(Prefix Sum)与二分查找的结合。
思路解析:
- 前缀和数组:
- 首先,构建一个前缀和数组
prefix_sums,其中prefix_sums[i]表示数组nums前i个元素的和。即prefix_sums[i] = nums[0] + nums[1] + ... + nums[i-1]。 - 因此,任何子数组
nums[i...j]的和可以表示为prefix_sums[j+1] - prefix_sums[i]。
- 首先,构建一个前缀和数组
- 二分查找:
- 对于每一个起点
i,我们希望找到最小的j使得prefix_sums[j+1] - prefix_sums[i] >= target。这等价于在prefix_sums中找到最小的j,使得prefix_sums[j+1] >= prefix_sums[i] + target。 - 通过二分查找,可以在
prefix_sums数组中快速找到这个j。
- 对于每一个起点
- 更新最小长度:
- 对每一个起点
i,如果找到了满足条件的j,我们更新最小子数组长度为j - i + 1。
- 对每一个起点
具体步骤:
- 构建前缀和数组
prefix_sums,长度为n + 1,其中prefix_sums[0] = 0。 - 遍历数组
nums的每一个起点i,计算当前需要查找的目标和target_sum = prefix_sums[i] + target。 - 使用二分查找在
prefix_sums中查找最小的j使得prefix_sums[j] >= target_sum。 - 更新最小子数组长度为
j - i,如果找到了符合条件的j。 - 最后返回最小子数组长度,如果没有找到则返回 0。
1 | class Solution: |
时间复杂度:$O(nlogn)$
空间复杂度:$O(n)$