【算法】滑动窗口—最小覆盖子串

题目

         ”最小覆盖子串“问题,难度为Hard,题目如下:

        给你两个字符串 S 和 T,请你在 S 中找到包含 T 中全部字母的最短子串。如果 S 中没有这样一个子串,则算法返回空串,如果存在这样一个子串,则可以认为答案是唯一的。

        比如输入 S = "ADBECFEBANC",T = "ABC",算法应该返回 "BANC"。

        如果我们使用暴力解法,代码大概是这样的:

        for (int i = 0; i < s.size; i++) {

                for (int j = i + 1; j < s.size; j++) {

                        if [i : j] 包含 t 的所有字母:

                                更新答案

                }

        }

        思路很简单,但显然不是我们想要的。

滑动窗口思路分析

        1.我们在字符串 S 中使用双指针中的左、右指针技巧,初始化 left = right = 0,把索引左闭右开区间 [left, right) 称为一个”窗口“。

        2.先不断地增加 right 指针扩大窗口 [left, right),直到窗口中的字符串符合要求(包含了 T 中的所有字符)。

        3.此时,停止增加 right,转而不断增加 left 指针缩小窗口 [left, right),直到窗口中的字符串不再符合要求(不包含 T 中所有字符了)。同时,每次增加 left,都要更新一轮结果。

        4.重复第2和第3步,直到 right 到达字符 S 的尽头。

        第2步相当于在寻找一个”可行解“,然后第3步在优化这个”可行解“,最终找到最优解,也就是最短的覆盖子串。左、右指针轮流前进 ,窗口大小增增减减,窗口不断向右滑动,这就是”滑动窗口“这个名字的来历。

        下面画图理解一下这个思路。needs 和 window 相当于计数器,分别记录 T 中字符出现次数和”窗口“中的相应字符的出现次数。

        初始状态:

a2a6f4fbc2554d7388c9120dc1ef8546.png

        增加 right,直到窗口 [left, right) 包含了 T 中所有字符:

ac2a978709634b9e90beb1d1fcd7b4ca.png

        现在开始增加 left,缩小窗口 [left, right):

79ce1706f6074f41bed6491fa30752e4.png

        直到窗口中的字符串不再符合要求,left 不再继续移动:

