leetcode面试经典150题——32 串联所有单词的子串(中等+困难)

题目: 串联所有单词的子串(1中等)

描述

给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。

异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。

示例 1:

输入: s = “cbaebabacd”, p = “abc”
输出: [0,6]
解释:
起始索引等于 0 的子串是 “cba”, 它是 “abc” 的异位词。
起始索引等于 6 的子串是 “bac”, 它是 “abc” 的异位词。
leetcode链接

方法一:滑动窗口
我们定义一个长度为p.size()大小的窗口,在s中不断移动此大小固定的窗口,并且比较窗口内的元素是否由p中的元素组成,考虑到题目给出的字符串都是由26个小写的字母组成因此,我们比较窗口内的元素,可以统计窗口内每个字母出现的次数,和p中每个字母出现的次数是否相同,如果相同,那么此窗口即为所求子串,因此我们定义两个大小为26的vector1和vector2,分别存储窗口中单词出现的次数和p中单词出现的次数。
时间复杂度:o(m+(n-m)*26) 需要o(m)来初始化vector存储单词的数量,后面有n-m个窗口,因此需要比较n-m次单词的数量,每次比较需要比较26个元素,因此时间复杂度为o((n-m)*26)
空间复杂度:o(1) 只需要常量级的空间

我们先统计第一个窗口的字母数量,再循环统计后面窗口的字母数量,如图所示,一边删除前一个单词(第一个指针),一边增加后一个窗口字母(后一个指针),即可得到当前指针内窗口字母的数量
在这里插入图片描述

vector<int> findAnagrams(string s, string p) {int n = s.size();int m = p.size();vector<int> ans;//s的大小小于p时候,肯定不存在满足条件子串if(n<m){return ans;}vector<int> sCount(26,0);vector<int> pCount(26,0);//先统计第一个窗口单词出现的次数for(int i=0;i<m;i++){sCount[s[i]-'a']++;pCount[p[i]-'a']++;}//比较第一个窗口是否为所求子串if(sCount==pCount){ans.push_back(0);}for(int i=0;i<n-m;i++){//统计下一个窗口的字母数量sCount[s[i]-'a']--;sCount[s[i+m]-'a']++;if(sCount==pCount){ans.push_back(i+1);}}return ans;
}

方法二:
考虑我们方法一花费的时间主要在滑动窗口每种字母数量与p的对比上,因此我们方法二不再统计每个窗口的字母数量,我们存储滑动窗口和p的每种单词的数量差值,并且用differ记录数量不一样的字母的个数,那么如果differ=0,表示所有字母的数量都相同,那么该窗口即为所求窗口,因此我们通过判断differ是否为0来判断是否为子串,省去了判断每一种字母数量的时间。
时间复杂度:o(m+n-m) o(m)用来初始化vector,后面有n-m个窗口需要比较,比较的时间复杂度为o(1)
空间复杂度:o(1) 申请了常量级的空间

vector<int> findAnagrams(string s, string p) {int n = s.size();int m = p.size();vector<int> ans;if(n<m){return ans;}vector<int> count(26,0);for(int i=0;i<m;i++){count[s[i]-'a']++;count[p[i]-'a']--;}int differ = 0;for(int i=0;i<26;i++){//统计第一个窗口不同数量字母的个数if(count[i]!=0){differ++;}}if(differ == 0){//如果没有则第一个窗口即为所求的子串ans.push_back(0);}for(int i=0;i<n-m;i++){if (count[s[i] - 'a'] == 1) {  // 窗口中字母 s[i] 的数量与字符串 p 中的数量从不同变得相同--differ;} else if (count[s[i] - 'a'] == 0) {  // 窗口中字母 s[i] 的数量与字符串 p 中的数量从相同变得不同++differ;}--count[s[i] - 'a'];if (count[s[i + m] - 'a'] == -1) {  // 窗口中字母 s[i+pLen] 的数量与字符串 p 中的数量从不同变得相同--differ;} else if (count[s[i + m] - 'a'] == 0) {  // 窗口中字母 s[i+pLen] 的数量与字符串 p 中的数量从相同变得不同++differ;}++count[s[i + m] - 'a'];if(differ==0){ans.push_back(i+1);}}return ans;
}

题目: 串联所有单词的子串(2困难)

描述
给定一个字符串 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] 也是可以的。

leetcode链接

