滑动窗口——串联所有单词的子串

一.题目描述

30. 串联所有单词的子串 - 力扣(LeetCode)

二.题目解析 

题目前提:s是一个字符串,words是一个字符串数组,里面所有的字符串的长度都是相等的。

题目要求:找到s中的一段连续的子串,该子串是由words中的所有字符串随机排列组合起来的,但是每一个字符串内部的顺序是不变的。然后返回该子串的起始位置即可。

三.算法原理

3.1问题转化

因为words中的每一个字符串都是一样长的,所以我们可以将s字符串进行划分,划分成与words中字符串一样长的形式:

然后我们将words中的两个字符串看作两个字符,那么s中的字符串也可以根据分组看成若干字符,这时,该题就转换成了昨天的那道题——找出所有的异位词,找出一个子区间,是由words组成的即可。

 所以这道题我们也可以使用滑动窗口来解决问题。

3.2滑动窗口

在使用滑动窗口之前,我们还要对一些细节进行分析:

细节1:

我们刚才划分是从首位置开始划分的,但是答案也可能这样分布:

所以我们要根据开始位置的不同,进行多次滑动窗口的过程。根据示例的分析,我们需要进行len次滑动窗口(len指words中每一个单词的长度) ,第len+1次滑动窗口就和第一个次一样了。

细节2:

我们这次哈希表里面存的就不再是字符了,而是字符串。所以我们要用容器unordered_map来实现。

细节3:

进窗口的时候,我们就不再是一次进一个元素了,而是进一段子区间。我们可以使用substr函数来获取子区间,该子区间的长度就是words中每一个单词的长度

对于这个示例就是将right后面的3个字符作为字符串插入到哈希表中。

细节4:

判断的逻辑,当子区间的长度大于words所有字符的和的时候就需要出窗口了,但是我们这里没有必要用子区间的所有长度与words总长度比较,只需用right-left+1与总长度比较即可。 

细节5:

出窗口的时候,我们让left后面的len个字符出窗口,而不是一个,与进窗口一致。

细节6:

left和right不再一次走一步,因为我们要将一段区间插入到哈希表中,所有left和right每次走len步。 

四.代码实现

// C++

// 写法一:
vector<int> ret;
int len = words[0].size();
int n = words.size();
if (s.size() < len * n)
    return ret;
unordered_map<string, int> mp_w;
for (auto& e : words) mp_w[e]++;

for (int i = 0; i < len; ++i)
{
    unordered_map<string, int> mp_s;
    for (int l = i, r = i, count = 0; r + len <= s.size(); r += len)
    {
        // 进窗口 + 维护count
        string s_in = s.substr(r, len);
        mp_s[s_in]++;
        if (mp_s[s_in] <= mp_w[s_in]) count++;

        // 判断
        if (r - l + 1 > len * n)
        {
            // 出窗口 + 维护count
            string s_out = s.substr(l, len);
            if (mp_s[s_out] <= mp_w[s_out]) count--;
            mp_s[s_out]--;
            l += len;
        }

        //更新结果
        if (count == n) ret.emplace_back(l);
    }
}
return ret;


// 写法二:
vector<int> ret;

int n = words.size(); // words中有几个单词
int len = words[0].size(); // 每个单词的长度
if (s.size() < len * n)
    return ret;
unordered_map<string, int> mp_w;
for (auto e : words) mp_w[e]++;

int i = 0;
while (i < len)
{
    unordered_map<string, int> mp_s;
    int count = 0;
    for (int left = i, right = i; right < s.size();)
    {
        // 进窗口
        if (right + len > s.size()) break;
        right += len;
        string s_in(s.begin() + right - len, s.begin() + right);
        mp_s[s_in]++;
        if (mp_s[s_in] <= mp_w[s_in]) count++;

        // 判断
        if (right - left > len * n)
        {
            string s_out(s.begin() + left, s.begin() + left + len);
            if (mp_s[s_out] <= mp_w[s_out]) count--;
            mp_s[s_out]--;
            left += len;
        }

        //更新结果
        if (count == n) ret.emplace_back(left);
    }
    ++i;
}
return ret;
# python

