【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;
    }
}
相关推荐
Lueeee.2 小时前
v4l2驱动开发
数据结构·驱动开发·b树
开开心心就好2 小时前
音频编辑工具,多端支持基础剪辑易操作
java·网络·windows·java-ee·电脑·maven·excel
凯子坚持 c2 小时前
Protocol Buffers C++ 进阶数据类型与应用逻辑深度解析
java·服务器·c++
黎雁·泠崖2 小时前
Java面向对象:对象内存图+成员与局部变量
java·开发语言
窗边鸟2 小时前
小白日记之java方法(java复习)
java·学习
小饼干超人2 小时前
详解向量数据库中的PQ算法(Product Quantization)
人工智能·算法·机器学习
你撅嘴真丑3 小时前
第四章 函数与递归
算法·uva
漫随流水3 小时前
leetcode回溯算法(77.组合)
数据结构·算法·leetcode·回溯算法
砚边数影3 小时前
AI数学基础(一):线性代数核心,向量/矩阵运算的Java实现
java·数据库·人工智能·线性代数·矩阵·ai编程·金仓数据库