四、滑动窗口-算法总结

news2024/11/16 7:35:20

文章目录

  • 四、滑动窗口
    • 4.1 模板
    • 4.2 示例
      • 4.2.1 最小覆盖子串
      • 4.2.2 字符串的排列
      • 4.2.3 找到字符串中所有字母异位词
      • 4.2.4 无重复字符的最长子串

四、滑动窗口

4.1 模板

/* 滑动窗口算法框架 */
void slidingWindow(string s, string t) {
    unordered_map<char, int> need, window;
    for (char c : t) need[c]++;

    int left = 0, right = 0;
    int valid = 0;
    while (right < s.size()) {
        // c 是将移入窗口的字符
        char c = s[right];
        // 右移窗口
        right++;
        // 进行窗口内数据的一系列更新
        ...

        // 判断左侧窗口是否要收缩
        while (window needs shrink) {
            // d 是将移出窗口的字符
            char d = s[left];
            // 左移窗口
            left++;
            // 进行窗口内数据的一系列更新
            ...
        }
    }
}

需要变化的地方

  • 1、右指针右移之后窗口数据更新
  • 2、判断窗口是否要收缩
  • 3、右指针右移之后窗口数据更新
  • 4、根据题意计算结果

4.2 示例

4.2.1 最小覆盖子串

76. 最小覆盖子串
在这里插入图片描述

// 使用Map的存储方式
class Solution {
    public String minWindow(String s, String t) {
        // 1、创建用于保存滑动窗口包含的字符集的map
        Map<Character,Integer> winChars =  new HashMap<>();
        // 2、创建保存子串中的字符集的map(注意重复的字符会累计次数)
        Map<Character,Integer> tChars = new HashMap<>();
        Integer temp;
        for(char c:t.toCharArray()){
            tChars.put(c,(temp=tChars.get(c)) == null?1:(temp+1));
        }

        int tCharNum = tChars.size(); // 子串中不同字符的个数
        int winCharNum = 0; // 滑动窗口中已匹配子串字符的个数(相同的字符要个数上匹配)
        int i = 0,j = 0; // 定义滑动窗口的左右边界
        int start = 0,end = 0; // 定义最终的滑动窗口的左右边界(即:最小尺寸的滑动窗口)
        int minWinLength = Integer.MAX_VALUE; // 初始化最小的滑动窗口值

        // 基于滑动窗口
        //先右移右指针直至包含所有的子串中的字符集, 再进行滑动窗口左边界右移
        while(j < s.length()){
            char c = s.charAt(j);
            if(tChars.get(c) != null){ // 若是子串中的字符, 记录当前的字符
                winChars.put(c,(temp=winChars.get(c)) == null?1:(temp+1));
                if(winChars.get(c).equals(tChars.get(c))){ // 判断是否已经有字符被完全匹配完(个数)
                    winCharNum++;
                }
            }
            j++; // 右移滑动窗口,注意此处操作会指向最小窗口右边界的下一个位置(由于字符子串获取是左闭右开)
            
            // 右移左边界(即:滑动窗口中已匹配完所有的子串字符)
            while(winCharNum == tCharNum){
                // 记录当前的滑动窗口长度
                if(j - i < minWinLength){
                    start = i;
                    end = j;
                    minWinLength = j - i;
                }

                char leftChar = s.charAt(i);
                if(tChars.get(leftChar) != null){ // 若右移左边界排除了一个子串中的字符
                    if(winChars.get(leftChar).equals(tChars.get(leftChar))){ // 该字符刚好个数完全匹配,则右移左边界会使总匹配个数减一
                        // 也可能滑动窗口中匹配的字符个数大于子串中该字符的个数
                        winCharNum--;
                    }
                    winChars.put(leftChar,winChars.get(leftChar)-1); // 更新滑动窗口中的字符集
                }
                i++;
            }
        }
        if(minWinLength == Integer.MAX_VALUE){ // 若没有更新,则返回空串
            return "";
        }
        return s.substring(start,end);
    }
}

