从何时你也忌讳空山无人,从何时开始|

Drunker•L

园龄:4个月粉丝:0关注:0

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

思路

1. 滑动窗口

滑动窗口是一种非常常用的技巧,尤其适用于数组或字符串问题,尤其是在求解“最小子数组”和、“最大子数组”等问题时。滑动窗口的基本思想是利用两个指针(通常是leftright)来维护一个窗口,然后根据问题的需求动态调整窗口的大小。它的优势在于不需要重新计算窗口内的每个元素,可以实现比暴力算法更高效的时间复杂度。

对于本题“最小长度子数组和大于等于目标值”的问题,我们考虑使用滑动窗口来优化暴力求解的方法。

滑动窗口的核心思路:

  • 窗口的定义:我们用两个指针leftright来定义一个滑动窗口,left是窗口的左边界,right是窗口的右边界。
  • 窗口内的元素和:随着right指针的移动,逐渐增大窗口,直到窗口内的和大于等于target。此时,我们尝试收缩窗口(通过移动left指针),看能否保持和大于等于target,并且尽量缩小窗口的大小。
  • 更新最小长度:每当窗口内的和满足条件时,我们记录当前窗口的长度,并更新最小长度。

具体设计过程:

  1. 初始化

    • left指针表示窗口的左边界,初始值设为0。
    • currentSum记录当前窗口的元素和,初始值设为0。
    • minLength记录最小子数组的长度,初始化为一个极大值(比如Integer.MAX_VALUE)。
  2. 扩展窗口

    • right指针从左到右扫描数组,每次扩展窗口时,加入nums[right]currentSum中。
  3. 收缩窗口

    • 一旦currentSum大于等于target,我们就尝试通过移动left指针来缩小窗口,直到currentSum小于target为止。在每次缩小窗口时,我们更新最小子数组的长度。
  4. 返回结果

    • 最终返回记录的最小子数组长度。如果没有找到满足条件的子数组,返回0。

代码实现:

public class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int n = nums.length;
        int minLength = Integer.MAX_VALUE;
        int currentSum = 0;
        int left = 0;
        
        for (int right = 0; right < n; right++) {
            // 扩展窗口,增加当前元素
            currentSum += nums[right];
            
            // 当窗口和大于等于目标值时,尝试收缩窗口
            while (currentSum >= target) {
                // 更新最小长度
                minLength = Math.min(minLength, right - left + 1);
                // 收缩窗口,减去左边界的元素
                currentSum -= nums[left];
                left++;
            }
        }
        
        return minLength == Integer.MAX_VALUE ? 0 : minLength;
    }
}

代码解释:

  1. 初始化

    • minLength用来记录最小子数组的长度,初始化为Integer.MAX_VALUE,表示暂时还没有符合条件的子数组。
    • currentSum记录当前窗口内的和。
    • left表示窗口的左边界。
  2. 扩展窗口

    • 我们通过right指针从左到右遍历数组,每次right向右移动时,将nums[right]加入currentSum中。
  3. 收缩窗口

    • 一旦currentSum大于等于target,就开始尝试通过left++来缩小窗口,减去左边界的元素,直到currentSum小于target
    • 在每次收缩窗口时,更新minLengthright - left + 1(即当前窗口的长度)。
  4. 结果返回

    • 如果minLength仍然是Integer.MAX_VALUE,说明没有找到符合条件的子数组,返回0。否则返回minLength

本文作者:Drunker•L

本文链接:https://www.cnblogs.com/drunkerl/p/18658242

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Drunker•L  阅读(8)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起