方法一:
类似于上题的方法二,我们用differ记录窗口单词出现次数和words中出现次数之差,如果differ为空,那么说明窗口中的单词和words中的单词相同。
定义n为words的大小,m为words中每个单词的长度,ls为s字符串的长度,那么每个窗口的长度应该为nm。首先我们需要将字符串s分成单词组,即分成一组有长度为m的单词组成的单词组,那么应该有m种分法,这里解释一下为什么是m种:假如字符串0123456按两个一分,那么有0 12 34 56和01 23 45 6这两种分法,如果按三个一分,那么有0 123 456和01 234 56和0123 456这三种分法,以此类推字符串按m个一分一共有m种分法,然后对于这里的每一种分法我们进行滑动窗口,来判断当前窗口是否为所求的子串,窗口一次移动一个单词的长度,即为移动m,那么即为左边减去一个单词,右边加上一个单词。
时间复杂度:o(ls
m) 一共有m种分法,每一种分法我们都需要利用滑动窗口,而滑动窗口的时间复杂度为o(ls),所以总时间复杂度为o(lsm)
空间复杂度:o(n
m) 一共m种分法,每一种都需要定义大小为n的unordered_map

vector<int> findSubstring(string s, vector<string>& words) {int n = words.size();int m = words[0].size();int ls = s.size();vector<int> ans;//枚举每一种单词组合的起始位置 for(int i=0;i<m&&i+n*m<=ls;i++){unordered_map<string,int> differ;for(int j = 0;j<n;j++){//统计窗口中单词出现的次数 differ[s.substr(i + j * m, m)]++;}for(int j=0;j<n;j++){//如果窗口中单词出现的次数和words中一样,那么在differ中删去 if(--differ[words[j]]==0){differ.erase(words[j]);}}//ls-m*n为剩余的字母数量,滑动窗口,每次移动一个单词的长度 for(int start=i;start<ls-m*n+1;start+=m){if(start!=i){//右边加入一个单词 string word = s.substr(start+(n-1)*m,m);if(++differ[word]==0){differ.erase(word);}//左边减去一个单词 word = s.substr(start-m,m);if(--differ[word]==0){differ.erase(word);}}//如果窗口中所有单词出现的次数和words一样则为所求子串 if(differ.empty()){ans.push_back(start);}}}return ans;
}

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

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

相关文章

【涂鸦T2-U】1、开发环境搭建

前言 本章介绍T2-U的开发环境搭建流程&#xff0c;以及一些遇到的问题。 一、资料 试用网址&#xff1a; 【新品体验】涂鸦 T2-U 开发板免费试用 涂鸦官网文档&#xff1a; 涂鸦 T2-U 开发板 T2-U 模组规格书 T2-U 开发板 淘宝(资料较全)&#xff1a; 涂鸦智能 TuyaOS开发…

【C语言】字母转换大小写的三种方法

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:C语言 ⚙️操作环境:Visual Studio 2022 目录 方法一&#xff1a;库函数法 1.小写转换大写&#xff1a;toupper()函数 2.大写转换小写&#xff1a;tolower()函数 方法二&#xff1a;自定义函数加减32法 1.小写转换大…

Redis报错:JedisConnectionException: Could not get a resource from the pool

1、问题描述&#xff1a; redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool 2、简要分析&#xff1a; redis.clients.util.Pool.getResource会从JedisPool实例池中返回一个可用的redis连接。分析源码可知JedisPool 继承了 r…

BigDecimal的使用全面总结

BigDecimal BigDecimal可以表示任意大小&#xff0c;任意精度的有符号十进制数。所以不用怕精度问题&#xff0c;也不用怕大小问题&#xff0c;放心使用就行了。就是要注意的是&#xff0c;使用的时候有一些注意点。还有就是要注意避免创建的时候存在精度问题&#xff0c;尤其…

Spring全面详解(学习总结)

Spring FrameWork一、 前言二、IOC(控制反转)2.1 对于IOC的理解2.2如何使用IOC2.3配置文件的解读2.4IOC容器创建bean的两种方式2.5从IOC容器中取bean2.6bean的属性如果包含特殊字符 三、DI(依赖注入)四、Spring中的bean五、Spring中的继承六、Spring的依赖七、Spring读取外部资…

【咕咕送书 | 第六期】深入浅出阐述嵌入式虚拟机原理,实现“小而能”嵌入式虚拟机!

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏:《粉丝福利》 《linux深造日志》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 文章目录 ⛳️ 写在前面参与规则引言一、为什么嵌入式系统需要虚拟化技术&#xff1f;1.1 专家推荐 二、本书适合谁&#x…

WiFi的CSMA/CA竞争窗口流程简述

1、若站点最初有数据要发送&#xff08;不是发送不成功再进行重传的那种&#xff09;&#xff0c;且检测到信道空闲&#xff0c;在等待DIFS后&#xff0c;就发送整个数据帧。 2、否则&#xff0c;站点执行退避算法。一旦检测到信道忙&#xff0c;就冻结退避计时器。只要信道空…

Less 安装教程