// 使用数组的存储方式
class Solution {
public String minWindow(String s, String t) {
    // 技巧:用数组代替Map
    // 保存滑动窗口字符集
    int[] winMap = new int[256];
    // 保存需要出现的字符集
    int[] tMap = new int[256];
    for (char c : t.toCharArray()) {
        tMap[c]++;
    }
    // 计算共出现了多少不同的字符
    int charNum = 0;
    for (int n : tMap) {
        if (n > 0) {
            charNum++;
        }
    }
    // 滑动窗口左右边界
    int left = 0;
    int right = 0;
    // 匹配数
    int match = 0;
    // 窗口调整前暂存原窗口边界
    int start = 0;
    int end = 0;
    // 窗口长度的最小值
    int minValue = Integer.MAX_VALUE;
    while (right < s.length()) {
        char c = s.charAt(right);
        // 在需要的字符集里面,添加到窗口字符集里面
        if (tMap[c] != 0) {
            winMap[c]++;
            // 如果当前字符的数量匹配需要的字符的数量,则match值+1
            if (tMap[c] == winMap[c]) {
                match++;
            }
        }
        right++;
        // 当所有字符数量都匹配之后,开始缩紧窗口
        while (match == charNum) {
            // 获取结果
            if (right - left < minValue) {
                minValue = right - left;
                start = left;
                end = right;
            }
            char leftChar = s.charAt(left);
            // 左指针指向不在需要字符集则直接跳过
            if (tMap[leftChar] != 0) {
                // 左指针指向字符数量和需要的字符相等时,右移之后match值就不匹配则减一
                if (winMap[leftChar] == tMap[leftChar]) {
                    match--;
                }
                winMap[leftChar]--;
            }
            left++;
        }
    }
    if (minValue == Integer.MAX_VALUE) {
        return "";
    }
    return s.substring(start, end);
}
}

4.2.2 字符串的排列

567. 字符串的排列
在这里插入图片描述

// 使用数组的存储方式
class Solution {
    public boolean checkInclusion(String s1, String s2) {
        // 创建保存滑动窗口中字符集的数组
        int[] wChars = new int[256];
        // 创建保存子串字符集的数组(累计字符个数)
        int[] tChars = new int[256];

        // 记录子串的字符
        for(char c:s1.toCharArray()){
            tChars[c]++;
        }
        int tCharNum = 0; // 子串不同字符的个数 
        for(int i:tChars){
            if(i>0){
                tCharNum++;
            }
        }

        int left = 0,right = 0; // 滑动窗口的左右边界
        int winCharNum = 0; // 记录滑动窗口中匹配字符的数量(具有多个相同字符需要被匹配完)

        // 滑动窗口算法
        // 先右移有边界直至窗口内匹配完所有子串字符,接着做一左边界
        while(right < s2.length()){
            char c = s2.charAt(right);
            if(tChars[c] != 0){
                wChars[c]++; // 记录当前字符
                if(wChars[c] == tChars[c]){ // 对某一个字符完全匹配后记录数量
                    winCharNum++;
                }
            }
            right++; // 此时right指向窗口右边界的右边一个位置

            // 右移左边界
            while(winCharNum == tCharNum){
                c = s2.charAt(left);
                if(tChars[c] != 0){
                    if(wChars[c] == tChars[c]){ // 若当前字符数刚好等于子串中该字符的数量,则再减少一个就减少匹配数
                        winCharNum--;
                        if(right - left == s1.length()){ // 若窗口长度等于子串长度则为排列匹配
                            return true;
                        }
                    }
                    // 更新窗口中字符的信息
                    wChars[c]--;
                }
                left++;
            }
        }
        return false;


    }
}

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

438. 找到字符串中所有字母异位词
在这里插入图片描述

class Solution {
    public List<Integer> findAnagrams(String s, String p) {
        // 创建保存窗口中字符集的数组
        int[] wChars = new int[256];
        // 创建保存子串的字符集信息(累计字符个数)
        int[] tChars = new int[256];
        for(char c:p.toCharArray()){
            tChars[c]++;
        }

        // 记录子串中不同字符的数量
        int tCharsNum = 0;
        for(int i:tChars){
            if(i>0){
                tCharsNum++;
            }
        }

        int left = 0, right = 0; // 定义滑动窗口的左右边界
        int wCharsNum = 0; // 记录窗口中匹配的字符个数(相同字符需数量匹配完)

        // 记录结果
        List<Integer> result = new ArrayList<>();

        // 滑动窗口算法
        // 先右移有边界直至窗口匹配完所有子串的字符,然后右移左边界
        while(right < s.length()){
            char c = s.charAt(right);
            if(tChars[c] != 0){ // 当前字符为子串中出现的字符
                wChars[c]++; // 窗口中记录当前字符
                if(wChars[c] == tChars[c]){ // 字符数量匹配完则记录一个字符数量
                    wCharsNum++;
                }
            }
            right++;

            // 右移左边界
            while(wCharsNum == tCharsNum){
                c = s.charAt(left);
                if(tChars[c] != 0){ // 当前字符为子串中出现的字符
                    if(tChars[c] == wChars[c]){ // 若数量相等,则取出当前字符后则记录数少1
                        wCharsNum--;
                        if(right - left == p.length()){ // 当前left为满足匹配要求的临界边界;right则为右边界的后面一个位置。相等时则意味则排列匹配
                            // 记录左边界作为结果
                            result.add(left);
                        }
                    }
                    // 更新窗口字符信息
                    wChars[c]--;
                }
                left++;
            }
        }
        return result;

    }
}

