题目:
给定一个含有 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 <= 109
1 <= nums.length <= 105
1 <= nums[i] <= 105
进阶:
如果你已经实现 O(n) 时间复杂度的解法, 请尝试设计一个 O(n log(n)) 时间复杂度的解法。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/minimum-size-subarray-sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路:
一、【前缀和+二分查找】
前缀和:sum[i]表示从nums[0]到nums[i-1]的元素和。本题中说明了每个元素都为正,所以前缀和一定是递增的。
- 首先预处理出前缀和数组sum,前缀和数组下标从1开始,sum[i] = sum[i - 1] + nums[i - 1];
- 假设s对应的前缀和为:s = sum[i+1]=sum[i] + nums[i],将nums[i]视为结果数组的右端点,现在问题转换为找结果数组的左端点,已知s和target,题目要求是要找到大于等于target的最小数组长度,于是可以转换成在前缀和数组下标[0,i]中内找到满足小于等于d = s - target的最大下标,这个最大下标就是结果数组的左端点。
注意:
代码中更新最短长度用的:i - left,为什么没有写成 i - left+ 1?
因为前缀和下标从1开始的,而left是从下标0开始的。故相减下来就是数组的长度。
java代码:
1 class Solution { 2 public int minSubArrayLen(int target, int[] nums) { 3 int n = nums.length, ans = Integer.MAX_VALUE; 4 int[] sum = new int[n + 1]; 5 //计算前缀和 6 for (int i = 1; i <= n; i++){ 7 sum[i] = sum[i - 1] + nums[i - 1]; 8 } 9 for (int i = 1; i <= n; i++){ 10 int s = sum[i], d = s - target; 11 int left = 0, right = i; 12 while (left < right){ 13 int mid = left + (right - left + 1) / 2; 14 //不够d,需要往右移 15 if (sum[mid] <= d){ 16 left = mid; 17 }else{ 18 //超过了d,往左移 19 right = mid - 1; 20 } 21 } 22 //循环结束:left == right,找到小于等于d的最大下标,更新最小长度 23 if (sum[left] <= d){ 24 ans = Math.min(ans, i - left); 25 } 26 } 27 return ans == Integer.MAX_VALUE ? 0 : ans; 28 } 29 }
二、【滑动窗口】--双指针
滑动窗口需要考虑的三点:
1.窗口内是什么?
2.怎么移动窗口的起始位置?
3.怎么移动窗口的结束位置?
然后本题就是:
1.窗口内就是 满足其和 ≥ s 的长度最小的 连续 子数组。
2.窗口的起始位置如何移动:如果当前窗口的值大于s了,窗口就要向前移动了(也就是该缩小了)。
3.窗口的结束位置如何移动:窗口的结束位置就是遍历数组的指针,也就是for循环里的索引。
关键部分图解:
来源:作者【carlsun-2】
链接:https://leetcode.cn/problems/minimum-size-subarray-sum/solution/by-carlsun-2-iiee/
java代码:
1 class Solution { 2 public int minSubArrayLen(int target, int[] nums) { 3 int n = nums.length, ans = Integer.MAX_VALUE; 4 int left = 0, sublen = 0, sum = 0; 5 for (int right = 0; right < n; right++){ 6 sum += nums[right]; 7 while (sum >= target){ 8 //获取当前数组长度 9 sublen = right - left + 1; 10 ans = Math.min(ans, sublen); 11 sum -= nums[left++]; 12 } 13 } 14 return ans == Integer.MAX_VALUE ? 0 : ans; 15 } 16 }
python3代码:
1 class Solution: 2 def minSubArrayLen(self, target: int, nums: List[int]) -> int: 3 left, ans, sum, sublen = 0, float("inf"), 0, 0 4 for right in range(len(nums)): 5 sum += nums[right] 6 while sum >= target: 7 sublen = right - left + 1 8 ans = min(sublen, ans) 9 sum -= nums[left] 10 left += 1 11 return 0 if ans == float("inf") else ans标签:java,target,nums,209,sum,力扣,int,数组,ans From: https://www.cnblogs.com/liu-myu/p/16931813.html