当前位置: 首页 > news >正文

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

题目

         ”最小覆盖子串“问题,难度为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);}}

相关文章:

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

题目 ”最小覆盖子串“问题&#xff0c;难度为Hard&#xff0c;题目如下&#xff1a; 给你两个字符串 S 和 T&#xff0c;请你在 S 中找到包含 T 中全部字母的最短子串。如果 S 中没有这样一个子串&#xff0c;则算法返回空串&#xff0c;如果存在这样一个子串&#xff0c;则可…...

“Fast-forward“ in git-pull result

当你执行 git pull 并且结果显示 Fast-forward 时&#xff0c;这意味着你的本地分支可以直接快进到远程分支的最新提交&#xff0c;没有任何冲突或者需要合并的内容。具体来说&#xff0c;Fast-forward 是一种合并方式&#xff0c;它的特点是将当前分支的指针直接移动到远程分支…...

Oracle(133)如何创建表空间(Tablespace)?

在Oracle数据库中&#xff0c;表空间&#xff08;Tablespace&#xff09;是存储数据的逻辑单位&#xff0c;它由一个或多个数据文件组成。表空间是数据库数据管理的基本结构&#xff0c;了解如何创建表空间对于数据库管理员至关重要。 创建表空间的基本语法 创建表空间的基本…...

Linux中权限和指令

&#x1f4a5;1、Linux基本指令 1.1 mv 指令 mv指令是move的缩写&#xff0c;用来移动或重命名文件、目录&#xff0c;经常用来备份文件或目录。 mv old_name new_name&#xff1a; 重命名文件或目录mv file /path/to/directory&#xff1a; 移动文件到指定目录 roothcss-ecs…...

本地镜像发布到阿里云

本地镜像发布到阿里云 登录阿里云容器镜像服务配置 Docker 登录阿里云容器镜像服务标记你的 Docker 镜像推送镜像到阿里云验证使用阿里云镜像注意事项 将 Docker 本地镜像发布到阿里云&#xff08;Alibaba Cloud&#xff09;容器镜像服务&#xff08;Container Registry&#x…...

【Linux】【Vim】Vim 基础

Vim/Gvim 基础 文本编辑基础编辑操作符命令和位移改变文本重复改动Visual 模式移动文本(复制、粘贴)文本对象替换模式 光标移动以 word 为单位移动行首和行尾行内指定单字符移动到匹配的括号光标移动到指定行滚屏简单查找 /string标记 分屏vimdiff 文本编辑 基础编辑 Normal 模…...

计算机人工智能前沿进展-大语言模型方向-2024-09-18

计算机人工智能前沿进展-大语言模型方向-2024-09-18 1. The Application of Large Language Models in Primary Healthcare Services and the Challenges W YAN, J HU, H ZENG, M LIU, W LIANG - Chinese General Practice, 2024 人工智能大语言模型在基层医疗卫生服务中的应…...

ubuntu24安装vivado24(安装并解决若干错误)

目录 安装方法&#xff1a;问题1&#xff1a;解决办法&#xff1a; 问题2&#xff1a;解决方法&#xff1a; 安装完成&#xff1a; 安装方法&#xff1a; 注意&#xff1a;内存最好预留80G空闲的。 安装好大小&#xff1a; 安装依赖库&#xff1a; sudo apt-get update sud…...

CSS实现文本溢出省略号或完整显示

目录 前言1. 省略号2. 完整展示3. Demo 前言 文本内容超出容器宽度的问题&#xff0c;为了保持页面布局的整洁&#xff0c;通常会使用省略号来隐藏多余的内容 一共有两种方式&#xff1a; 设定省略号完整展示 1. 省略号 文本溢出时显示省略号 .item-value {flex-basis: 7…...

three.js PropertyBinding和PropertyMixer

PropertyBinding 对场景图中某一真实属性的引用&#xff0c;内部使用。 构造器 PropertyBinding( rootNode : Object3D, path, parsedPath ) -- rootNode: -- path -- parsedPath (可选) 属性 # .path : Number # .parsedPath : Number # .node : Number # .rootNode …...

ssh远程连接try1账号切换tips

1&#xff0c;创建拥有sudo权限的用户&#xff1a; 在root下 sudo adduser bio sudo vim /etc/sudoers //修改添加如下&#xff1a; bio ALL(ALL) ALL //bio用户就拥有了root权限参考&#xff1a;https://github.com/isLishude/blog/issues/70 2&#xff0c;修改ssh配置 …...

C++之第十二课

课程列表 哎呀呀&#xff0c;失踪人口回归了&#xff01;&#xff08;前段时间跑去B站了&#xff0c;久等了&#xff09; 今天来讲——数组 有一道题是这样的&#xff1a; 有n个数&#xff0c;请输出其中最大的数。 原来我们就要&#xff1a; int a,b,c... 但是——数组…...

Linux硬连接、软连接和复制的区别

