LeetCode_30_困难_串联所有单词的子串

文章目录

  • 1. 题目
  • 2. 思路及代码实现详解(Python)
    • 2.1 滑动窗口


1. 题目

给定一个字符串 s s s 和一个字符串数组 w o r d s words words w o r d s words words 中所有字符串 长度相同

s s s 中的 串联子串 是指一个包含 w o r d s words words 中所有字符串以任意顺序排列连接起来的子串。

例如,如果 w o r d s = [ " a b " , " c d " , " e f " ] words = ["ab","cd","ef"] words=["ab","cd","ef"], 那么 " a b c d e f " , " a b e f c d " , " c d a b e f " , " c d e f a b " , " e f a b c d " , " e f c d a b " "abcdef", "abefcd","cdabef", "cdefab","efabcd", "efcdab" "abcdef""abefcd""cdabef""cdefab""efabcd""efcdab" 都是串联子串。 " a c d b e f " "acdbef" "acdbef" 不是串联子串,因为他不是任何 w o r d s words words 排列的连接。

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

示例 1:

输入: s = " b a r f o o t h e f o o b a r m a n " , w o r d s = [ " f o o " , " b a r " ] s = "barfoothefoobarman", words = ["foo","bar"] s="barfoothefoobarman",words=["foo","bar"]
输出: [ 0 , 9 ] [0,9] [0,9]
解释:因为 w o r d s . l e n g t h = = 2 words.length == 2 words.length==2 同时 w o r d s [ i ] . l e n g t h = = 3 words[i].length == 3 words[i].length==3,连接的子字符串的长度必须为 6 6 6
子串 " b a r f o o " "barfoo" "barfoo" 开始位置是 0 0 0。它是 w o r d s words words 中以 [ " b a r " , " f o o " ] ["bar","foo"] ["bar","foo"] 顺序排列的连接。
子串 " f o o b a r " "foobar" "foobar" 开始位置是 9 9 9。它是 w o r d s words words 中以 [ " f o o " , " b a r " ] ["foo","bar"] ["foo","bar"] 顺序排列的连接。
输出顺序无关紧要。返回 [ 9 , 0 ] [9,0] [9,0] 也是可以的。

示例 2:

输入: s = " w o r d g o o d g o o d g o o d b e s t w o r d " , w o r d s = [ " w o r d " , " g o o d " , " b e s t " , " w o r d " ] s = "wordgoodgoodgoodbestword", words = ["word","good","best","word"] s="wordgoodgoodgoodbestword",words=["word","good","best","word"]
输出: [ ] [] []
解释:因为 w o r d s . l e n g t h = = 4 words.length == 4 words.length==4 并且 w o r d s [ i ] . l e n g t h = = 4 words[i].length == 4 words[i].length==4,所以串联子串的长度必须为 16 16 16
s s s 中没有子串长度为 16 16 16 并且等于 w o r d s words words 的任何顺序排列的连接。
所以我们返回一个空数组。

示例 3:

输入: s = " b a r f o o f o o b a r t h e f o o b a r m a n " , w o r d s = [ " b a r " , " f o o " , " t h e " ] s = "barfoofoobarthefoobarman", words = ["bar","foo","the"] s="barfoofoobarthefoobarman",words=["bar","foo","the"]
输出: [ 6 , 9 , 12 ] [6,9,12] [6,9,12]
解释:因为 w o r d s . l e n g t h = = 3 words.length == 3 words.length==3 并且 w o r d s [ i ] . l e n g t h = = 3 words[i].length == 3 words[i].length==3,所以串联子串的长度必须为 9 9 9
子串 " f o o b a r t h e " "foobarthe" "foobarthe" 开始位置是 6 6 6。它是 w o r d s words words 中以 [ " f o o " , " b a r " , " t h e " ] ["foo","bar","the"] ["foo","bar","the"] 顺序排列的连接。
子串 " b a r t h e f o o " "barthefoo" "barthefoo" 开始位置是 9 9 9。它是 w o r d s words words 中以 [ " b a r " , " t h e " , " f o o " ] ["bar","the","foo"] ["bar","the","foo"] 顺序排列的连接。
子串 " t h e f o o b a r " "thefoobar" "thefoobar" 开始位置是 12 12 12。它是 w o r d s words words 中以 [ " t h e " , " f o o " , " b a r " ] ["the","foo","bar"] ["the","foo","bar"] 顺序排列的连接。


