题目:

给定一个数组 nums 和一个正整数 target , 找出满足和大于等于 target 的长度最短的连续子数组并返回其长度,如果不存在这种子数组则返回 0。

方法一:滑动窗口

  • 设置一个左指针left和右指针right都指向数组开头位置0,左指针和右指针相当于滑动窗口的两端,题目就是要求使得窗口中的数字之和大于等于目标值的最小窗口长度。
  • 如果当前窗口中的数字之和小于target,不断移动右指针扩大窗口,直到窗口中的数字和大于等于target,比较得出最小窗口长度,此时,左指针移动一步,继续向右移动窗口,比较下一轮满足条件时窗口长度,最后的到最小值

alt

import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param nums int整型一维数组 
     * @param target int整型 
     * @return int整型
     */
    public int minSubarray (int[] nums, int target) {
        // write code here
        int left=0,right=0;
        int sum=nums[left];
        int res=nums.length;
        while(left<nums.length&&right<nums.length){
            while(right<nums.length&&sum<target)//当和小于目标值时,右指针向右移动,扩大窗口直到和大于等于目标值跳出循环
            {
                right++;
                if(right<nums.length)sum+=nums[right];
            }
            res=Math.min(res,right-left+1);//保存最小窗口长度
            sum-=nums[left];
            left++;//缩小窗口
        }
        return res;
    }
}
  
/**
 * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
 *
 * 
 * @param nums int整型一维数组 
 * @param target int整型 
 * @return int整型
 */
function minSubarray( nums ,  target ) {
    // write code here
    let left=0,right=0;
    const n= nums.length;
    let res=n;
    let sum=nums[left];
    while(left<n&&right<n){
        while(right<n&&sum<target){
            right++;
            if(right<n)sum+=nums[right];
        }
        res=Math.min(res,right-left+1);
        sum-=nums[left];
        left++;
    }
    return res;
}
module.exports = {
    minSubarray : minSubarray
};

复杂度:

  • 时间复杂度:O(n2)O(n^{2}),双层循环
  • 空间复杂度:O(1)O(1),常数级空间复杂度

方法二:二分+前缀和

  • 计算数组中每个数字结尾的前缀和数组preSum,例如preSum[j]-preSum[i]就是nums[i+1:j]之间数字的和
  • 于是,我们可以二分枚举长度mid为1到nums.length,当长度mid存在使得和大于target时,缩小搜索区间在[1:mid),否则搜索区间在[mid,nums.length]

alt

import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param nums int整型一维数组 
     * @param target int整型 
     * @return int整型
     */
    public int minSubarray (int[] nums, int target) {
        // write code here
        int[]preSum=new int[nums.length+1];
        for(int i=1;i<nums.length+1;i++){
            preSum[i]=preSum[i-1]+nums[i-1];
            if(nums[i-1]>=target)return 1;
        }
        int l=1,r=nums.length;
        if(preSum[nums.length]<target)return 0;
        while(l<r){
            int mid=(r+l)/2;//二分查找长度mid
            boolean flag=false;
            for(int i=0;i+mid<=nums.length;i++){//迭代尝试每一个长度为mid的子数组
                if(preSum[i+mid]-preSum[i]>=target){//满足和大于等于target跳出循环
                    flag=true;
                    break;
                }
            }
            if(flag)r=mid;
            else l=mid+1;
        }
        return l;
    }
}

复杂度:

  • 时间复杂度:O(nlog2n)O(nlog_{2}n),二分搜索的时间复杂度为:O(nlog2n)O(nlog_{2}n)
  • 空间复杂度:O(1)O(1),常数级空间复杂度