【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;
    }
}
相关推荐
李少兄39 分钟前
Java 中只有值传递吗?
java·开发语言·python
名字还没想好☜1 小时前
Spring @EventListener 事件驱动解耦实战:同步转异步、事务绑定与顺序控制
java·数据库·后端·python·spring
果壳science1 小时前
《自然本源》如何实现狭义相对论的代数化
笔记·算法·几何学
一木 之林1 小时前
插件、MCP、Skill 的区别?
java·c++·人工智能
suhan1 小时前
【数据结构】二、线性表:2.单链表的定义与实现(带头结点与不带头结点的区别)
数据结构
小刘在重生~1 小时前
面试重点:final、finalize、finally 三者区别
java
边境悍匪2 小时前
蜗牛学苑 Java 智能体学习 Day39|SpringAI 会话存储、Function‑Call 工具调用、MCP 思维导图复盘
java·开发语言·spring boot·学习·阿里云
302wanger2 小时前
分享一个工作习惯:整点看即时消息
算法
letisgo52 小时前
JAVA 高级进阶02篇《并发编程三板斧:JMM、CAS与AQS的源码级拆解》
java·面试·并发编程·aqs·jmm
胡写代码2 小时前
若依 + MyBatis-Plus,分页为什么悄悄失效了?
java·后端