提示

  • 1 < = s . l e n g t h < = 1 0 4 1 <= s.length <= 10^4 1<=s.length<=104
  • 1 < = w o r d s . l e n g t h < = 5000 1 <= words.length <= 5000 1<=words.length<=5000
  • 1 < = w o r d s [ i ] . l e n g t h < = 30 1 <= words[i].length <= 30 1<=words[i].length<=30
  • w o r d s [ i ] words[i] words[i] s s s 由小写英文字母组成

2. 思路及代码实现详解(Python)

2.1 滑动窗口

words \textit{words} words 的长度为 m m m words \textit{words} words 中每个单词的长度为 n n n s s s 的长度为 ls \textit{ls} ls。由于已知单词的长度和数量,因此可以直到串联子串的长度,并通过建立一个固定长度的窗口,并在不断滑动窗口的过程中,判断窗口中的固定长度字符串的出现次数是否与 w o r d s words words 中的一致,如果一致,则获取窗口的开始索引位置。

具体做法是,首先需要将 s s s 划分为单词组,每个单词的大小均为 n n n (首尾除外)。这样的划分方法有 n n n 种( l e n ( s ) / n len(s)/n len(s)/n 的商的情况),即先删去前 i i i i = 0 ∼ n − 1 i = 0 \sim n-1 i=0n1)个字母后,将剩下的字母进行划分,如果末尾有不到 n n n 个字母也删去。对这 n n n 种划分得到的单词数组分别使用滑动窗口对 words \textit{words} words 进行搜寻,每次向右滑动 n n n 个距离,直到 s s s 右端剩余字符数不足 n n n

划分成单词组后,一个窗口包含 s s s 中从 i i i 起始的前 m m m 个单词,用一个哈希表 differ \textit{differ} differ 表示窗口中单词频次和 words \textit{words} words 中单词频次之差,当差值为 0 0 0 时认为窗口中单词数量与 w o r d s words words 当中单词数量一致。初始化 differ \textit{differ} differ 时,出现在窗口中的单词,每出现一次,相应的值增加 1 1 1,出现在 words \textit{words} words 中的单词,每出现一次,相应的值减少 1 1 1。然后将窗口右移,右侧会加入一个单词,左侧会移出一个单词,并对 differ \textit{differ} differ 做相应的更新。窗口移动时,若出现 differ \textit{differ} differ 中值不为 0 0 0 的键的数量为 0 0 0,则表示这个窗口中的单词频次和 words \textit{words} words 中单词频次相同,窗口的左端点是一个待求的起始位置。划分的方法有 n n n 种,做 n n n 次滑动窗口后,即可找到所有可能的起始位置。

class Solution:def findSubstring(self, s: str, words: List[str]) -> List[int]:res = []m, n, ls = len(words), len(words[0]), len(s)for i in range(n):if i + m * n > ls:breakdiffer = Counter()for j in range(m):word = s[i + j * n: i + (j + 1) * n]differ[word] += 1for word in words:differ[word] -= 1if differ[word] == 0:del differ[word]for start in range(i, ls - m * n + 1, n):if start != i:word = s[start + (m - 1) * n: start + m * n]differ[word] += 1if differ[word] == 0:del differ[word]word = s[start - n: start]differ[word] -= 1if differ[word] == 0:del differ[word]if len(differ) == 0:res.append(start)return res

该算法遍历了 n n n 种窗口的左端起始位置,每次窗口滑动的时间复杂度为 O ( l s ) O(ls) O(ls),总的渐进复杂度为 O ( l s × n ) O(ls\times n) O(ls×n),空间复杂度为 O ( m × n ) O(m\times n) O(m×n),主要是保存单词出现频次的哈希表开销。