class Solution:
    def findSubstring(self, s: str, words: List[str]) -> List[int]:
        ret = [] # 返回列表
        cnt_w = Counter() # 记录words中单词的频次
        for e in words:
            cnt_w[e]+=1

        n,Len = len(words),len(words[0]) # words中单词的个数,以及长度

        for i in range(0,Len):
            cnt_s = Counter() # 窗口中单词的频次
            r,l,count = i,i,0
            while r+Len <= len(s):
                # 进窗口 + 维护 count
                s_in = s[r:r+Len]
                cnt_s[s_in] += 1
                if cnt_s[s_in] <= cnt_w[s_in]:
                    count+=1
                
                # 判断 
                if r-l+1>n*Len:
                    # 出窗口 + 维护 count
                    s_out = s[l:l+Len]
                    if cnt_s[s_out] <= cnt_w[s_out]:
                        count -= 1
                    cnt_s[s_out] -= 1
                    l += Len
                
                # 更新结果
                if count == n:
                    ret.append(l)
                r += Len
        return ret

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【微软,模型规模】模型参数规模泄露:理解大型语言模型的参数量级

模型参数规模泄露&#xff1a;理解大型语言模型的参数量级 关键词&#xff1a; #大型语言模型 Large Language Model #参数规模 Parameter Scale #GPT-4o #GPT-4o-mini #Claude 3.5 Sonnet 具体实例与推演 近日&#xff0c;微软在一篇医学相关论文中意外泄露了OpenAI及Claud…

SpringBoot Maven 项目 pom 中的 plugin 插件用法整理

把 SpringBoot Maven 项目打包成 jar 文件时&#xff0c;我们通常用到 spring-boot-maven-plugin 插件。 前面也介绍过&#xff0c;在 spring-boot-starter-parent POM 和 spring-boot-starter POM 中都有插件的管理&#xff0c;现在我们就撸一把构建元素中插件的用法。 一、…

UE5AI感知组件

官方解释&#xff1a; AI感知系统为Pawn提供了一种从环境中接收数据的方式&#xff0c;例如噪音的来源、AI是否遭到破坏、或AI是否看到了什么。 AI感知组件&#xff08;AIPerception Component&#xff09;是用于实现游戏中的非玩家角色&#xff08;NPC&#xff09;对环境和其…

【数据仓库】hive on Tez配置

hive on Tez 搭建 前提是hive4.0hadoop3.2.2数仓已搭建完成&#xff0c;现在只是更换其执行引擎 为Tez。搭建可参考【数据仓库】hive hadoop数仓搭建实践文章。 Tez 下载 下载地址 https://archive.apache.org/dist/tez/ 官网地址 https://tez.apache.org/releases/apac…

finereport动态数据源插件教程2

场景&#xff1a; 模板中有多个数据集&#xff0c;只需要其中一个数据集按照不同的参数显示不同数据库的数据。 模板制作&#xff1a; 两个数据集ds1&#xff0c;ds2&#xff0c;ds1的绑定到参数面板的下拉框上&#xff0c;ds2显示到模板正文中&#xff0c;现在需要ds1根据不同…

Java通过谷歌邮箱Gmail直接发送邮件的三种方式

错误 Connected to the target VM, address: 127.0.0.1:52082, transport: socketException in thread "main" javax.mail.MessagingException: Got bad greeting from SMTP host: smtp.gmail.com, port: 587, response: [EOF] at com.sun.mail.smtp.SMTPTransp…

WSDM 2025 | 时间序列(time series)论文总结

AWSDM 2025于2025年3月10号到14号在德国汉诺威举行&#xff08;Hannover, Germany&#xff09; 本文总结了WSDM 2024有关时间序列&#xff08;time series&#xff09;的相关论文&#xff0c;如有疏漏&#xff0c;欢迎大家补充。&#xff08;没有时空数据相关的论文&#xff0…

反直觉导致卡关-迫击炮谜题

这个谜题&#xff0c;在两周目中先后卡了我至少三个小时&#xff0c;先后缓慢装填并发射迫击炮弹尝试了数百次。 一周目卡了很久&#xff0c;稀里糊涂的过了&#xff0c;想不到二周目还会卡那么久。 研究了很多播主的攻略&#xff0c;但还是一头雾水&#xff0c; 直到分析其…

庐山派K230学习日记4 PWM控制

