【LeetCode精选算法】滑动窗口专题一

目录

[9. 长度最小的子数组(209. Minimum Size Subarray Sum)](#9. 长度最小的子数组(209. Minimum Size Subarray Sum))

[10. 无重复字符的最长子串(3. Longest Substring Without Repeating Characters)](#10. 无重复字符的最长子串(3. Longest Substring Without Repeating Characters))

[11. 最大连续1的个数 III(1004. Max Consecutive Ones III)](#11. 最大连续1的个数 III(1004. Max Consecutive Ones III))

[12. 将x减到0的最小操作数(1658. Minimum Operations to Reduce X to Zero)](#12. 将x减到0的最小操作数(1658. Minimum Operations to Reduce X to Zero))


1. 长度最小的子数组(209. Minimum Size Subarray Sum)

题目链接 :LeetCode 209

详细解题思路:

  1. 核心思想:滑动窗口(同向双指针)

  2. 具体步骤:

    • 初始化left=0, right=0, sum=0, minLen=∞

    • 右指针right向右扩展窗口,累加sum

    • 当sum ≥ target时:

      • 更新minLen

      • 左指针left向右收缩窗口,直到sum < target

    • 重复直到right到达数组末尾

  3. 时间复杂度:O(n),每个元素最多被访问两次

  4. 空间复杂度:O(1)

java 复制代码
class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int left = 0, right = 0;
        int sum = 0;
        int minLength = Integer.MAX_VALUE;
        
        while (right < nums.length) {
            // 扩展窗口:右指针右移
            sum += nums[right];
            
            // 收缩窗口:当窗口和≥target时,尝试缩小窗口
            while (sum >= target) {
                // 更新最小长度
                minLength = Math.min(minLength, right - left + 1);
                
                // 收缩窗口:左指针右移
                sum -= nums[left];
                left++;
            }
            
            // 继续扩展窗口
            right++;
        }
        
        // 如果没找到符合条件的子数组,返回0
        return minLength == Integer.MAX_VALUE ? 0 : minLength;
    }
}

2. 无重复字符的最长子串(3. Longest Substring Without Repeating Characters)

题目链接 :LeetCode 3

详细解题思路:

  1. 核心思想:滑动窗口 + 哈希表记录字符出现次数

  2. 具体步骤:

    • 初始化left=0, right=0,哈希数组hash[128]

    • 右指针right向右扩展,对应字符计数加1

    • 当某个字符计数>1时,说明出现重复:

      • 左指针left向右移动,直到重复字符的计数降为1

      • 同时更新哈希表

    • 每次循环更新最大长度

  3. 优化:可以用哈希表记录字符最后出现的位置,直接跳转到重复字符的下一位

  4. 时间复杂度:O(n),空间复杂度:O(字符集大小)

java 复制代码
class Solution {
    public int lengthOfLongestSubstring(String s) {
        // 哈希表,记录每个字符出现的次数
        int[] hash = new int[128];
        int left = 0, right = 0;
        int maxLength = 0;
        
        while (right < s.length()) {
            // 右指针字符进入窗口
            char inChar = s.charAt(right);
            hash[inChar]++;
            
            // 如果当前字符出现次数>1,说明有重复
            while (hash[inChar] > 1) {
                // 左指针字符移出窗口
                char outChar = s.charAt(left);
                hash[outChar]--;
                left++;
            }
            
            // 更新最大长度
            maxLength = Math.max(maxLength, right - left + 1);
            
            // 右指针右移
            right++;
        }
        
        return maxLength;
    }
}

3. 最大连续1的个数 III(1004. Max Consecutive Ones III)

题目链接 :LeetCode 1004

详细解题思路:

  1. 核心思想:滑动窗口,维护窗口内0的个数≤k

  2. 问题转化:求最长子数组,其中0的个数不超过k

  3. 具体步骤:

    • 初始化left=0, right=0, zeroCount=0

    • 右指针right扩展窗口:

      • 如果nums[right]==0,zeroCount++
    • 当zeroCount > k时,收缩窗口:

      • 如果nums[left]==0,zeroCount--

      • left++

    • 更新最大窗口长度

  4. 时间复杂度:O(n),空间复杂度:O(1)

java 复制代码
class Solution {
    public int longestOnes(int[] nums, int k) {
        int left = 0, right = 0;
        int zeroCount = 0;  // 窗口内0的个数
        int maxLength = 0;
        
        while (right < nums.length) {
            // 右指针扩展窗口
            if (nums[right] == 0) {
                zeroCount++;
            }
            
            // 如果0的个数超过k,收缩窗口
            while (zeroCount > k) {
                if (nums[left] == 0) {
                    zeroCount--;
                }
                left++;
            }
            
            // 更新最大长度
            maxLength = Math.max(maxLength, right - left + 1);
            
            // 右指针右移
            right++;
        }
        
        return maxLength;
    }
}

4. 将x减到0的最小操作数(1658. Minimum Operations to Reduce X to Zero)

题目链接 :LeetCode 1658

详细解题思路:

  1. 核心思想:问题转化 + 滑动窗口

  2. 问题转化:

    • 移除数组两端元素,使和为x

    • 等价于:找到数组中间最长的子数组,使其和为sum - x

    • 最小操作数 = n - 最长子数组长度

  3. 具体步骤:

    • 计算数组总和totalSum

    • 目标子数组和target = totalSum - x

    • 如果target < 0,直接返回-1

    • 使用滑动窗口找到和为target的最长子数组

  4. 边界情况:

    • 如果target == 0,需要移除整个数组

    • 如果找不到和为target的子数组,返回-1

  5. 时间复杂度:O(n),空间复杂度:O(1)

java 复制代码
class Solution {
    public int minOperations(int[] nums, int x) {
        int totalSum = 0;
        for (int num : nums) {
            totalSum += num;
        }
        
        int target = totalSum - x;
        // 如果目标值小于0,不可能实现
        if (target < 0) return -1;
        // 如果目标值等于0,需要移除所有元素
        if (target == 0) return nums.length;
        
        int left = 0, right = 0;
        int currentSum = 0;
        int maxSubarrayLength = -1;
        
        while (right < nums.length) {
            // 扩展窗口
            currentSum += nums[right];
            
            // 收缩窗口:如果当前和大于目标值
            while (currentSum > target && left <= right) {
                currentSum -= nums[left];
                left++;
            }
            
            // 如果找到目标子数组,更新最大长度
            if (currentSum == target) {
                maxSubarrayLength = Math.max(maxSubarrayLength, right - left + 1);
            }
            
            // 右指针右移
            right++;
        }
        
        // 如果没找到符合条件的子数组
        if (maxSubarrayLength == -1) return -1;
        
        // 最小操作数 = 总长度 - 最长子数组长度
        return nums.length - maxSubarrayLength;
    }
}
相关推荐
时间静止不是简史4 小时前
生产事故排查:Redis 宕机导致补偿队列消费线程死亡,通话录音未上送业务平台
java·redis
2301_32241428047 小时前
基于SpringBoot+Vue的休闲零食超市管理系统的设计与实现59004-计算机毕设 原创(免费领源码+部署教程+开发环境)
java·vue.js·spring boot·redis·mysql·决策树·推荐算法
徐小夕9 小时前
花了3个月,我们做了一款 AI 版的“飞书文档”
前端·算法·github
Robert--cao9 小时前
移动底盘与机械臂联合规划:开源算法与工程实现
算法
金銀銅鐵9 小时前
[Java] 用 GUI 展示 EnumSet 增减元素时的内部变化(上)
java·后端·ai编程
福建佰胜张工10 小时前
SMC 薄型气爪 MHF2-16D1 深度解析:平行开闭、低剖面结构在自动化装配中的选型与落地
java·服务器·安全·自动化
小豆庄10 小时前
Mac 上给视频人脸打码:本地工具的依赖、追踪与推理管线
算法·视觉检测·视频·敏捷流程·纹理贴图
catoop10 小时前
API Key 设计与安全生成方案:结构拆解、数据库设计与 Java 实现
java·数据库·安全
星夜离尘5610 小时前
MATLAB 工程实验:从相邻块均值手写重叠 Allan 偏差,数清有效项
算法·matlab·均值算法
system_error_x10 小时前
SpringBoot 集成 Thymeleaf 简洁入门
java·spring boot·后端