执行用时:97 ms
消耗内存:11.21 MB

题解来源:力扣官方题解

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

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

相关文章

Leetcode 3081. Replace Question Marks in String to Minimize Its Value

Leetcode 3081. Replace Question Marks in String to Minimize Its Value 1. 解题思路2. 代码实现 题目链接&#xff1a;3081. Replace Question Marks in String to Minimize Its Value 1. 解题思路 这一题其实感觉还是有点难的&#xff0c;主要一开始确实走了弯路&#x…

Python 异步编程(Async/Await)

Python 中的异步编程是一种编程模式&#xff0c;它允许程序在等待 I/O 操作&#xff08;如网络请求、文件读写等&#xff09;的同时继续执行其他任务&#xff0c;而不会阻塞整个程序。这种方式可以提高程序的效率和响应性。 在 Python 中&#xff0c;异步编程的核心概念是使用…

数据结构:9、二叉树

在上堆中已经介绍了什么是二叉树&#xff0c;所以这里直接写二叉树实现。 1、二叉树的构建 二叉树的构建第一步肯定是初始化&#xff0c;也就是构建这棵树&#xff0c;这里是利用前序遍历构建的&#xff0c;因为这里是利用链表形式创建的二叉树&#xff0c;所以这里就是和之前…

在java中当main方法执行完,堆内存会自己释放内存吗?(附解释)

在Java中&#xff0c;堆内存中的对象由Java虚拟机&#xff08;JVM&#xff09;的垃圾回收器自动进行内存管理和释放。当一个对象不再被引用时&#xff0c;垃圾回收器会在适当的时机自动回收该对象所占用的内存空间。这意味着在main方法执行完毕后&#xff0c;堆内存中的对象会被…

redis常用五大数据类型

目录 Key 字符串String 常用命令 列表List 常用命令 集合Set 常用命令 Hash哈希 键值对集合 有序集合Zset Redis新数据类型 Key set key value...添加keykeys *查看当前库中所有的keyexist key该key是否存在type keykey的类型del key删除keyunlink key根据value选择非阻塞…

Tomcat的Host Manager页面403的原因和解决办法

目录 背景 原因: 解决方案 背景 一直报错 403 Access Denied You are not authorized to view this page.By default the Host Manager is only accessible from a browser running on the same machine as Tomcat. If you wish to modify this restriction, youll need to…

C++ UML类图

参考文章&#xff1a; &#xff08;1&#xff09;C UML类图详解 &#xff08;2&#xff09;C基础——用C实例理解UML类图 &#xff08;3&#xff09;C设计模式——UML类图 &#xff08;4&#xff09;[UML] 类图介绍 —— 程序员&#xff08;灵魂画手&#xff09;必备画图技能之…

自然语言处理与图像描述

自然语言处理&#xff08;NLP&#xff09;与图像描述是两个相互关联且互补的领域。自然语言处理主要涉及计算机和人类&#xff08;自然&#xff09;语言之间的相互作用&#xff0c;包括文本分析、理解、生成和翻译等。而图像描述则是指使用自然语言来表达图像内容的过程&#x…

剑指offer面试题40 数组中只出现一次的数字

考察点 异或运算&#xff0c;与运算知识点 题目 分析 本题目要求数组中只出现一次的俩个数字&#xff0c;并且要求O(1)时间复杂度和空间复杂度。试想一下如果只有一个数字出现一次&#xff0c;那么针对全部元素做异或运算就可以了&#xff0c;因为相同元素异或为0。现在有俩…

2 使用GPU理解并行计算

2.1 简介 本章旨在对并行程序设计的基本概念及其与GPU技术的联系做一个宽泛的介绍。本章主要面向具有串行程序设计经验&#xff0c;但对并行处理概念缺乏了解的读者。我们将用GPU的基本知识来讲解并行程序设计的基本概念。 2.2 传统的串行代码 绝大多数程序员是在串行程序占据…

手撕算法-二叉树的最大深度

