leetcode 面试算法 209. 长度最小的子数组(最好理解的算法)

49 阅读1分钟

给定一个含有 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.cn/problems/mi…

题解

暴力的方法是直接两个for循环枚举每一个子数组的和,跟目标数进行比较,结果毫无疑问的超时了。

想到双指针也可以用来遍历每一个子数组,时间上或许可以两个for循环快。

指针分为左指针跟右指针,两者都从0下标出发,一前一后就可以表示出子数组,不过两个指针前进的条件就要进行修改,这点很关键,不然就会超时。

指针前进的条件,对于右指针,如果此时子数组的和比目标数要小,右指针前进,代表在子数组中添加一个数,使它的和变大。对于左指针,如果和比目标数要大或者两者相等的时候前进,代表从这个子数组中去掉一个数,同时因为和已经比目标数大了,此时就可以记录下长度,一直更新这个长度直到循环结束。 代码如下:

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int left=0,right=0;
        int sum=0,mmin=999999999;
        while(left<=nums.length-1){
            if(sum<target&&right<nums.length){
                sum+=nums[right++];
            }
            else if(sum>=target){
                mmin=Math.min(mmin,right-left);
                System.out.print(mmin+" ");
                sum-=nums[left++];
            }
            else {
                left++;
            }
            
        }
        if(mmin==999999999)return 0;
        return mmin;
    }
}

图片.png 虽然很慢,你就说过没过吧。