长度最小子数组(Java、滑动窗口)

题目

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

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

 

解题思路

利用滑动窗口求解。
先设置两个指针,都初始化为 0 ,分别记录子数组的头部和尾部,for 循环遍历数组,并控制右指针 R 的移动,内嵌 while 循环控制左指针 L 的移动,在移动过程中比较 len 和 R - L + 1 的值的大小,将较小值赋值给 len ,当 len == 1 时,可以直接返回并退出循环。

代码如下:

public static int minSubArrayLen(int[] nums, int target) {
        // 空数组直接返回 0 
        if(nums == null) return 0;
        
        int L = 0, R = 0;
        int len = Integer.MAX_VALUE;
        int num = 0;
        // 以右指针 R 遍历数组
        for(;R < nums.length; R++) {
            // 每循环一次就将右指针指向的元素加到 num 中,再和 target 比较,
            // 若是小于 target ,则直接进入下一循环
            num += nums[R];
            if(num < target) continue;
            // 否则比较 len 和 R - L + 1 的大小,将较小的值赋值给 len
            else {
                len = R - L + 1 < len ? R - L + 1 : len;
                // 内嵌一个循环,当 num >= target 时,num 减去左指针 L 指向的元素,同时左指针向右移动一位
                while(num >= target) {
                    num -= nums[L];
                    L++;
                    // 如果 len 的值大于  R - L + 1 的值,则将 R - L + 1 的值赋值给 len ,否则不操作
                    // 注意这里不能直接 len--,否则在特殊情况下会出现 len = 0 的错误结果
                    if(num >= target && len > R - L + 1) len = R - L + 1;
                }
            }
            // len == 1 可以直接返回
            if(len == 1) return len;
        }
        // len 的值没有变化说明没有匹配的长度最小数组,返回 0
        if(len == Integer.MAX_VALUE) return 0;
        return len;
    }

优化思路

我们可以尝试逆向思维,前面我们是将数组元素相加再和 target 进行比较,现在我们反过来,直接用 target 减去数组中的元素,然后和 0 比较大小。

R++ 和 L++ 放到 nums[ ] 里,使用条件表达式代替判断语句,使得代码更加简洁。

代码如下:

public static int minSubArrayLen(int[] nums, int target) {
        int L = 0, R = 0, min = Integer.MAX_VALUE;
        while(R < nums.length) {
            target -= nums[R++];
            while(target <= 0) {
                min = R - L < min ? R - L : min;
                target += nums[L++];
            }
        }
        return min == Integer.MAX_VALUE ? 0 : min;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值