描述&#xff1a;分析&#xff1a;求以节点root为根节点的树的最大深度。可以进行拆分&#xff1a;root为根节点的树的最大深度 max(左子树的最大深度, 右子树最大深度&#xff09;1 截止条件是节点为空&#xff0c;深度为0&#xff1b; 代码&#xff1a; public int maxDep…

HarmonyOS如何创建及调用三方库

介绍 本篇主要向开发者展示了在Stage模型中&#xff0c;如何调用已经上架到三方库中心的社区库和项目内创建的本地库。效果图如下&#xff1a; 相关概念 Navigation&#xff1a;一般作为Page页面的根容器&#xff0c;通过属性设置来展示页面的标题、工具栏、菜单。Tabs&#…

Java + sa-token统一身份认证开发笔记

官网地址&#xff1a;Sa-Token 统一认证服务端 直接用的官网的demo&#xff0c;稍加改动&#xff0c;因为要前后端分离&#xff0c;加了一个H5Controller&#xff0c;官网也有详细介绍&#xff0c;这一部分不难&#xff0c;照着做就行了 配置文件&#xff1a; # Sa-Token 配…

Java反射获取类信息的方式

获取Java类信息的方式有以下几种&#xff1a; 通过对象实例获取类信息&#xff1a; 可以通过对象实例的getClass()方法获取该对象所属类的Class对象。 通过类字面值获取类信息&#xff1a; 可以使用类字面值来获得类的Class对象。例如&#xff1a;String.class。 通过Class.for…

如何注册澳大利亚公司 注册澳大利亚公司流程 注册澳大利亚公司条件

澳大利亚注册公司的优势&#xff1a; 1、无需注册资本&#xff0c;手续简单方便可直接进行注册。 2、公司注册程序简单&#xff0c;提供公司名称、及股份比例即可&#xff0c; 3、税 务机关免费上门咨询服务&#xff0c;贸易局提供免费的信息。 4、在澳大利亚设立公司&…

vo、po、dto、bo、pojo、entity

VO&#xff1a;Value Object&#xff0c;值对象。 通常用于业务层之间的数据传递&#xff0c;由new创建&#xff0c;由GC回收&#xff1b;例如&#xff1a;将商品信息和用户信息重新用一个对象封装起来。和PO一样也是仅仅包含数据而已&#xff0c;但应是抽象出的业务对象&…

全网良心开源知识库:AI学习者的宝藏之地

导语&#xff1a;在这个信息爆炸的时代&#xff0c;想要入门AI&#xff0c;找到最一流的学习资源并非易事。然而&#xff0c;有一个地方&#xff0c;能让你免费学习AI&#xff0c;获取最顶尖的知识&#xff0c;还能加入最优秀的AI学习圈。今天&#xff0c;我要向大家推荐的&…

Jumpserver 堡垒机用户启用双因子登录

前言&#xff1a; 堡垒机双因子登录 堡垒机往往是内部权限的集合体&#xff0c;拿到了堡垒机的用户账号密码&#xff0c;很容易就顺藤摸瓜攻破各种应用系统&#xff0c;除了常规的用户名复杂密码的要求外&#xff0c;我们常常都要求采用双因子的登录方式。双因子最常见的就是账…

【Qt学习笔记】(六)界面优化

界面优化 1 QSS1.1 背景介绍1.2 基本语法1.3 QSS设置方式1.3.1 指定控件样式设计1.3.2 全局样式设置1.3.3 使用 Qt Designer 编辑样式 1.4 选择器1.4.1选择器概况1.4.2 子控件选择器&#xff08;Sub-Controls&#xff09;1.4.3伪类选择器(Pseudo-States) 1.5 样式属性1.5.1 盒模…

MyBatis:编织数据之美的艺术

在数据库交互的舞台上&#xff0c;MyBatis就如同一位出色的编码艺术家&#xff0c;通过其独特的姿态和技巧&#xff0c;将数据库操作变得既优雅又高效。在这篇博客中&#xff0c;我们将深入研究MyBatis的使用详解&#xff0c;揭开其中的奥秘&#xff0c;感受数据之美的艺术之旅…