【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;
    }
}
相关推荐
_OP_CHEN5 小时前
【算法基础篇】(五十七)线性代数之矩阵乘法从入门到实战:手撕模板 + 真题详解
线性代数·算法·矩阵·蓝桥杯·c/c++·矩阵乘法·acm/icpc
天天爱吃肉82185 小时前
【跨界封神|周杰伦×王传福(陶晶莹主持):音乐创作与新能源NVH测试,底层逻辑竟完全同源!(新人必看入行指南)】
python·嵌入式硬件·算法·汽车
im_AMBER5 小时前
Leetcode 114 链表中的下一个更大节点 | 删除排序链表中的重复元素 II
算法·leetcode
考琪5 小时前
Nginx打印变量到log方法
java·运维·nginx
xhbaitxl5 小时前
算法学习day38-动态规划
学习·算法·动态规划
多恩Stone5 小时前
【3D AICG 系列-6】OmniPart 训练流程梳理
人工智能·pytorch·算法·3d·aigc
wangjialelele5 小时前
Linux中的进程管理
java·linux·服务器·c语言·c++·个人开发
历程里程碑5 小时前
普通数组----轮转数组
java·数据结构·c++·算法·spring·leetcode·eclipse
pp起床5 小时前
贪心算法 | part02
算法·leetcode·贪心算法
sin_hielo5 小时前
leetcode 1653
数据结构·算法·leetcode