leetCode 30.串联所有单词的子串

news2024/9/22 15:38:22

给定一个字符串 s 和一个字符串数组 words words 中所有字符串 长度相同s 中的 串联子串 是指一个包含  words 中所有字符串以任意顺序排列连接起来的子串。

  • 例如,如果 words = ["ab","cd","ef"], 那么 "abcdef", "abefcd""cdabef", "cdefab""efabcd", 和 "efcdab" 都是串联子串。 "acdbef" 不是串联子串,因为他不是任何 words 排列的连接。

返回所有串联子串在 s 中的开始索引。你可以以 任意顺序 返回答案。

示例 1:

输入:s = "barfoothefoobarman", words = ["foo","bar"]
输出:[0,9]

解释:因为 words.length == 2 同时 words[i].length == 3,连接的子字符串的长度必须为 6。
子串 "barfoo" 开始位置是 0。它是 words 中以 ["bar","foo"] 顺序排列的连接。
子串 "foobar" 开始位置是 9。它是 words 中以 ["foo","bar"] 顺序排列的连接。
输出顺序无关紧要。返回 [9,0] 也是可以的。

示例 2:

输入:s = "wordgoodgoodgoodbestword", words = ["word","good","best","word"]
输出:[]

解释:因为 words.length == 4 并且 words[i].length == 4,所以串联子串的长度必须为 16。
s 中没有子串长度为 16 并且等于 words 的任何顺序排列的连接。
所以我们返回一个空数组。

示例 3:

输入:s = "barfoofoobarthefoobarman", words = ["bar","foo","the"]
输出:[6,9,12]
解释:因为 words.length == 3 并且 words[i].length == 3,所以串联子串的长度必须为 9。
子串 "foobarthe" 开始位置是 6。它是 words 中以 ["foo","bar","the"] 顺序排列的连接。
子串 "barthefoo" 开始位置是 9。它是 words 中以 ["bar","the","foo"] 顺序排列的连接。
子串 "thefoobar" 开始位置是 12。它是 words 中以 ["the","foo","bar"] 顺序排列的连接。

(1)情况一,子串完全匹配

(2)情况二,遇到了不匹配的单词,直接将 left 移动到该单词的后边

  (3)情况三,遇到了符合的单词,但是次数超了

class Solution {
public:
    vector<int> findSubstring(string s, vector<string>& words) {
        vector<int> res;
        if (s.size() == 0 || words.size() == 0) {
            return res;
        }

        int wordsNum = words.size();//words的个数
        int wordLen = words[0].size();//word的长度
        int width = wordsNum*wordLen;
        if(s.size()<width) return res;// 长度不符合预期
        
        // 将单词数组构建成哈希表
        unordered_map<string,int> words_map;
        // unordered_map<string,int> tmp_map;
        string word="";
        for (string str : words) {
            words_map[str]+=1;
        }
        
        // 只遍历 0 ~ wordLen 即可,因为滑动窗口都是按照 wordLen 的倍数进行滑动的
        for(int i=0;i<wordLen;i++) {
            unordered_map<string,int> tmp_map;
            // 滑动窗口
            int left=i,right=i,count=0;
            while(right + wordLen <= s.length()) {
                string word = s.substr(right,wordLen);
                // cout<<"word : " << word<<endl;
                right += wordLen;
                if(words_map.find(word)!=words_map.end()) {
                    int num = tmp_map[word]+1;
                    // 有效单词数+1
                    tmp_map[word]+=1;
                    count++;
                    // 出现情况三,遇到了符合的单词,但是次数超了
                    if(words_map[word] < num) {
                        // 一直移除单词,知道次数符合
                        while(words_map[word] < tmp_map[word]) {
                            string deleteWord = s.substr(left,wordLen);// 要移除的单词
                            tmp_map[deleteWord]--;// 更新tmp_map
                            left+=wordLen;// 同时移动左指针
                            count--;// count数目-1
                        }
                    }
                } else {
                    // 出现情况二,遇到了不匹配的单词,直接将 left 移动到该单词的后边
                    tmp_map.clear();// 清空tmp_map
                    count=0;// 清空count
                    left=right;
                    if(left+width>s.size()) break;
                }
                if(count == wordsNum) {
                    res.push_back(left);
                    // 出现情况一,子串完全匹配,我们将上一个子串的第一个单词从tmp中移除,窗口后移wordLen
                    string firstWord = s.substr(left,wordLen);
                    tmp_map[firstWord]--;
                    count--;
                    left += wordLen;
                }
            }
        }
        return res;
    }
};

改进一下:

