刷题系列之209.长度最小的子数组

44 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第19天,点击查看活动详情

题目来源

leetcode.cn/problems/mi…

题目介绍

给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。

输入: target = 7, nums = [2,3,1,2,4,3]
输出: 2
解释: 子数组 [4,3] 是该条件下的长度最小的子数组。

题目分析

根据题目提供的信息,我们已经知道一个正整数数组,和一个确定的值,我们需要找出连续的子数组,并使这个子数组元素相加的和大于这个确定的值。

要求的是这个子数组是所有满足条件当中的数组中长度是最小的。

关键词:长度最小的,连续的。

因此我们可以想到一个简单的解法就是,利用2个for循环,让每个元素和剩下的元素不断相加得到的值来进行判断。

例如target = 7, nums = [2,3,1,2,4,3],这里有6个元素,那么要做的就是循环得到

2,2+3,2+3+1,2+3+1+2...等等加到最后一个,然后继续

3,3+1,3+1+2...

...

等等双层for循环完毕,我们可以发现,第一次循环当2+3+1+2>=7了,这时候可以跳出循环,继续下一次循环,并且按照这个循环逻辑,满足条件的子数组长度肯定是越来越小的,因此循环结束后的最后一个子数组长度就是我们所求的值。

题目解答

/**
 * @param {number} target
 * @param {number[]} nums
 * @return {number}
 */
var minSubArrayLen = function(target, nums) {
        const n=nums.length;
        let result = n+1; // 初始化最终的结果,设置为最大长度+1,因为子数组长度最大就是n
        let sum = 0; // 子序列的数值之和
        let subLength = 0; // 子序列的长度
        for (let i = 0; i < n; i++) { // 设置子序列起点为i
            sum = 0;
            for (let j = i; j < n; j++) { // 设置子序列终止位置为j
                sum += nums[j];
                if (sum >= target) { // 一旦发现子序列和超过了s,更新result
                    subLength = j - i + 1; // 取子序列的长度
                    result = result < subLength ? result : subLength;
                    break; // 因为我们是找符合条件最短的子序列,所以一旦符合条件就break
                }
            }
        }
        // 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列
        return result == n+1 ? 0 : result;
};

image.png

官方解法之滑动窗口

这种解法很巧妙,先定义两个变量 分别表示子数组(滑动窗口)的开始位置和结束位置,维护变量 sum 存储子数组中的元素和。

先让r移动,不算计算sum,一旦满足条件,则取子数组长度res的值,并且让sum减掉l下标元素的值,看结果是否还满足,还满足则继续减去l+1的值,一旦不满足>=target,则跳出内层循环,继续外层循环,即累加r下标元素的值。

var minSubArrayLen = function(target, nums) {
    // 长度计算一次
    const len = nums.length;
    let l = r = sum = 0,
    res = len + 1; // 子数组最大不会超过自身
    while(r < len) {
        sum += nums[r++];
        // 窗口滑动
        while(sum >= target) {
            // r始终为开区间 [l, r) 因此r-l就是子数组长度,因为上面是r++了
            res = res < r - l ? res : r - l;
            sum-=nums[l++];
        }
    }
    return res > len ? 0 : res;
};

总结

这个题目的滑动窗口解法还是稍微有点抽象,需要仔细理解,一步步分析才能联想到。