leetcode 209: 长度最小的子数组
给定一个含有 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))
时间复杂度的解法。
Related Topics
数组
二分查找
前缀和
滑动窗口
思路1 : 滑动窗口
使用2个指针,当sum不符合时,继续向右加。
符合时,将left向左移动,减少sum的值。完成测试。
public int minSubArrayLen(int target, int[] nums) { int minLength = 1000000; int left = 0 ; int right = -1; int sum = 0 ; while(true){ if(sum>=target){//符合条件 //计算长度 int length = right - left + 1; //比出最小长度 if(length < minLength){ minLength = length; } sum-=nums[left]; left++; //左边移动一位 }else{//不符合 继续向右加 right++; if(right == nums.length){ break; } sum+=nums[right]; } } //退出上面循环的时候 sum 一定小于target //但是当所有值加起来都不满足还没有判断 return minLength == 1000000 ? 0 : minLength; } 解答成功: 执行耗时:1 ms,击败了99.99% 的Java用户 内存消耗:41.6 MB,击败了5.27% 的Java用户
思路1 的另一种写法。 上面的方法先right++,再加sum。
这一种先加sum,后right++。都得保证最后right == nums.length时,left已经移到最左边,使sum< target
参考leetcode官方解答
public int minSubArrayLen(int target, int[] nums) { int minLength = 1000000; int left = 0 ; int right = 0; int sum = 0 ; while(right < nums.length){ sum+=nums[right]; while(sum >= target){ int length = right - left + 1; if(length < minLength){ minLength = length; } sum-=nums[left]; left++; } right++; } return minLength == 1000000 ? 0 : minLength; }
思路2:前缀+二分查找
因为所有值都大于0,可以使用前缀和和二分查找,使时间复杂度达到 O(n log(n))
参考leetcode思路。
public int minSubArrayLen(int target, int[] nums) { //前缀法+二分查找 int result = Integer.MAX_VALUE; int[] sum = new int[nums.length+1]; sum[0] = 0; for(int i = 1 ; i <= nums.length;i++){ sum[i] = sum[i-1] + nums[i-1]; } for(int i = 1; i <= nums.length;i++){ int newTarget = target+sum[i-1]; int bound = Arrays.binarySearch(sum,newTarget); // binarySearch方法找不到相等的值时 返回 return -(low + 1); if(bound < 0 ){ bound = -bound -1; } //会有2中结果 如果没找到 bound会超过 // 找到 bound会停到一个大于等于它的位置 if(bound <= nums.length){ result = Math.min(result,bound - i + 1); } } return result == Integer.MAX_VALUE ? 0 : result; }