滑动窗口算法总结及相关例题

简介: 滑动窗口算法总结及相关例题
这里标注一下,本文参考于 《labuladong的算法小抄》

1. 算法思想

1.1 思想

滑动窗口,顾名思义: 滑动的窗口,其实就是使用 双指针进行维护一个窗口。经过相关题目的练习,可以得出该窗口大小 有固定大小的例题,也有 不固定大小的例题。我们要根据相应的题目进行分析。而如果窗口是固定大小的,我们一般会根据 窗口大小要超越固定大小而进行 缩小窗口。而 不是固定大小的窗口的就根据题目具体意思进行相应的窗口缩小。

1.2 套路代码

int l = 0, r = 0;
while(r < s.length()){
    扩大窗口
    
    c是要添加进去的字符
   char c = s.charAt(r);
    r ++;
    
    这里进行相关的操作

    while(窗口需要缩小时){
        
        
        缩小窗口
        
        d是要从窗口中出去的字符
        char d = s.charAt(l);
        l ++;


        这里进行相关的操作
    }
}

相关模板讲解:

  1. 在这里我们使用的是双指针算法技巧,初始化 l = 0 ,r = 0
  2. 我们这里维护的区间窗口为[l,r)
  3. r 作为右指针进行扩大窗口,c 是放入窗口内部的字符
  4. l 作为左指针进行缩小窗口,d 是从窗口中去除的字符
  5. 那么其他需要加进来的代码就是题目要求我们维护的相应的数据结构,和维护该数据结构的相关操作了。看我博客的友友们要随机应变哦。

1.3例题精讲

1.3.1 最小覆盖子串

在这里插入图片描述
思路分析:

  1. 在扩大窗口的同时,我们需要维护什么?
因为题目要我们求的是包含相应模板串中的所有字符,那么相应的字符可能是分散于我们求出来的答案中的,所以我们需要去维护 一个名为need的map集合存下模板串的所有字符及个数。还要 一个名为win的map集合存下相应主串中滑动窗口中是上一个map集合中所包含的字符,还需要一个变量 valid存下 滑动窗口中和模板串中对应字符的个数相同的字符个数,因为是要求子串,所以还需要一个 start记录相应的起始下标, len记录相应的长度。
  1. 什么时候缩小窗口?
valid等于 need的大小时,就是相应的主串的滑动窗口包含模板串的所有字符了,此时需要缩小窗口。

3.在什么地方、什么时候更新startlen?

内层while中进行更新。当 len 小于 r - l时。

AC代码:

