leetcode209-长度最小的子数组

172 阅读2分钟

题目描述

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

思考

由题目可知, 我们需要找的是长度最小的连续子数组,看到这类连续子集问题,一般可以尝试着使用栈或者队列来做。 这道题我们可以维护一个队列,每当有新数组元素的时候,我们将其压入队列,并计算队列所有数字的总和sum,如果sum大于目标值,我们就与之前暂存的最小长度比较,如果小于最小长度,那就更新最小长度, 然后将队头元素出队列。

        let minL = 0, minR = nums.length + 1;
        let i = minL,  j = minL;  // i j 表示队列头尾指针
        let sum = nums[0];

        while(true) {
            if (sum >= s) {
                if ( j - i < minR - minL) {
                    minL = i;
                    minR = j;
                }
                sum = sum - nums[i];
                i++;
            } else {
                j++;
                sum = sum + nums[j];
            }

            if (i >= nums.length) {
                break;
            }
        }
	return minR -minL + 1;

这里需要注意的一点是 有以下特殊情况

s = 7 nums = [1, 1, 1, 7];

如上面例子的数组, 我们在将数字7压入队列的时候,sum是大于7的, 这时候最小长度是4。但是这并非是最小长度,我们可以发现的是,将队头元素出队列之后,sum还是大于7。 因此,每当我们得到一个大于ssum值的时候, 我们在比较完最小长度之后,还需要确定出对列之后的sum值是否仍是大于s的。

接下来我们需要考虑一下特殊情况

1 nums的和小于s, 因此我们需要一个字段标识是否找了符合要求的序列, 如果有,计算子序列长度,如果没有 则返回0

2 当队尾指针j指向了nums尾部的时候, 如果接下来队列的数值和小于s,则我们不需要再移动队头指针i, 因为队列的元素总和小于s, 队列长度不会增加,只会减少。

代码改造如下

        ....
        let hasMin = false;
        while(true) {
            // console.log(i, j, sum);
            if (sum >= s) {
               hasMin = true;
               ....
            } else if (j >= nums.length - 1) {
                break;
            } else {
               ....
            }

            if (i >= nums.length) {
                break;
            }
        }
        
        // console.warn(minL, minR, sum);
        return  hasMin ?  minR - minL + 1 : 0;

完整代码

var minSubArrayLen = function(s, nums) {
    if (nums.length < 1) {
        return 0;
    }

    let minL = 0, minR = nums.length + 1;
    let i = minL,  j = minL;
    let sum = nums[0];
    let hasMin = false;

    while(true) {
        if (sum >= s) {
            hasMin = true;
            if ( j - i < minR - minL) {
                minL = i;
                minR = j;
            }
            sum = sum - nums[i];
            i++;
        } else if (j >= nums.length - 1) {
            break;
        } else {
            j++;
            sum = sum + nums[j];
        }

        if (i >= nums.length) {
            break;
        }
    }
    
    return  hasMin ?  minR - minL + 1 : 0;
};