4.2.4 无重复字符的最长子串

3. 无重复字符的最长子串
在这里插入图片描述

class Solution {
    public int lengthOfLongestSubstring(String s) {
        if(s.length() < 2){
            return s.length();
        }

        // 保存窗口中的字符集信息
        int[] wChars = new int[256];
        int maxSubLength = 0;
        int left = 0, right = 0; // 定义滑动窗口的左右边界

        while(right < s.length()){
            char c = s.charAt(right);
            right++;
            wChars[c]++; // 记录窗口中的字符信息

            // 右移左边界收缩窗口
            while(wChars[c] > 1){
                char leftChar = s.charAt(left);
                left++;
                wChars[leftChar]--;
            }
            maxSubLength = Math.max(maxSubLength,right - left);
        }
        return maxSubLength;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2133895.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C++题解】1398. 奇偶统计

欢迎关注本专栏《C从零基础到信奥赛入门级&#xff08;CSP-J&#xff09;》 问题&#xff1a;1398. 奇偶统计 类型&#xff1a;二维数组 题目描述&#xff1a; 在一个n行m列的二维数组中&#xff0c;有若干奇数和偶数&#xff0c;请编程统计出这个二维数组中&#xff0c;奇数…

使用canal.deployer-1.1.7和canal.adapter-1.1.7实现mysql数据同步

1、下载地址 --查看是否开启bin_log日志&#xff0c;value on表示开启 SHOW VARIABLES LIKE log_bin; -- 查看bin_log日志文件 SHOW BINARY LOGS; --查看bin_log写入状态 SHOW MASTER STATUS; --查看bin_log存储格式 row SHOW VARIABLES LIKE binlog_format; --查看数据库服…

actuator字符绕过漏洞在Nginx上的配置

最近遇到了安全部门派发的actuator泄漏漏洞&#xff0c;领导希望不暴露到外网上&#xff0c;对于内网需要认证才可以访问。 要想不暴露到外网上&#xff0c;就需要在网络层面做拦截&#xff0c;比如nginx和apisix上做代理配置。 URI字符绕过的风险背景知识: URI字符绕过是一种安…

【笔记】第二节 熔炼、轧制、热处理和焊接工艺

文章目录 2.1 钢轨冶炼工艺2.1.1 冶炼工艺(1)铁水预处理(2)转炉合金化冶炼(3)钢包精炼工艺&#xff08;LF&#xff08;Ladle Furnace&#xff09;炉&#xff09; 2.1.2 技术要点(1) LF精炼(2) 夹杂物及有害元素控制非金属夹杂物P和S杂质气体 (3) 铸造组织控制钢轨材质的特点铸造…

雷尼绍圆光栅差分ABZ测量问题

雷尼绍圆光栅差分ABZ测量问题 文章目录 雷尼绍圆光栅差分ABZ测量问题引言一 设备1.1 雷尼绍圆光栅1.2 永磁同步电机1.3 M新动力驱动控制器 二 问题2.1 关于圆光栅2.1.1 电机静止时存在位置抖动问题2.1.2 脉冲数计算问题 引言 最近在调试FOC控制&#xff0c;位置反馈采用的是雷…

基于Ubuntu2404搭建mysql8配置远程访问

使用系统为Ubuntu2404&#xff0c;mysql8版本为8.0.36 安装mysql apt install -y mysql-server设置开机自启动 systemctl enable --now mysql修改密码&#xff0c;似乎是bug&#xff0c;修改密码第一次不成功&#xff0c;第二次可以 mysql use mysql; update user set Host…

局域网UDP通信实验

环境&#xff1a; 一个随身WIFI 一台笔记本电脑 一部手机 随身WIFI连接电脑 手机连接WIFI 此时手机和电脑在同一局域网中 手机IPV4地址&#xff1a;192.168.0.20 电脑IPV4地址&#xff1a;192.168.0.39 电脑端使用两台windows系统计算机简单TCP通信测试_两台计算机tcp通信-CSDN…

性能测试:Locust使用介绍(五)

事件钩子 Locust附带了许多事件钩子&#xff0c;可用于以不同的方式扩展Locust。 例如&#xff0c;以下是如何设置一个事件监听器&#xff0c;该监听器将在请求完成后触发&#xff1a; from locust import eventsevents.request.add_listener def my_request_handler(reques…

通信工程学习:什么是EDFA掺铒光纤放大器

EDFA&#xff1a;掺铒光纤放大器 EDFA&#xff0c;即掺铒光纤放大器&#xff08;Erbium-Doped Fiber Amplifier&#xff09;&#xff0c;是一种在光纤通信中广泛使用的光放大器件。以下是对EDFA的详细解释&#xff1a; 一、定义与基本原理 EDFA是在石英光纤中掺入少量的稀土元…

fpga系列 HDL:全连接层实现单个神经元PE(组成:FADD+FM)+vivado单模块仿真

vivado单模块仿真 右键模块的tb.v文件-》“Set as Top” -》点击左侧的“Run Simulation” vivado单模块综合 也可将其他模块暂时Disable PE模块单独综合的结果: 单个神经元PE的结构 processingElement.v 该模块计算两个浮点数的乘积&#xff0c;并将乘积与当前结果相加。最…

Django笔记一:搭建Django环境与URL路径访问

博主之前学从Java后端开发&#xff0c;后面获取到读研资格&#xff0c;想着未来转算法岗&#xff0c;初学Python&#xff0c;发现Python还挺有趣的&#xff0c;由于之前所学后端缘故&#xff0c;有点后端情节&#xff0c;想学习一下Django框架&#xff08;python的web框架&…

Unix时间戳与C语言的time.h库函数

目录 Unix时间戳介绍 UTC/GMT 时间与秒计数器转换代码 time.h库函数 Unix时间戳介绍 Unix 时间戳&#xff08;Unix Timestamp&#xff09;定义为从UTC/GMT的1970年1月1日0时0分0秒开始所经过的秒数&#xff0c;不考虑闰秒 时间戳存储在一个秒计数器中&#xff0c;秒计数器…

Ajax 揭秘:异步 Web 交互的艺术

Ajax 揭秘&#xff1a;异步 Web 交互的艺术 一 . Ajax 的概述1.1 什么是 Ajax ?1.2 同步和异步的区别1.3 Ajax 的应用场景1.3.1 注册表单的用户名异步校验1.3.2 内容自动补全 二 . Ajax 的交互模型和传统交互模型的区别三 . Ajax 异步请求 axios3.1 axios 介绍3.1.1 使用步骤3…

车辆重识别(关于卷积神经网络一些资料)2024/9/11

关于卷积神经网络的介绍 一&#xff0c;全连接神经网络 1&#xff0c;全连接神经网络的整体结构 X代表左边输入的数据&#xff08;向量或者矩阵等等&#xff09;&#xff0c;Y代表模型对数据处理之后的结果&#xff0c;中间的节点都可以算作为隐藏层。 2&#xff0c;全连接神经…

【C++二分查找 容斥原理】1201. 丑数 III

本文涉及的基础知识点 C二分查找 容斥原理&#xff1a;组合数学汇总 LeetCode1201. 丑数 III 丑数是可以被 a 或 b 或 c 整除的 正整数 。 给你四个整数&#xff1a;n 、a 、b 、c &#xff0c;请你设计一个算法来找出第 n 个丑数。 示例 1&#xff1a; 输入&#xff1a;n …

读构建可扩展分布式系统:方法与实践03分布式系统要点

1. 通信基础 1.1. 每个分布式系统都包含通过网络进行通信的软件组件 1.2. 硬件 1.2.1. 全球互联网就是一台异构机器&#xff0c;由不同类型的网络通信通道和设备组成&#xff0c;它们每秒将数百万条消息通过网络传送到预定目的地 1.2.2. 对于单个光纤链路&#xff0c;可以提…

使用gzexe保护Kylin Linux Shell脚本安全

使用gzexe保护Kylin Linux Shell脚本安全 1、加密脚本2、解密脚本3、注意事项 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 在Kylin Linux中&#xff0c;若需保护shell脚本内容不被直接查看&#xff0c;可以使用gzexe工具进行加密。 1、…

R语言机器学习算法实战系列(一):XGBoost算法(eXtreme Gradient Boosting)

介绍 XGBoost(eXtreme Gradient Boosting)是一种基于梯度提升决策树(GBDT)的优化算法,它在处理大规模数据集和复杂模型时表现出色,同时在防止过拟合和提高泛化能力方面也有很好的表现。以下是XGBoost算法的原理和应用方向的详细介绍: 算法原理 目标函数:XGBoost的目标…

Android 测试机

要测手机应用&#xff0c;直接挂电脑上跑虚拟机的话&#xff0c;怀疑电脑都要起火了。 eBay 上买了个新的机器&#xff0c;也才 100 美元多点&#xff0c;机器都没有拆过&#xff0c;电池是完全无电的状态。 操作系统是 Android 12 的版本&#xff0c;升级到 Android 14 后&am…

从用户数据到区块链:Facebook如何利用去中心化技术

在数字化时代&#xff0c;用户数据的管理和保护已成为科技公司面临的重大挑战。作为全球最大的社交网络平台之一&#xff0c;Facebook不仅在用户数据的处理上积累了丰富的经验&#xff0c;也在探索如何利用去中心化技术&#xff0c;如区块链&#xff0c;来改进其数据管理和用户…