public String minWindow(String s, String t) {
        Map<Character,Integer> map = new HashMap<>();
        Map<Character,Integer> map2 = new HashMap<>();

        for(int i = 0; i < t.length(); i ++) map.put(t.charAt(i),map.getOrDefault(t.charAt(i),0) + 1);

        int l = 0, r = 0;
        int valid = 0;
        int start = 0, len = Integer.MAX_VALUE;

        while(r < s.length()){
            char c = s.charAt(r);
            r ++;

            if(map.containsKey(c)){
                map2.put(c,map2.getOrDefault(c,0) + 1);
                if(map.get(c).equals(map2.get(c))){
                    valid ++;
                }
            }

            while(valid == map.size()){
                if(r - l < len){
                    start = l;
                    len = r - l;
                }

                char d = s.charAt(l);
                l ++;
                if(map.containsKey(d)){
                    if(map.get(d).equals(map2.get(d))){
                        valid --;
                    }
                    map2.put(d,map2.get(d) - 1);
                }

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

特别提醒:

`Byte,Short,Integer,Long 这 4 种包装类默认创建了数值 [-128,127] 的相应类型的缓存数据,Character 创建了数值在 [0,127] 范围的缓存数据,Boolean 直接返回 True Or False。
两种浮点数类型的包装类 Float,Double 并没有实现常量池技术。`

所以如果是超出相应的范围,就不能使用 ==判断数值大小,而必须使用equals方法

1.3.2 找到字符串中所有字母异位词

在这里插入图片描述
思路分析:

  1. 题目分析
这是 窗口大小固定的相关例题。上面那一道是窗口大小不是固定的。
  1. 所需要维护的数据结构?
因为模板串的字符顺序和主串的不一定相同,所以 维护的数据结构和上面的一样。这里不再过多讲解。
  1. 什么时候缩小窗口?
因为是固定大小的窗口,所以一般是 窗口大小等于相应的窗口大小时先进行 是否符合要求判断,然后进行缩小窗口。

AC代码:

class Solution {
    List<Integer> list = new ArrayList<>();
    public List<Integer> findAnagrams(String s, String p) {
        Map<Character,Integer> need = new HashMap<>();
        Map<Character,Integer> win = new HashMap<>();

        // 初始化need
        for(int i = 0; i < p.length(); i ++) need.put(p.charAt(i),need.getOrDefault(p.charAt(i),0) + 1);

        int l = 0, r = 0;
        int valid = 0;
        while(r < s.length()){
            char c = s.charAt(r);
            r ++;

            
            if(need.containsKey(c)){
                win.put(c,win.getOrDefault(c,0) + 1);
                if(need.get(c).equals(win.get(c))){
                    valid ++;
                }
            }

            while(r - l >= p.length()){
                // 相应的操作
                if(valid == need.size()) list.add(l);

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

                if(need.containsKey(d)){
                    if(need.get(d).equals(win.get(d))){
                        valid --;
                    }
                    win.put(d,win.get(d) - 1);
                }
            }
        }
        return list;
    }
}

可以练手的相关题目:

567. 字符串的排列

这里对前面的滑动窗口问题进行总结:

前面的三个问题是难度比较高的三个滑动窗口问题,因为 他们的对应的模板串的字符在主串中相应位置不是固定的,所以我们使用 valid进行描述到达相应的标准,但是 我们需要对我们所确定的区间进行字符记录,且 记录的字符要是相应的模板串中含有的

2. 相关例题

后面的问题就相对比较简单:

2.1. 重复的DNA序列

在这里插入图片描述
思路分析:

  1. 题目分析
其实 定长是10,而又是相应的字符串,并且 不和前面相应的例题一样,他这相应的字符顺序截取的是什么就是什么,不需要改变。那么就可以直接根据 相应的substirng。但是就是需要统计出现的次数。
  1. 维护的数据结构
map集合。截取后存入 相应的map集合边放边存。然后根据条件进行判断。

AC代码:

class Solution {
    public List<String> findRepeatedDnaSequences(String s) {
        int L = 10;
        List<String> list = new ArrayList<>();

        Map<String,Integer> map = new HashMap<>();
        for(int i = 0; i <= s.length() - L; i ++){
            String a = s.substring(i,i + L);
            map.put(a,map.getOrDefault(a,0) + 1);
            if(map.get(a) == 2){
                // 为什么是== 2的时候,如果是大于2的话就会导致冗余情况
                list.add(a);
            }
        }
        return list;
    }
}

2.2. 存在重复元素 II

在这里插入图片描述
思路分析:

  1. 题目分析
这是 窗口大小固定的相关例题。上面那一道是窗口大小不是固定的。
  1. 维护的数据结构?
set 集合,因为需要判断在前面的区间中是否出现过,所以使用 set集合
  1. 缩小窗口的时机
因为这里维护的是 [i - k + 1,i]区间,所以当 set.size() > k的时候缩小窗口。

AC代码:

class Solution {
    public boolean containsNearbyDuplicate(int[] nums, int k) {
        Set<Integer> set = new HashSet<>();
        for(int i = 0; i < nums.length; i ++){
            // 相当于一个数字在前面的一段区间内只能出现一次
            // 每次遍历的时候加入set集合
            // 该步骤简化了判断在区间距离小于k + 1的情况下是否存在相同元素
            if(set.contains(nums[i])) return true;

            // 在这里进行添加的原因是前面已经判断过了,set集合中不存在相应的重复元素
            set.add(nums[i]);

            if(set.size() > k){
                // 但是set集合中的元素个数不能超过k + 1个
                set.remove(nums[i - k]);
            }
        }
        return false;
    }
}

220. 存在重复元素 III
在这里插入图片描述
思路分析:

  1. 题目分析
这里的思路和前面的相似。
  1. 注意点
但是就是我们这里需要说明的是 添加操作的相应的位置改变。因为 前面的那一道题是判断过集合不存在相应的元素,才进行添加。而我们这里没有。
if(ts.size() + 1 > k){
  ts.remove(nums[i - k] * 1L);
}
ts.add(nums[i] * 1L);

AC代码:

class Solution {
    public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {
        if(k == 0) return false;
        TreeSet<Long> ts = new TreeSet<>();

        for(int i = 0; i < nums.length; i ++){
            Long u = nums[i] * 1L;
            // TreeSet 是一个可以提供找到大于相应值的最小值 和 一个可以找到小于相应值的最大值的方法

            Long f = ts.floor(u);
            Long r = ts.ceiling(u);

            if(f != null && u - f <= t) return true;
            if(r != null && r - u <= t) return true;

            if(ts.size() + 1 > k){
                ts.remove(nums[i - k] * 1L);
            }
            ts.add(nums[i] * 1L);
        }
        return false;
    }
}

学到的新知识:

TreeSet : 一个可以提供 大于相应元素的最小值和一个可以提供 小于相应元素最大值的集合。
相关文章
|
5月前
|
机器学习/深度学习 监控 算法
员工上网行为监控软件中基于滑动窗口的C#流量统计算法解析​
在数字化办公环境中,员工上网行为监控软件需要高效处理海量网络请求数据,同时实时识别异常行为(如高频访问非工作网站)。传统的时间序列统计方法因计算复杂度过高,难以满足低延迟需求。本文将介绍一种基于滑动窗口的C#统计算法,通过动态时间窗口管理,实现高效的行为模式分析与流量计数。
115 2
|
3月前
|
存储 机器学习/深度学习 监控
公司电脑上网监控中滑动窗口算法的理论构建与工程实现
本文提出一种基于滑动窗口算法的实时网络流量监控框架,旨在强化企业信息安全防护体系。系统采用分层架构设计,包含数据采集、处理与分析决策三大模块,通过 Java 实现核心功能。利用滑动窗口技术动态分析流量模式,结合阈值检测与机器学习模型识别异常行为。实验表明,该方案在保证高检测准确率的同时支持大规模并发处理,为企业数字化转型提供可靠保障。
73 0
|
5月前
|
存储 机器学习/深度学习 监控
如何监控员工的电脑——基于滑动时间窗口的Java事件聚合算法实现探析​
在企业管理场景中,如何监控员工的电脑操作行为是一个涉及效率与合规性的重要课题。传统方法依赖日志采集或屏幕截图,但数据量庞大且实时性不足。本文提出一种基于滑动时间窗口的事件聚合算法,通过Java语言实现高效、低资源占用的监控逻辑,为如何监控员工的电脑提供一种轻量化解决方案。
112 3
|
6月前
|
存储 监控 算法
基于 PHP 语言的滑动窗口频率统计算法在公司局域网监控电脑日志分析中的应用研究
在当代企业网络架构中,公司局域网监控电脑系统需实时处理海量终端设备产生的连接日志。每台设备平均每分钟生成 3 至 5 条网络请求记录,这对监控系统的数据处理能力提出了极高要求。传统关系型数据库在应对这种高频写入场景时,性能往往难以令人满意。故而,引入特定的内存数据结构与优化算法成为必然选择。
125 3
|
算法
【算法】滑动窗口——最小覆盖子串
【算法】滑动窗口——最小覆盖子串
106 0
|
算法
【算法】滑动窗口——找到字符串中所有字母异位词
【算法】滑动窗口——找到字符串中所有字母异位词
158 0
|
算法
【算法】滑动窗口——将x减到0的最小操作数
【算法】滑动窗口——将x减到0的最小操作数
120 0
|
9月前
|
算法
|
算法 容器
【算法】滑动窗口——串联所有单词的子串
【算法】滑动窗口——串联所有单词的子串

热门文章

最新文章