class Solution {
public:
    vector<int> findSubstring(string s, vector<string>& words) {
        vector<int> res;
        if (s.size() == 0 || words.size() == 0) {
            return res;
        }
        

        int wordsNum = words.size();//words的个数
        int wordLen = words[0].size();//word的长度
        int width = wordsNum*wordLen;
        if(s.size()<width) return res;// 长度不符合预期
        
        // 将单词数组构建成哈希表
        unordered_map<string,int> words_map;
        // unordered_map<string,int> tmp_map;
        string word="";
        for (string str : words) {
            words_map[str]+=1;
        }

        if(wordLen==1 && words_map.size()==1) {
            char c=words[0][0];
            for(int i=0;i<=s.size()-width;i++) {
                if(s[i]==c)
                    res.push_back(i);
            }
            return res;
        }
        
        // 只遍历 0 ~ wordLen 即可,因为滑动窗口都是按照 wordLen 的倍数进行滑动的
        for(int i=0;i<wordLen;i++) {
            unordered_map<string,int> tmp_map;
            // 滑动窗口
            int left=i,right=i,count=0;
            while(right + wordLen <= s.length()) {
                string word = s.substr(right,wordLen);
                // cout<<"word : " << word<<endl;
                right += wordLen;
                if(words_map.find(word)!=words_map.end()) {
                    int num = tmp_map[word]+1;
                    // 有效单词数+1
                    tmp_map[word]+=1;
                    count++;
                    // 出现情况三,遇到了符合的单词,但是次数超了
                    if(words_map[word] < num) {
                        // 一直移除单词,知道次数符合
                        while(words_map[word] < tmp_map[word]) {
                            string deleteWord = s.substr(left,wordLen);// 要移除的单词
                            tmp_map[deleteWord]--;// 更新tmp_map
                            left+=wordLen;// 同时移动左指针
                            count--;// count数目-1
                        }
                    }
                } else {
                    // 出现情况二,遇到了不匹配的单词,直接将 left 移动到该单词的后边
                    tmp_map.clear();// 清空tmp_map
                    count=0;// 清空count
                    left=right;
                    if(words_map.find(s.substr(right,wordLen))==words_map.end()) {
                        right+=wordLen;
                        left=right;
                    }
                    if(left+width>s.size()) break;
                }
                if(count == wordsNum) {
                    res.push_back(left);
                    // 出现情况一,子串完全匹配,我们将上一个子串的第一个单词从tmp中移除,窗口后移wordLen
                    string firstWord = s.substr(left,wordLen);
                    tmp_map[firstWord]--;
                    count--;
                    left += wordLen;
                }
            }
        }
        return res;
    }
};

参考文章:30. 串联所有单词的子串 - 力扣(LeetCode)icon-default.png?t=N7T8https://leetcode.cn/problems/substring-with-concatenation-of-all-words/solutions/9092/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-w-6/?envType=study-plan-v2&envId=top-interview-150

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

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

相关文章

如何利用示波器解析I2C数据

前言 &#xff08;1&#xff09;如果有嵌入式企业需要招聘校园大使&#xff0c;湖南区域的日常实习&#xff0c;任何区域的暑假Linux驱动实习岗位&#xff0c;可C站直接私聊&#xff0c;或者邮件&#xff1a;zhangyixu02gmail.com&#xff0c;此消息至2025年1月1日前均有效 &am…

【5G PHY】5G SS/PBCH块介绍(一)

博主未授权任何人或组织机构转载博主任何原创文章&#xff0c;感谢各位对原创的支持&#xff01; 博主链接 本人就职于国际知名终端厂商&#xff0c;负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作&#xff0c;目前牵头6G算力网络技术标准研究。 博客…

短视频矩阵打造攻略:玩转短视频

短视频矩阵系统是一个智能的短视频创作、发布、管理和分析的平台。该方法能够帮助用户迅速搭建起自身的短视频矩阵&#xff0c;并在多个平台上进行传播与展示&#xff0c;进而提升短视频的营销效率。该短视频矩阵系统具有如下基本功能&#xff1a; 1.短视频制作&#xff1a;为用…

队列的实现方式—Python数据结构(三)

队列 1. 定义 队列是一种常见的数据结构&#xff0c;用于按照先进先出&#xff08;FIFO&#xff09;的原则管理数据项。在Python中&#xff0c;有多种方法可以实现队列&#xff0c;其中最常见的包括使用列表&#xff08;list&#xff09;和使用标准库中的 queue 模块。队列通…

docker运行nginx镜像

今天在这里讲如何在docker上运行nignx镜像&#xff0c;并将配置文件和目录挂载到宿主机上&#xff0c;以实现方便统一的管理配置信息。 首先第一步需要拉取镜像&#xff0c;我们还是拉取最新的镜像&#xff0c;不需要添加tag版本号&#xff0c; docker pull nginx 拉取结束后用…

反射的作用( 越过泛型检查 和 可以使用反射保存所有对象的具体信息 )

1、绕过 编译阶段 为集合添加数据 反射是作用在运行时的技术&#xff0c;此时集合的泛型将不能产生约束了&#xff0c;此时是可以 为集合存入其他任意类型的元素的 。泛型只是在编译阶段可以约束集合只能操作某种数据类型&#xff0c;在 编译成Class文件进入 运行阶段 的时候&a…

Zebec Protocol 薪酬支付工具 WageLink 上线,掀新一轮薪酬支付浪潮

