leecodecode【滑动窗口】【2026.5.27打卡-java版本】

长度最小的子数组

给定一个含有 n个正整数的数组和一个正整数 target

找出该数组中满足其总和大于等于target的长度最小的 子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度**。** 如果不存在符合条件的子数组,返回 0

要点: 同向的滑动窗口,先找到right,再left缩小尝试

java 复制代码
class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        //滑动窗口
        int left = 0;
        int right = 0;
        int sum = 0;
        int ans = nums.length + 1;
        while(right < nums.length){
            sum += nums[right];
            while(sum-nums[left] >= target ){
                sum = sum - nums[left];
                left++;
            }

            if(sum >= target){
                ans = Math.min(ans, right - left +1);
            }
            right++;
        }

        return ans == nums.length +1 ? 0 : ans;
    }
}

乘积小于 K 的子数组

要点,和上面差不多,ans += right - left +1;

java 复制代码
class Solution {
    public int numSubarrayProductLessThanK(int[] nums, int k) {
        //同向双指针
        int left = 0;
        int right = 0;
        int n = nums.length;
        int sum = 1;
        int ans = 0;
        for(int i = 0; i < n; i++){
            sum *= nums[i];
            while(left <= i && sum >= k){
                sum = sum/nums[left];
                left++;
            }

            ans += i -left +1;

        }

        return ans;
        
    }
}

无重复字符的最长子串

要点:set去重,也是找到right,然后移除left

java 复制代码
class Solution {
    public int lengthOfLongestSubstring(String s) {
        //set和滑动窗口
        Set<Character> temp = new HashSet<>();

        int left = 0;
        int right = 0;
        int n = s.length();
        int ans = 0;
        while(right < n){
            char c = s.charAt(right);
            if(!temp.contains(c)){
                temp.add(c);
                right++;
            }else{
                char remove = s.charAt(left);
                temp.remove(remove);
                left++;
            }
            ans = Math.max(ans, temp.size());
        }

        return ans;
        
    }
}

最小覆盖子串

要点:need数组,required数组,valid,start

一句话总结:用双指针滑动窗口,右指针扩展至包含 t 的所有字符(按需计数),再收缩左指针以缩小窗口,同时记录最短合法子串。

java 复制代码
class Solution {
    public String minWindow(String s, String t) {
        if(s == null || t == null || s.length() < t.length()){
            return "";
        }

        //统计t中每个字符的需求次数
        int[] need = new int[128];
        for(char c : t.toCharArray()){
            need[c]++;
        }

        //没顺序要求,就是包含就行
        int required = 0;
        for(int count : need){
            if(count > 0){
                required++;
            }
        }

        int[] window = new int[128];
        int left = 0;
        int right = 0;
        int valid = 0;
        int min = Integer.MAX_VALUE;
        int start = 0;

        for(int i = 0; i < s.length(); i++){
            char c = s.charAt(i);

            //更新window 和 valid
            if(need[c] > 0){
                window[c]++;
                if(window[c] == need[c]){
                    valid++;
                }
            }

            //达到要求则开始收缩
            while(valid == required){
                if(i - left < min ){
                    min = i - left +1;
                    start = left;
                }

                char d = s.charAt(left);
                left++;

                if(need[d] > 0){
                    if(window[d] == need[d]){
                        valid --;
                    }
                    window[d] --;
                }
            }
        }

        return min == Integer.MAX_VALUE ? "" : s.substring(start, start+min);
        
    }
}

随机知识

双指针(Two Pointers)完整总结

一、什么是双指针

使用两个指针(下标/迭代器)遍历数据结构,通过指针的移动策略高效解决问题。时间复杂度通常 O(n) 或 O(n log n)(含排序)。

二、四种经典模式

模式 指针移动方向 典型特征 代表题目
同向双指针(滑动窗口) 都从左向右,一快一慢 维护连续窗口,满足某种条件 无重复最长子串、最小覆盖子串
对向双指针(左右夹逼) 一左→右,一右→左 有序数组或两端逼近求极值 两数之和II、三数之和、盛水容器
快慢指针 速度不同,同一序列 检测环、找中点、找重复数 环形链表、寻找重复数
分离双指针 各自在不同序列上 比较/归并两个有序数组/字符串 判断子序列、合并有序数组

注意:滑动窗口只是同向双指针的一种,不要把对向双指针也叫做滑动窗口。

三、各模式模板与例题

1. 对向双指针(左右夹逼)

适用:有序数组求两数和/三数和、最大面积、接雨水等。

