【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]==0zeroCount++
    • zeroCount > k时,收缩窗口:

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

      • 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;
    }
}
相关推荐
qq_43350218几秒前
Codex cli 飞书文档创建进阶实用命令 + Skill 创建&使用 小白完整教程
java·前端·飞书
2301_8227032012 分钟前
Flutter 框架跨平台鸿蒙开发 - 创意声音合成器应用
算法·flutter·华为·harmonyos·鸿蒙
safestar201217 分钟前
ES批量写入性能调优:BulkProcessor 参数详解与实战案例
java·大数据·运维·jenkins
还在忙碌的吴小二24 分钟前
Harness 最佳实践:Java Spring Boot 项目落地 OpenSpec + Claude Code
java·开发语言·spring boot·后端·spring
风吹迎面入袖凉24 分钟前
【Redis】Redis的五种核心数据类型详解
java·redis
cmpxr_28 分钟前
【C】数组名、函数名的特殊
c语言·算法
夕除32 分钟前
javaweb--02
java·tomcat
ailvyuanj37 分钟前
2026年Java AI开发实战:Spring AI完全指南
java
KAU的云实验台38 分钟前
【算法精解】AIR期刊算法IAGWO:引入速度概念与逆多元二次权重,可应对高维/工程问题(附Matlab源码)
开发语言·算法·matlab