当前位置: 首页 > 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;则可…...

应用案例|开源 PolarDB-X 在互联网安全场景的应用实践

背景介绍 中盾数科集团始创于2012年&#xff0c;是由网络安全服务而发展起来的科技型、多元化的企业集团。旗下包括网络安全服务、信创一体化服务、箱式液冷、区块链、位置服务、视觉服务等六大板块&#xff0c;业务覆盖湖南、甘肃、贵州等多个省份。 业务挑战 中盾集团基于A…...

【大数据】MapReduce的“内存增强版”——Spark

【大数据】MapReduce的“内存增强版”——Spark 文章脉络 Spark架构 Spark-core SparkConf 和 SparkContext RDD Spark集群 Spark-sql 在大数据时代&#xff0c;数据处理和分析成为企业竞争的重要手段。Hadoop作为大数据处理的基石&#xff0c;其核心组件MapReduce在众多…...

o1模型:引领AI技术在STEM领域的突破与应用

o1模型是OpenAI最新推出的大型语言模型&#xff0c;它在多个领域展现出了卓越的能力&#xff0c;被认为是AI技术发展的一个重要里程碑。以下是对o1模型的详细介绍和分析&#xff1a; o1模型的简介和性能评估 o1模型在物理、化学、生物学等领域的基准任务上达到了博士生水平&…...

数据库系统 第57节 数据库迁移

数据库迁移是一个复杂的过程&#xff0c;涉及到将数据从一个数据库系统转移到另一个数据库系统。这个过程通常需要仔细规划和执行&#xff0c;以确保数据的完整性和可用性。以下是数据库迁移的一些关键方面&#xff1a; 数据迁移工具&#xff1a; 这些工具可以帮助自动化迁移过…...

【主机入侵检测】Wazuh规则详解

前言 Wazuh 规则是一组用XML格式编写的条件&#xff0c;它们定义了应该如何解释日志数据。这些规则由Wazuh Manager使用&#xff0c;用于在日志消息中检测特定的模式或行为&#xff0c;并相应地生成警报或响应。它们在威胁检测中扮演着至关重要的角色&#xff0c;因为它们允许系…...

redis有序集合写入和求交集的速度

背景 团队小伙伴做了一个需求。大概的需求是有很多的图片作品&#xff0c;图片作品有一些类别&#xff0c;每个人进入到每个类别的作品业&#xff0c;根据权重优先查看权重最高的的作品&#xff0c;权重大概是基于每个人对该作品的浏览计算&#xff0c;浏览过的作品放在最后展…...

微服务之服务注册与发现:Etcd、Zookeeper、Consul 与 Nacos 比较

在微服务架构中&#xff0c;服务注册与发现是实现服务动态管理和负载均衡的关键。本文将对四款主流的服务注册与发现工具——Etcd、Zookeeper、Consul、Nacos进行深入对比&#xff0c;从功能、性能、一致性、生态集成、应用场景等多个维度展开分析&#xff0c;帮助您选择最适合…...

桥接模式详解和分析JDBC中的应用

&#x1f3af; 设计模式专栏&#xff0c;持续更新中&#xff0c; 欢迎订阅&#xff1a;JAVA实现设计模式 &#x1f6e0;️ 希望小伙伴们一键三连&#xff0c;有问题私信都会回复&#xff0c;或者在评论区直接发言 桥接模式 文章目录 桥接模式桥接模式的四个核心组成&#xff1a…...

【python - 函数】

一、交互式会话 在与 Python 的交互式会话中&#xff0c;你可以在提示符 >>> 后键入一些 Python 代码&#xff0c;Python 解释器会读取并执行你键入的各种命令。 要启动交互式会话&#xff0c;请在终端 (Mac/Unix/Linux) 中键入 python3 或在 Windows 中打开 Python…...

scipy中稀疏矩阵特征值问题概述

在Python的scipy库中&#xff0c;这三种算法——ARPACK、LOBPCG、和AMG——都是用于求解稀疏矩阵特征值问题的数值方法。它们各自有不同的特性和适用场景&#xff0c;以下是详细说明&#xff1a; 1. ARPACK (Arnoldi Package) ARPACK&#xff08;Arnoldi Package&#xff09;…...

浅谈线性表——队列

文章目录 一、什么是队列&#xff1f;二、队列底层三、自我实现一个队列3.1、链式存储3.1.1、单向链表实现队列的实现代码3.1.2、双向链表实现队列的实现代码 3.2、顺序存储3.2.1、循环队列的实现代码 一、什么是队列&#xff1f; 队列是只允许在一端进行插入数据操作&#xf…...

2-94 基于matlab的最佳维纳滤波器的盲解卷积算法

基于matlab的最佳维纳滤波器的盲解卷积算法。维纳滤波将地震子波转换为任意所需要的形态。维纳滤波不同于反滤波&#xff0c;它是在最小平方的意义上为最 佳。基于最佳纳滤波理论的滤波器算法是莱文逊(Wiener—Levinson)算法。程序提供了4种子波和4种期望输出&#xff1a;零延迟…...

【提示词】浅谈GPT等大模型中的Prompt

Prompt是人工智能&#xff08;AI&#xff09;提示词&#xff0c;是一种利用自然语言来指导或激发人工智能模型完成特定任务的方法。在AI语境中&#xff0c;Prompt是一种自然语言输入&#xff0c;通常指的是向模型提出的一个请求或问题&#xff0c;这个请求或问题的形式和内容会…...

最强AI照片说话Windows一体包下载地址,口型合成音频驱动图片,免安装,下载即用