模板(两数之和 II)

python

复制代码
left, right = 0, len(arr) - 1
while left < right:
    s = arr[left] + arr[right]
    if s == target:
        return [left+1, right+1]
    elif s < target:
        left += 1
    else:
        right -= 1

模板(三数之和)

python

复制代码
arr.sort()
res = []
for i in range(n-2):
    if i > 0 and arr[i] == arr[i-1]: continue
    left, right = i+1, n-1
    while left < right:
        s = arr[i] + arr[left] + arr[right]
        if s == 0:
            res.append([arr[i], arr[left], arr[right]])
            while left < right and arr[left] == arr[left+1]: left += 1
            while left < right and arr[right] == arr[right-1]: right -= 1
            left += 1; right -= 1
        elif s < 0:
            left += 1
        else:
            right -= 1

典型题目

  • 167.两数之和II(有序数组)

  • 15.三数之和

  • 11.盛最多水的容器(移动高度较小的指针)

  • 42.接雨水(双指针法:维护左右最大高度)

2. 同向双指针(滑动窗口)

详细见独立笔记,此处只给快速识别:要求连续子串/子数组 + 条件 + 最优值

模板骨架

python

复制代码
left = 0
for right in range(n):
    加入nums[right]
    while 不满足条件:
        移除nums[left]
        left += 1
    更新答案(此时窗口满足条件)

3. 快慢指针

适用:链表/数组判环、找环入口、找中点、找重复数。

模板(链表判环)

python

复制代码
slow = fast = head
while fast and fast.next:
    slow = slow.next
    fast = fast.next.next
    if slow == fast:
        return True

4. 分离双指针(双序列)

适用:判断子序列、合并两个有序数组。

模板(判断子序列)

python

复制代码
i = j = 0
while i < len(s) and j < len(t):
    if s[i] == t[j]:
        i += 1
    j += 1
return i == len(s)

四、快速判断表(遇到题目对照)

题目关键词 双指针类型
连续子数组/子串 + 条件 + 最长/最短 同向(滑动窗口)
有序数组 + 两数和/三数和 对向
最大面积(垂线) 对向
接雨水 对向 或 单调栈
判断子序列 分离
链表有环/环入口 快慢
数组原地去重/移除元素 同向(快慢变种)

五、常见误区

  • 接雨水:对向双指针(不是滑动窗口)

  • 盛最多水的容器:对向双指针

  • 判断子序列:分离双指针

  • 两数之和II:对向双指针

  • 三数之和:对向双指针(需先排序)

六、刷题顺序建议

  • 对向:167 → 11 → 15 → 42

  • 同向(滑动窗口):3 → 209 → 76

  • 分离:392 → 88

  • 快慢:141 → 142 → 287

167.两数之和2

要点:双指针

复制代码
class Solution {
    public int[] twoSum(int[] numbers, int target) {
        //有序 - 找两个数
        int left = 0;
        int right = numbers.length -1;
        
        while(left < right){
            int sum = numbers[left] + numbers[right];
            if(sum == target){
                break;
            }else if(sum < target){
                left++;
            }else{
                right--;
            }
        }
 
        return new int[]{left+1, right+1};
    }
}
三数之和

要点:双指针+去重,i里面直接continue跳过

复制代码
class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        //a + b+ c = 0
        List<List<Integer>> ans = new ArrayList<>();
        Arrays.sort(nums);
        int n = nums.length;
        for(int i = 0; i < n-2; i++){
           
            if(i != 0 && nums[i-1] ==nums[i]){
                //不能修改i
                continue;
            }
            int a = nums[i];
 
            int left = i+1;
            int right = n -1;
 
            while(left < right){
                int sum = a + nums[left] +nums[right];
                if(sum == 0){
                    ans.add(new ArrayList<>(Arrays.asList(a,nums[left], nums[right])));
                    //ans.add(new ArrayList<>(Arrays.asList(a, left, right)));
                    left++;
                    right--;
                    while(left < right && nums[left] == nums[left -1]){
                        left++;
                    }
 
                    while(left < right && nums[right] == nums[right+1]){
                        right--;
                    }
                }else if(sum < 0){
                    left++;
                }else{
                    right--;
                }
 
 
            }
 
 
 
        }
 
        return ans;
 
    }
}

滑动窗口

复制代码
维护一个窗口,
left。right
​
​

滑动窗口(Sliding Window)总结

一、什么时候用滑动窗口?

触发条件(同时满足)

  1. 处理线性结构:数组、字符串

  2. 要求连续子序列/子数组/子串

  3. 最优值:最长、最短、恰好、包含、覆盖、最大和等