文章目录 前言LESS的系统要求安装LESS例子输出Less编译css工具后言 前言 hello world欢迎来到前端的新世界 &#x1f61c;当前文章系列专栏&#xff1a;Sass和Less &#x1f431;‍&#x1f453;博主在前端领域还有很多知识和技术需要掌握&#xff0c;正在不断努力填补技术短板…

error LNK2038: 检测到“RuntimeLibrary”的不匹配项 解决方法

问题&#xff1a; 我们在使用Visual Studio编程的时候偶尔会遇到以下三种报错&#xff1a; error LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MD_DynamicRelease”不匹配值“MDd_DynamicDebug” &#xff08;引用的是release模式&#xff0c;但设置成debug模式了…

操作系统——进程管理

文章目录 进程和线程进程的概念进程和程序的区别PCB(进程控制块)程序是如何运行的进程的特征进程的状态和状态转换五态模型 进程控制进程状态装换为啥需要保证原子性如何实现原语的原子性&#xff1f; 进程控制相关原语进程创建进程终止进程的阻塞和唤醒进程的唤醒进程的切换 进…

1603. 整数集合划分(2016年408数据结构算法题)

一、题目 1603. 整数集合划分https://www.acwing.com/problem/content/description/1605/ 二、算法的基本设计思想 由题意知&#xff0c;将最小的 个元素放在 中&#xff0c;其余的元素放在 中&#xff0c;分组结果即可满足题目要求。仿照快速排序的思想&#xff0c;基于枢…

Vue 2.0源码分析-Virtual DOM

Virtual DOM 这个概念相信大部分人都不会陌生&#xff0c;它产生的前提是浏览器中的 DOM 是很“昂贵"的&#xff0c;为了更直观的感受&#xff0c;我们可以简单的把一个简单的 div 元素的属性都打印出来&#xff0c;如图所示&#xff1a; 可以看到&#xff0c;真正的 DOM …

地铁在线售票vue票务系统uniAPP+vue 微信小程序

功能介绍 管理员 &#xff08;1&#xff09;管理员登录功能 &#xff08;2&#xff09;查看和修改线路信息 &#xff08;3&#xff09;减少线路 &#xff08;4&#xff09;修改价格&#xff08;5站3元 5-10 5元 10-15站6元 往上8元&#xff09; &#xff08;5&#xff09;删除用…

吾爱破解置顶的“太极”,太好用了吧!

日常工作和娱乐&#xff0c;都需要用到不同类型的软件&#xff0c;哪怕软件体积不大&#xff0c;也必须安装&#xff0c;否则到用时找不到就非常麻烦了。 其实&#xff0c;很多软件不一定一样不剩地全部安装一遍&#xff0c;一方面原因是用的不多&#xff0c;另一方面多少有点…

Android设计模式--外观模式

弈之为术&#xff0c;在人自悟 一&#xff0c;定义 外观模式要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行。提供一个高层次的接口&#xff0c;使得子系统更易于使用。 外观模式在开发中的使用频率是非常高的&#xff0c;尤其是在第三方的SDK里面&#xff0…

Django之admin页面样式定制(Simpleui)

好久不见&#xff0c;各位it朋友们&#xff01; 本篇文章我将向各位介绍Django框架中admin后台页面样式定制的一个插件库&#xff0c;名为Simpleui。 一&#xff09;简介 SimpleUI是一款简单易用的用户界面&#xff08;UI&#xff09;库&#xff0c;旨在帮助开发人员快速构建…

清华提出 SoRA,参数量只有 LoRA 的 70%,表现更好!

现在有很多关于大型语言模型&#xff08;LLM&#xff09;的研究&#xff0c;都围绕着如何高效微调展开。微调是利用模型在大规模通用数据上学到的知识&#xff0c;通过有针对性的小规模下游任务数据&#xff0c;使模型更好地适应具体任务的训练方法。 在先前的工作中&#xff…

基于驾驶训练算法优化概率神经网络PNN的分类预测 - 附代码

基于驾驶训练算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于驾驶训练算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于驾驶训练优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针对PNN神…

Robots 元标签与 X-Robots 标签

Robots Meta Tag 和 X-Robots-Tag 是两个常用的 HTML 标签&#xff0c;它们对观察机动爬虫和其他网络机器人很有启发性。这些标签可以控制您的网页如何被记录和显示。 什么是机器人元标记&#xff1f; 机器人元标记是一个 HTML 标签&#xff0c;它提供信息来查看电机爬虫和其…

Figma 插件学习(二)- 常用属性和方法

一. 如何调试figma插件 Plugins > Development > Show/Hide console 打开控制台即可开始调试 二.节点类型 根据不同的节点类型&#xff0c;也是会有不同的方法和属性&#xff0c;介绍几个常用节点类型 1.FrameNode 框架节点是用于定义布局层次结构的容器。它类似于HTM…