照片数字一键整合包&#xff1a;点击下载 一键安装包&#xff0c;简单一键启动&#xff0c;即刻使用&#xff0c;秒级体验。 目前效果最好的音频驱动图片说话的软件&#xff0c;比sadtalker、MuseTalk更清晰&#xff0c;效果更好&#xff0c;可以作为DID heygen的开源平替。原…...

Windows下使用cmake编译OpenCV

Windows下使用cmake编译OpenCV cmake下载OpenCV下载编译OpenCV cmake下载 下载地址&#xff1a;https://cmake.org/download/ 下载完成&#xff0c;点击选择路径安装即可 OpenCV下载 下载地址&#xff1a;https://github.com/opencv/opencv/releases/tag/4.8.1因为我们是编译…...

设计模式---中介者模式

设计模式---中介者模式 定义与设计思路中介者模式的引入&#xff1a;机场控制塔中介者模式的设计框架 定义与设计思路 定义&#xff1a;用一个中介对象来封装一系列对象交互。中介者使各对象不需要相互引用&#xff0c;从而使其耦合松散&#xff0c;而且可以独立地改变它们之间…...

六氟化硫密度微水在线监测配套5孔M12格兰头航空插头插座

我们将为大家介绍如何使用六氟化硫密度微水在线监测配套5孔M12格兰头连接器。在本教程中&#xff0c;我们将向您展示简单易懂的步骤&#xff0c;让您轻松掌握。 所需材料&#xff1a; 1. 六氟化硫密度微水在线监测器 2. 5孔M12格兰头连接器 3. 电源线 4. 符合要求的电缆 5…...

linux -L4.linux 暂停和启动进程

接第3课&#xff0c;L3 第3课-查看进程 通过端口号&#xff0c;查看对应的进程 netstat -tulnp | grep :9513暂停这个进程 Kill -STOP 5376重启这个进程 Kill -CONT 5376要查看特定PID对应的端口&#xff0c;你可以使用netstat命令结合grep工具来过滤输出。以下是一个基于L…...

Java多线程编程-基础篇

多线程相关的概念 并发 并发是指在同一时间段内&#xff0c;两个或多个任务在同一个处理器上交替执行&#xff0c;使得在宏观上看起来像是同时进行。并发是通过快速切换任务来模拟同时执行的效果&#xff0c;实际上在任何一个时刻点上只有一个任务在执行。 也就是说&#xff0…...

python打卡day49

知识点回顾&#xff1a; 通道注意力模块复习空间注意力模块CBAM的定义 作业&#xff1a;尝试对今天的模型检查参数数目&#xff0c;并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...

AI Agent与Agentic AI:原理、应用、挑战与未来展望

文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例&#xff1a;使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例&#xff1a;使用OpenAI GPT-3进…...

Nuxt.js 中的路由配置详解

Nuxt.js 通过其内置的路由系统简化了应用的路由配置&#xff0c;使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...

第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明

AI 领域的快速发展正在催生一个新时代&#xff0c;智能代理&#xff08;agents&#xff09;不再是孤立的个体&#xff0c;而是能够像一个数字团队一样协作。然而&#xff0c;当前 AI 生态系统的碎片化阻碍了这一愿景的实现&#xff0c;导致了“AI 巴别塔问题”——不同代理之间…...

音视频——I2S 协议详解

I2S 协议详解 I2S (Inter-IC Sound) 协议是一种串行总线协议&#xff0c;专门用于在数字音频设备之间传输数字音频数据。它由飞利浦&#xff08;Philips&#xff09;公司开发&#xff0c;以其简单、高效和广泛的兼容性而闻名。 1. 信号线 I2S 协议通常使用三根或四根信号线&a…...

GitFlow 工作模式(详解)

今天再学项目的过程中遇到使用gitflow模式管理代码&#xff0c;因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存&#xff0c;无论是github还是gittee&#xff0c;都是一种基于git去保存代码的形式&#xff0c;这样保存代码…...

快刀集(1): 一刀斩断视频片头广告

一刀流&#xff1a;用一个简单脚本&#xff0c;秒杀视频片头广告&#xff0c;还你清爽观影体验。 1. 引子 作为一个爱生活、爱学习、爱收藏高清资源的老码农&#xff0c;平时写代码之余看看电影、补补片&#xff0c;是再正常不过的事。 电影嘛&#xff0c;要沉浸&#xff0c;…...

tauri项目,如何在rust端读取电脑环境变量

如果想在前端通过调用来获取环境变量的值&#xff0c;可以通过标准的依赖&#xff1a; std::env::var(name).ok() 想在前端通过调用来获取&#xff0c;可以写一个command函数&#xff1a; #[tauri::command] pub fn get_env_var(name: String) -> Result<String, Stri…...

Vue 模板语句的数据来源

&#x1f9e9; Vue 模板语句的数据来源&#xff1a;全方位解析 Vue 模板&#xff08;<template> 部分&#xff09;中的表达式、指令绑定&#xff08;如 v-bind, v-on&#xff09;和插值&#xff08;{{ }}&#xff09;都在一个特定的作用域内求值。这个作用域由当前 组件…...

基于鸿蒙(HarmonyOS5)的打车小程序

1. 开发环境准备 安装DevEco Studio (鸿蒙官方IDE)配置HarmonyOS SDK申请开发者账号和必要的API密钥 2. 项目结构设计 ├── entry │ ├── src │ │ ├── main │ │ │ ├── ets │ │ │ │ ├── pages │ │ │ │ │ ├── H…...