1 本节介绍​ &#x1f4dd;本节您将学习如何通过将K230开发板的GPIO引脚复用为PWM功能并输出PWM信号&#xff1b;实现输出PWM信号及控制板载无源蜂鸣器发出声音。 &#x1f3c6;学习目标 1️⃣如何将GPIO引脚配置为PWM模式&#xff0c;通过40Pin排针中的部分引脚来输出PWM信号…

c语言的文件操作与文件缓冲区

目录 C语言文件操作函数汇总 简单介绍文件 为什么使用文件 什么是文件 文件名 二进制文件和文本文件 流和标准流 流 标准流 文件指针 文件的打开和关闭 文件的顺序读写 顺序读写函数介绍 文件的随机读写 fseek ftell rewind 文件读取结束的判定 文件缓冲区 缓…

嵌入式linux中socket控制与实现

一、概述 1、首先网络,一看到这个词,我们就会想到IP地址和端口号,那IP地址和端口各有什么作用呢? (1)IP地址如身份证一样,是标识的电脑的,一台电脑只有一个IP地址。 (2)端口提供了一种访问通道,服务器一般都是通过知名端口号来识别某个服务。例如,对于每个TCP/IP实…

Nginx:动静分离

什么是动静分离? 动静分离 是指将网站中的静态资源(如图片、样式表、脚本等)和动态内容(如 PHP、Python、Node.js 等后端生成的内容)分开部署和处理。这样做的好处是可以利用不同的服务器或缓存策略来优化不同类型的资源。 动静分离的好处 提高性能:静态资源可以直接从…

PADS Layout 差分线设计规则及其设计规则约束的详细过程步骤

一般我们的电路板有很多的差分线,有90欧姆的差分线,也有100欧姆的差分线,90欧姆的差分线主要是针对USB的差分线,特别是对于USB HUB的板子,那么我们就要设置差分线。一般我们设置差分线,一般要切换到Router里面来设置,如下所示: 那么设置差分对,一般要对原理图和Router…

计算机网络--路由表的更新

一、方法 【计算机网络习题-RIP路由表更新-哔哩哔哩】 二、举个例子 例1 例2

概述(讲讲python基本语法和第三方库)

我是北子&#xff0c;这是我自己写的python教程&#xff0c;主要是记录自己的学习成果方便自己日后复习&#xff0c; 我先学了C/C&#xff0c;所以这套教程中可能会将很多概念和C/C去对比&#xff0c;所以该教程大概不适合零基础的人。 it seems that python nowadays 只在人工…

redux用法总结

redux用法总结 目录 基本概念工作原理核心概念基本使用异步操作 Redux ThunkRedux Saga React 集成Redux Toolkit最佳实践 基本概念 什么是 Redux&#xff1f; Redux 是一个可预测的状态容器&#xff0c;用于管理 JavaScript 应用的状态。它遵循三个基本原则&#xff1a; …

Gitee上传项目代码教程(详细)

工具必备&#xff1a;Git Bash 上传步骤 1.在Gitee创建项目仓库 2.进入本地项目目录 右键打开Git Bash here 3.配置用户名和邮箱 如果之前给git配置过用户名和邮箱可跳过 查看Git是否配置成功&#xff1a;git config --list git config --global user.name "xxx"…

ARM CCA机密计算安全模型之安全生命周期管理

安全之安全(security)博客目录导读 目录 一、固件启用的调试 二、CCA系统安全生命周期 三、重新供应 四、可信子系统与CCA HES 启用 CCA&#xff08;机密计算架构&#xff09;的安全系统是指 CCA 平台的实现处于可信状态。 由于多种原因&#xff0c;CCA 启用系统可能处于不…

计算机视觉CV期末总复习

1.计算机视觉基础 数字图像表示 二值图像 仅包含黑白两种颜色的图像&#xff0c;只使用1个比特为&#xff08;0黑或1白&#xff09;表示 彩色图像&#xff1a;分不同的颜色空间 gray灰度图像 每个像素只有一个采样颜色&#xff0c;取值范围0--255&#xff0c;为8比特位&a…

web安全常用靶场

这里写自定义目录标题 phpstydy2018pikachuxss-labs phpstydy2018 网盘地址 提取码: nxnw ‌phpStudy是一款专为PHP开发者设计的集成环境工具&#xff0c;主要用于简化PHP开发环境的搭建过程。‌ 它集成了Apache、MySQL、PHP等核心组件&#xff0c;用户只需进行一次性安装&a…