Zebec Protocol 正在从多个方面推动流支付的应用&#xff0c;除了作为一种全新的支付手段来对支付领域进行重塑外&#xff0c;其也在以流支付体系为基础&#xff0c;不断地向薪酬发放领域深度的拓展。 在今年早些时候&#xff0c;Zebec Protocol 通过美国投资机构 Payroll Grow…

【类和对象+this引用】

文章目录 面向对象与面向过程面向对象关注的是对象&#xff0c;用类描述这个对象如何定义类如何更改类名 类的实例化this引用总结 面向对象与面向过程 面向对象就是解决问题的一种思想&#xff0c;主要依靠对象之间的交互完成一件事情。 面向过程好比传统的洗衣服方式&#x…

【RNA world】RNA的多功能性与早期生命进化

文章目录 RNARNA plays core functions in Central Dogma of BiologyrRNAsnRNA RNA worldReplication催化作用感知环境变化并作出响应 来自Manolis Kellis教授&#xff08;MIT计算生物学主任&#xff09;的课 油管链接&#xff1a;6.047/6.878 Lecture 7 - RNA folding, RNA wo…

[尚硅谷React笔记]——第5章 React 路由

目录&#xff1a; 对SPA应用的理解对路由的理解前端路由原理路由的基本使用路由组件与一般组件NavLink的使用封装NavLink组件Switch的使用解决样式丢失问题路由的模糊匹配与严格匹配Redirect的使用嵌套路由向路由组件传递params参数向路由组件传递search参数.向路由组件传递st…

【Docker从入门到入土 3】Docker镜像的创建方法

Part3 一、Docker镜像1.1 镜像的概念1.2 镜像结构的分层 二、Docker镜像的创建2.1 基于现有镜像创建2.1.1 创建思路2.1.2 举个例子 2.2 基于本地模板创建2.3 基于Dockerfile 创建 三、Dockerfile 详解3.1 Dockerfile 操作指令3.1.1 常用的操作指令3.1.2 CMD和ENTRYPOINT的区别…

【Java基础面试四十一】、说一说你对static关键字的理解

文章底部有个人公众号&#xff1a;热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享&#xff1f; 踩过的坑没必要让别人在再踩&#xff0c;自己复盘也能加深记忆。利己利人、所谓双赢。 面试官&#xff1a;说一说你对static关键字…

hdlbits系列verilog解答(异或非门)-08

文章目录 wire线网类型介绍一、问题描述二、verilog源码三、仿真结果 wire线网类型介绍 wire线网类型是verilog的一种数据类型&#xff0c;它是一种单向的物理连线。它可以是输入也可以是输出&#xff0c;它与reg寄存器数据类型不同&#xff0c;它不能存储数据&#xff0c;只能…

文件系统相关

文件系统部分的大纲要求&#xff1a; 文件系统的全局结构&#xff1a;文件系统在外存中的结构&#xff0c;文件系统在内存中的结构外存空闲空间管理办法虚拟文件系统文件系统挂载 一、文件系统的层次结构 可分为三个层次&#xff1a;最低层是对象及其属性&#xff0c;中间层…

物证管理系统|智物证DW-S404是一套成熟系统

系统背景 我司物证智能管理系统&#xff08;智物证DW-S404&#xff09;是一套成熟系统&#xff0c;依托互3D技术、RFID技术、数据库技术、AI、视频分析技术对物证进行统一管理、分析的信息化、智能化、规范化的系统。 物证是公安或者监狱处理案件的关键凭证&#xff0c;针对过…

3交换机的配置与使用

越来越发觉大学的教程是真好&#xff0c;虽然说深度可能不太够&#xff0c;但作为入门实在太好了。中国也有公开课&#xff0c;推荐中国大学MOOC&#xff0c;感谢网易有道与高教社。 最近特别累、活也特别多&#xff0c;所以学习的时间少了很多。但看到MOOC之后&#xff0c;又…

软件测试(六)自动化测试 Junit5

Junit5 selenium是自动化测试框架&#xff08;写自动化测试用例&#xff09;Junit单元测试框架&#xff08;管理写好的测试用例&#xff09; 注解&#xff1a;Test&#xff0c;Disable &#xff0c;BeforeAll&#xff0c;AfterAll&#xff0c;BeforeEach&#xff0c;AfteEach…

操作系统——多个类别产品的生产者-消费者问题(王道视频p33、课本ch6)

1.问题解剖——得到的是 1个“互斥信号量” 3个“同步信号量” 其中特别注意&#xff0c;对于盘子plate可以清空的设计4个对象的&#xff0c;但是只用这一个同步信号量就可以实现 2.代码—— 3.由于这里的同步信号量的初值都是1&#xff0c;所以&#xff0c;即使不设置互斥信…

04.Finetune vs. Prompt

目录 语言模型回顾大模型的两种路线专才通才二者的比较 专才养成记通才养成记Instruction LearningIn-context Learning 自动Prompt 部分截图来自原课程视频《2023李宏毅最新生成式AI教程》&#xff0c;B站自行搜索 语言模型回顾 GPT&#xff1a;文字接龙 How are __. Bert&a…