# [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

提示:

进阶:

如果你已经实现 O(n) 时间复杂度的解法, 请尝试设计一个 O(n log(n)) 时间复杂度的解法。

这道题是求满足条件的子数组最小长度。对于求子串、子数组的最优解问题,我们首先想到是否能用滑动窗口或是动态规划来解。这道题要求子数组连续,那么其实用滑动窗口就够了。

那么就来到了经典的问题填空环节:

  1. 扩充右边界后,何时能使滑动窗口内的元素满足要求。根据题意,当滑动窗口内元素总和 >= target 时,考虑开始缩小左边界。

  2. 何时更新返回结果。在本题中,当滑动窗口内元素总和 >= target 时,比对记录值与当前sum结果,保存最小值。

这样一套操作下来,整个问题就没有任何难点可言了。

(吐槽一句,题目是要笑死我吗,实现了O(n)的算法,为啥还要我设计一个O(nlgn)的算法……)

function minSubArrayLen(target: number, nums: number[]): number {
  let res: number = nums.length + 1;
  let left = 0;
  let right = 0;

  let sum = 0;
  while (right < nums.length) {
    sum += nums[right];
    right += 1;

    while (sum >= target) {
      res = Math.min(res, right - left);
      sum -= nums[left];
      left++;
    }
  }

  // 不存在时返回0
  return res === nums.length + 1 ? 0 : res;
}