快速判断口诀:连续区间问最优,条件变化可滑走

二、怎么用?三步固定框架

python

复制代码
left = 0
for right in range(n):
    # 1. 移入右指针元素,更新窗口状态
    add(nums[right])
    
    # 2. 当窗口不满足条件时,移动左指针直到重新满足
    while 窗口不满足题目条件:
        remove(nums[left])
        left += 1
    
    # 3. 此时窗口满足条件,更新答案(最长/最短/计数等)
    更新答案

关键定义

  • 窗口满足条件:如"窗口内无重复字符"、"窗口内元素和 ≥ target"

  • 窗口不满足条件:需要移出左边元素直到再次满足

三、两大常见分支速查表

类型 典型题目 窗口调整核心
固定窗口大小 大小为k的子数组最大和 先构建k窗口,之后每次右移一步,左边同步移出
可变窗口(求最长) 无重复字符的最长子串 遇到违反条件 → 缩小左边界直到满足 → 更新最长
可变窗口(求最短) 和≥target的最短子数组 满足条件时 → 尝试缩小左边界找更短 → 更新最短
计数类(含模式) 最小覆盖子串 用need/have计数器,满足全部种类后收缩左边界

记忆提示

  • 求最长:右移后更新

  • 求最短:左移后(收缩时)更新

四、经典例题演练(无重复字符的最长子串)

输入s = "abcabcbb" 输出:3

过程模拟(理解核心):

  1. [a] → 无重复 → 最长=1

  2. [ab] → 无重复 → 最长=2

  3. [abc] → 无重复 → 最长=3

  4. a → 出现重复 → 左移直到无重复 → [bca] → 最长仍为3

  5. 继续扫描,最终最长=3

时间复杂度:O(n)(每个元素最多进出窗口各一次)

五、从"不会"到"会"的训练方法

遇到新题问自己

  • 是连续子串/子数组吗? 不是 → 换方法(DP、二分等)

  • 答案与长度/和/覆盖有关吗? 是 → 滑动窗口候选

  • 窗口变化有明确条件吗? 有 → 滑动窗口

刻意练习步骤

  1. 先写框架(while结构),不纠结细节

  2. 口述:为什么用滑动窗口?什么时候右移?什么时候左移?

  3. 改题目条件,推理窗口变化(如"最长无重复" → "最多重复一次")

六、推荐必做题目(按难度顺序)

  1. LeetCode 3:无重复字符的最长子串

  2. LeetCode 209:长度最小的子数组

  3. LeetCode 76:最小覆盖子串(较难,但完全符合框架)

碎碎念:后续会更新每天学习的八股和算法 题,开始准备秋招的第17天。努力连续更新100天!以后每天就按,秋招项目【java+agent】,科研,必做项目,算法,八股,锻炼身体来总结。

总结:不要放弃呀,

1.算法要系统过一遍【灵神】3/27【早上加晚上】

2.秋招项目,【java】开始实际看业务,2.5/10;【agent】还在学,决定把helloagent看一遍,3/16

3.科研要跑一下,无

4.检测项目也得总结文档,无,

5.训练项目看看先选择好,4小时,但是还没搞清楚+测试视频1小时【下午】

6.背八股,无

7.锻炼身体,无

不要再熬夜了!!

【保持心态,持续努力】

相关推荐
曹牧2 小时前
C#:基类中定义泛型方法
java·开发语言·c#
Brilliantwxx2 小时前
【算法题】 面试级别的二叉树题目OJ复习(上)
数据结构·c++·笔记·算法·面试
颖火虫盟主2 小时前
Conan C++ 包管理工具深度解析
java·jvm·c++
Devin~Y2 小时前
大厂 Java 面试实录:Spring Boot微服务/Kafka/Redis/K8s可观测性 + RAG Agent(小Y社死版)
java·spring boot·redis·spring cloud·kafka·kubernetes·micrometer
摇滚侠2 小时前
Java 零基础全套教程,IDEA 开发工具,笔记 59-61
java·笔记·intellij-idea
Run_Teenage2 小时前
算法:图的存储与遍历,最小生成树(Prim算法,kruskal算法)
算法·深度优先·图论
曹牧2 小时前
Eclipse:代码块折叠
java·ide·eclipse
WWTYYDS_6662 小时前
手写 C++ Any 类:深入理解多态与模板
开发语言·c++·算法
玉树临风ives2 小时前
atcoder ABC 459 题解
算法