算法9,滑动窗口,长度最小的子数组

复制代码
public int minSubArrayLen(int target, int[] nums) {
        int left=0;
        int right=0;
        int sum=nums[left];
        if(sum>=target){
            return 1;
        }
        else right++;
        sum+=nums[right];
        int len=right-left+1;
        while(sum>=target){
            sum-=nums[left];
            left++;
            if(len<=right-left+1){
                len=right-left+1;
            }
            while (sum<target){
                right++;
                sum+=nums[right];
                if(len<=right-left+1){
                    len=right-left+1;
                }
                
            }
        }
        return len;
    }

其核心内容是 "长度最小的子数组"问题​ 的算法笔记。以下从题目分析、算法分析和代码编写三个方面进行总结:


题目分析

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

  • 输入 :一个正整数数组 nums,一个正整数 target

  • 输出:最小子数组的长度。

  • 示例 :笔记中以数组 [2,3,1,2,4,3]target = 7为例。符合条件的子数组有 [4,3][2,4,3],最小长度为 2。

算法分析

笔记中对比了两种解法:

  1. 暴力枚举法

    • 思路 :枚举所有可能的子数组(通过双重循环确定左右边界),计算每个子数组的和,判断是否 ≥ target并记录最小长度。

    • 缺点:时间复杂度为 O(n²)(若每次求和都重新计算,则为 O(n³)),效率低下。

  2. 滑动窗口(双指针)法(最优解)

    • 核心思想 :利用数组元素均为正数的单调性 ,使用两个同向移动的指针(leftright)构成一个窗口。通过动态调整窗口大小,在 O(n) 时间内找到最小窗口。

    • 步骤

      1. 初始化left = 0right = 0sum = 0minLen = 无穷大(如INT_MAX)

      2. 进窗口 :将 nums[right]加到 sum中,然后 right右移。

      3. 判断 :当 sum >= target时,说明当前窗口满足条件。

        • 更新结果 :计算当前窗口长度 right - left,并更新 minLen

        • 出窗口 :从 sum中减去 nums[left],然后 left右移,以尝试缩小窗口,寻找更小的满足条件的窗口。

      4. 重复步骤 2 和 3,直到 right到达数组末尾。

    • 优点:每个元素最多被访问两次(进窗口和出窗口各一次),时间复杂度为 O(n),空间复杂度为 O(1)。

代码编写

以下是修正和完善图片中代码逻辑后的 Java 实现:

复制代码
class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int n = nums.length;
        int left = 0;      // 窗口左边界
        int right = 0;     // 窗口右边界
        int sum = 0;       // 窗口内元素的和
        int minLen = Integer.MAX_VALUE; // 最小长度,初始化为最大值

        while (right < n) {
            // 1. 进窗口:右指针向右移动,扩大窗口
            sum += nums[right];
            
            // 2. 判断:当窗口内元素和满足条件时,尝试收缩窗口以找到更小的窗口
            while (sum >= target) {
                // 3. 更新结果:计算当前窗口长度并更新最小值
                int currentLen = right - left + 1;
                minLen = Math.min(minLen, currentLen);
                
                // 4. 出窗口:左指针向右移动,缩小窗口
                sum -= nums[left];
                left++;
            }
            
            // 继续移动右指针,扩大窗口
            right++;
        }
        
        // 如果 minLen 没有被更新过,说明没有符合条件的子数组,返回 0
        return (minLen == Integer.MAX_VALUE) ? 0 : minLen;
    }
}

代码说明

  1. 初始化leftright都从 0 开始,sum初始为 0,minLen初始为 Integer.MAX_VALUE

  2. 主循环while (right < n)控制右指针遍历整个数组。

  3. 进窗口 :每次循环先将当前 right指向的元素加入 sum

  4. 内层循环 :当 sum >= target时,说明当前窗口满足条件。此时:

    • 计算当前窗口长度 right - left + 1,并更新 minLen

    • 然后从 sum中减去 nums[left],并将 left右移一位,以尝试寻找更小的满足条件的窗口。

    • 这个内层循环会持续到 sum < target,确保我们找到了以当前 right为右边界的最小满足条件的窗口。

  5. 移动右指针 :内层循环结束后,right右移,继续探索下一个元素。

  6. 返回值 :如果 minLen从未被更新,则返回 0;否则返回 minLen

此解法是解决"长度最小的子数组"问题的标准滑动窗口方法,高效且易于理解。

相关推荐
Old Uncle Tom8 小时前
OpenClaw 记忆系统 -- 记忆预加载
java·数据结构·算法·agent
会编程的土豆8 小时前
洛谷题单入门1 顺序结构
数据结构·算法·golang
生信碱移8 小时前
PACells:这个方法可以鉴定疾病/预后相关的重要细胞亚群,作者提供的代码流程可以学习起来了,甚至兼容转录组与 ATAC 两种数据类型!
人工智能·学习·算法·机器学习·数据挖掘·数据分析·r语言
智者知已应修善业8 小时前
【51单片机中的打飞机设计】2023-8-25
c++·经验分享·笔记·算法·51单片机
圣保罗的大教堂10 小时前
leetcode 1855. 下标对中的最大距离 中等
leetcode
智者知已应修善业11 小时前
【51单片机按键调节占空比3位数码管显示】2023-8-24
c++·经验分享·笔记·算法·51单片机
JasmineX-111 小时前
数据结构(笔记)——双向链表
c语言·数据结构·笔记·链表
.54811 小时前
## Sorting(排序算法)
python·算法·排序算法
wuweijianlove12 小时前
算法的平均复杂度建模与性能回归分析的技术7
算法·数据挖掘·回归
子琦啊12 小时前
【算法复习】字符串 | 两个底层直觉,吃透高频题
linux·运维·算法