‌硬连接、软连接和复制在Linux系统中的主要区别体现在以下三点&#xff1a; 文件链接的方式文件独立性文件系统的操作上。‌ 一、硬连接 1. 硬连接是通过ln命令创建的&#xff0c;它为文件创建别名&#xff0c;与源文件共享同一inode号码&#xff0c;因此硬连接和源文件实际…...

基于STM32的无人小车自主避障系统设计

文章目录 前言资料获取设计介绍功能介绍设计程序具体实现截图参考文献设计获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师&#xff0c;一名热衷于单片机技术探索与分享的博主、专注于 精通51/STM32/MSP430/AVR等单片机设…...

杂牌鼠标侧键设置

X-Mouse Button Control修改侧键基本功能介绍-CSDN博客 下载链接 【X-Mouse汉化版】X-Mouse中文版 v2.19.2 绿色版&#xff08;支持Win10&#xff09;-开心电玩 (kxdw.com)...

Android WebView H5 Hybrid 混和开发

对于故乡&#xff0c;我忽然有了新的理解&#xff1a;人的故乡&#xff0c;并不止于一块特定的土地&#xff0c;而是一种辽阔无比的心情&#xff0c;不受空间和时间的限制&#xff1b;这心情一经唤起&#xff0c;就是你已经回到了故乡。——《记忆与印象》 前言 移动互联网发展…...

智源推出下一代检索增强大模型框架MemoRAG

北京智源人工智能研究院与中国人民大学高瓴人工智能学院联合发布了一款创新的人工智能模型框架——MemoRAG。该框架基于长期记忆&#xff0c;旨在推动检索增强生成&#xff08;RAG&#xff09;技术的发展&#xff0c;使其能够处理更复杂的任务&#xff0c;而不仅限于简单的问答…...

【AprilTag】视觉定位实战 | 使用 ROS 驱动的 USB 摄像头进行相机标定与 AprilTag 识别

写在前面&#xff1a; &#x1f31f; 欢迎光临 清流君 的博客小天地&#xff0c;这里是我分享技术与心得的温馨角落。&#x1f4dd; 个人主页&#xff1a;清流君_CSDN博客&#xff0c;期待与您一同探索 移动机器人 领域的无限可能。 &#x1f50d; 本文系 清流君 原创之作&…...

[数据集][目标检测]俯拍航拍森林火灾检测数据集VOC+YOLO格式6116张2类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;6116 标注数量(xml文件个数)&#xff1a;6116 标注数量(txt文件个数)&#xff1a;6116 标注…...

windows10下tomcat安装及配置教程

Apache Tomcat是一个开源的、轻量级的Servlet容器&#xff0c;广泛用于运行Java Web应用程序。以下是Tomcat安装及配置的基本步骤&#xff0c;根据搜索结果整理&#xff1a; 一、安装前的准备工作 确保你的计算机上已经安装了Java Development Kit (JDK)&#xff0c;因为Tomc…...

大数据学习栈记——Neo4j的安装与使用

本文介绍图数据库Neofj的安装与使用&#xff0c;操作系统&#xff1a;Ubuntu24.04&#xff0c;Neofj版本&#xff1a;2025.04.0。 Apt安装 Neofj可以进行官网安装&#xff1a;Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...

智慧医疗能源事业线深度画像分析(上)

引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...

django filter 统计数量 按属性去重

在Django中&#xff0c;如果你想要根据某个属性对查询集进行去重并统计数量&#xff0c;你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求&#xff1a; 方法1&#xff1a;使用annotate()和Count 假设你有一个模型Item&#xff0c;并且你想…...

Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具

文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...

在Ubuntu中设置开机自动运行(sudo)指令的指南

在Ubuntu系统中&#xff0c;有时需要在系统启动时自动执行某些命令&#xff0c;特别是需要 sudo权限的指令。为了实现这一功能&#xff0c;可以使用多种方法&#xff0c;包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法&#xff0c;并提供…...

从零实现STL哈希容器:unordered_map/unordered_set封装详解

本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说&#xff0c;直接开始吧&#xff01; 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...

【Oracle】分区表

个人主页&#xff1a;Guiat 归属专栏&#xff1a;Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...

安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖

在Vuzix M400 AR智能眼镜的助力下&#xff0c;卢森堡罗伯特舒曼医院&#xff08;the Robert Schuman Hospitals, HRS&#xff09;凭借在无菌制剂生产流程中引入增强现实技术&#xff08;AR&#xff09;创新项目&#xff0c;荣获了2024年6月7日由卢森堡医院药剂师协会&#xff0…...

动态 Web 开发技术入门篇

一、HTTP 协议核心 1.1 HTTP 基础 协议全称 &#xff1a;HyperText Transfer Protocol&#xff08;超文本传输协议&#xff09; 默认端口 &#xff1a;HTTP 使用 80 端口&#xff0c;HTTPS 使用 443 端口。 请求方法 &#xff1a; GET &#xff1a;用于获取资源&#xff0c;…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...