724c5c8420884e56af1c8aff2d98f2e6.png

        之后重复上述过程,先移动 right,再移动 left······直到 right 指针到达字符串 S 的末端,算法结束。现在来看看滑动窗口代码框架怎么用。

        首先,初始化 window 和 need 两个哈希表,记录窗口中的字符和需要凑齐的字符:

        Map<Character, Integer> need = new HashMap<>();
        Map<Character, Integer> window = new HashMap<>();
        for (int i = 0; i < t.length(); i++) {
            char key = t.charAt(i);
            need.put(key, need.getOrDefault(key, 0) + 1);
        }

        然后,使用 left 和 right 变量初始化窗口的两端,不要忘了,区间 [left, right) 是左闭右开的,所以初始情况下窗口没有包含任何元素:

        int left = 0, right = 0, valid = 0;
        while (right < s.length()) { // 开始滑动 }

        其中,valid 变量表示窗口中满足 need 条件的字符个数,如果 valid 和 need.size 的大小相同,则说明窗口已满足条件,已经完全覆盖了串 T。

        现在开始套模板,只需要思考以下4个问题:

        1.当移动 right 扩大窗口,即加入字符时,应该更新哪些数据?

        2.什么条件下,窗口应该暂停扩大,开始移动 left 缩小窗口?

        3.当移动 left 缩小窗口,即移出字符时,应该更新哪些数据?

        4.我们要的结果应该在扩大窗口时还是缩小窗口时进行更新?

        一般来说,如果一个字符进入窗口,应该增加 window 计数器;如果一个字符移出窗口,应该减少 window 计数器;当 valid 满足 need 时应该收缩窗口;收缩窗口的时候应该更新最终结果。

        下面是完整代码:

package SlidingWindow;import java.util.HashMap;
import java.util.Map;// leetcode 017 最小覆盖子串
public class MCS {public String slidingWindow(String s, String t) {Map<Character, Integer> need = new HashMap<>();Map<Character, Integer> window = new HashMap<>();for (int i = 0; i < t.length(); i++) {char key = t.charAt(i);need.put(key, need.getOrDefault(key, 0) + 1);}int left = 0, right = 0, valid = 0; // valid 表示窗口中满足 need 条件的字符个数// 记录最小覆盖子串的启始索引及长度int start = 0, len = Integer.MAX_VALUE;while (right < s.length()) {// c 是将要移入窗口的字符char c = s.charAt(right);// 右移窗口right++;// 进行窗口内数据的一系列更新if (need.containsKey(c)) {window.put(c, window.getOrDefault(c, 0) + 1);if (window.getOrDefault(c, 0).equals(need.getOrDefault(c, 0))) { // window[c] == need[c]valid++;}}/*** debug 输出的位置***/System.out.println("window:(" + left + ", " + right + ")");/*********************/// 判断左侧窗口是否要收缩while (valid == need.size()) { // window need shrink —窗口需要收缩// 在这里更新最小覆盖子串if (right - left < len) {start = left;len = right - left;}// d 是将要移出窗口的字符char d = s.charAt(left);// 左移窗口left++;// 进行窗口内数据的一系列更新if (need.containsKey(d)) {if (window.getOrDefault(d, 0).equals(need.getOrDefault(d, 0))) {valid--;}window.put(d, window.getOrDefault(d, 0) - 1);}}}// 返回最小覆盖子串return len == Integer.MAX_VALUE ? "" : s.substring(start, start + len); // s.substring(start, start + len) == C++ 中的 s.substr(start, len)}public static void main(String[] args) {MCS mcs = new MCS();String str = mcs.slidingWindow("ADOBECODEBANC", "ABC");System.out.println(str);}}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

单细胞BCR的分析Dandelion重注释的安装以及用法----11111

今天来学习下这个新的方法&#xff0c;主要是针对单细胞BCR 首先安装singularity Singularity 是一种容器化技术&#xff0c;类似于 Docker&#xff0c;专为高性能计算&#xff08;HPC&#xff09;和科学研究领域的需求设计。它允许用户在不同环境中运行和移植应用程序&#x…

免费PDF工具集套装,支持批量

软件介绍 PDFgear 支持多种与 PDF 相关的操作&#xff0c;包括但不限于编辑、转换、合并和签署 还支持批量操作&#xff0c;支持批量转换功能&#xff0c;可以将 PDF 文件转换为多种格式&#xff0c;包括 Word、Excel、PowerPoint、图像甚至电子书等。 下载方式 请看文章尾部…

虚拟机vaware中cpu设置跑满大核

首先&#xff0c;大核速度快&#xff0c;并且在资源紧张时大核优先&#xff0c;小核甚至是闲着围观大核跑满。其次&#xff0c;遇到经常切换操作虚拟机和win11的使用场景&#xff0c;切换核心本身也会造成一点卡顿&#xff0c;降低虚拟机里操作流畅度。另外&#xff0c;13代在你…

【软件测试】自动化测试常用函数 二

目录 &#x1f334;等待 &#x1f6a9;强制等待 &#x1f6a9;隐式等待 &#x1f6a9;显示等待 &#x1f333;浏览器导航 &#x1f332;弹窗 &#x1f6a9;警告弹窗确认弹窗 &#x1f6a9;提示弹窗 &#x1f384;上传文件 &#x1f340;浏览器参数设置 &#x1f6a9…

浅显易懂的Git教程

Git概述 SVN与Git的对比 SVN&#xff08;Subversion&#xff09; 类型&#xff1a;集中式版本控制系统 工作流程&#xff1a; 从中央服务器下载最新版本到本地。在本地进行开发。提交更改回中央服务器。 优点&#xff1a; 简单易用&#xff0c;适合小型团队。版本历史清…

Leetcode—环形链表||

题目描述 思路 快慢指针 结论 我们需要用到一个重要的结论&#xff1a;让一个指针从链表起始位置开始遍历链表,同时让一个指针从判环时相遇点的位置开始绕环运行,两个指针都是每次均走一步,最终肯定会在入口点的位置相遇。 画图解释 1.利用快慢指针找到相遇点 2. 定义两个…

医学数据分析实训 项目七 集成学习--空气质量指标--天气质量分析和预测

项目七&#xff1a;集成学习 实践目的 理解集成学习算法原理&#xff1b;熟悉并掌握常用集成学习算法的使用方法&#xff1b;熟悉模型性能评估的方法&#xff1b;掌握模型优化的方法。 实践平台 操作系统&#xff1a;Windows7及以上Python版本&#xff1a;3.8.x及以上集成开…

计算机网络(七) —— https协议与网络安全证书

目录 一&#xff0c;关于https 二&#xff0c;关于加密 2.1 明文&#xff0c;密钥 2.2 对称和非对称加密 2.3 数据摘要&#xff0c;数据指纹&#xff0c;数字签名 三&#xff0c;https过程过程探究 四&#xff0c;证书 4.1 CA认证 4.2 证书大致内容和申请流程 4.3 签…

Java-idea小锤子图标

这一版的idea小锤子图标其实就在这里 点进去就找到了~

计算机毕业设计 家电销售展示平台的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

面了智谱大模型算法岗,效率贼高!

最近这一两周不少互联网公司都已经开始秋招提前批面试了。不同以往的是&#xff0c;当前职场环境已不再是那个双向奔赴时代了。求职者在变多&#xff0c;HC 在变少&#xff0c;岗位要求还更高了。 最近&#xff0c;我们又陆续整理了很多大厂的面试题&#xff0c;帮助一些球友解…

【linux-Day3】linux的基本指令<中>

【linux-Day3】linux的基本指令<中> linux下的基本指令&#x1f4e2;man&#xff1a;访问linux手册页&#x1f4e2;echo&#xff1a;把字符串写入指定文件中&#x1f4e2;cat&#xff1a;查看目标文件的内容&#x1f4e2;cp&#xff1a;复制文件或目录&#x1f4e2;mv&am…

根据 IP 地址进行 VPN 分流(详细,亲测,通用)

根据 IP 地址进行 VPN 分流&#xff08;详细&#xff0c;亲测&#xff0c;通用&#xff09; 背景 不在学校的时候需要使用实验室的服务器&#xff0c;但是实验室的服务器只能在校园网内访问&#xff0c;因此在校外就需要使用学校的 VPN&#xff0c;但是打开 VPN 以后会默认将…

Axure中后台管理信息系统通用原型方案

Axure中后台管理信息系统通用原型方案中的12套模板&#xff0c;旨在帮助开发者与设计师快速搭建出标准且美观的中后台产品原型&#xff0c;提升开发效率和节省协作成本。这些模板覆盖了多样化的中后台管理系统开发需求&#xff0c;具有高度的灵活性和可定制性。 以下是对这些模…

技术周总结 09.09~09.15周日(C# WinForm WPF 软件架构)

文章目录 一、09.09 周一1.1) 问题01: Windows桌面开发中&#xff0c;WPF和WinForm的区别和联系&#xff1f;联系&#xff1a;区别&#xff1a; 二、09.12 周四2.1&#xff09;问题01&#xff1a;visual studio的相关快捷键有哪些&#xff1f;通用快捷键编辑导航调试窗口管理 2…

论文解读《LaMP: When Large Language Models Meet Personalization》

引言&#xff1a;因为导师喊我围绕 “大语言模型的个性化、风格化生成” 展开研究&#xff0c;所以我就找相关论文&#xff0c;最后通过 ACL 官网找到这篇&#xff0c;感觉还不错&#xff0c;就开始解读吧&#xff01; “说是解读&#xff0c;其实大部分都是翻译哈哈哈&#x…

基于SSM的在线家用电器销售系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 【2025最新】基于JavaSSMVueMySQL的在线家…

传输层协议 —— UDP协议

目录 0.前言 1.UDP协议格式 16位源端口和目的端口 16位UDP长度 16位校验和 2.UDP协议特点 无连接 不可靠 面向数据报 3.UDP的缓冲区 0.前言 首先&#xff0c;我们得明确一点&#xff0c;网络模型是分层的。自底向上分别是物理层、数据链路层、网络层、传输层、应用层…

MODIS/Landsat/Sentinel下载教程详解【常用网站及方法枚举】

⛄前言 在当今快速发展的地球观测时代&#xff0c;遥感技术作为获取地球表面及其环境信息的重要手段&#xff0c;正以前所未有的广度和深度改变着我们对自然界的认知与管理方式。MODIS&#xff08;Moderate-resolution Imaging Spectroradiometer&#xff0c;中分辨率成像光谱…

unity安装配置和vs2022联动教程

目录 1.选择vs2022配置 2.安装unity 2.1安装unity hub 2.2注册个人账号 2.3安装编辑器 2.4修改为简体中文 2.5添加许可证 2.6安装位置修改 3.项目的创建 3.1如何创建 3.2如何选择 3.3配置语言 3.4去哪里找语言包 4.unity编辑器窗口的介绍 4.1游戏的运行和停止 4…