LeetCode题练习与总结:串联所有单词的子串

2024-03-09 18:44

本文主要是介绍LeetCode题练习与总结:串联所有单词的子串,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、题目

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

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

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

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

二、解题思路

  1. 确定单词长度:首先,我们需要知道每个单词的长度,这可以通过检查 words 数组中的第一个元素得到。

  2. 计算重复因子:由于所有单词长度相同,我们可以计算 s 中的字符数与单词长度的比值,这个比值决定了 s 中可以有多少个完整的 words 组合。

  3. 创建哈希表:为了快速查找单词,我们可以创建一个哈希表,其中键是单词,值是该单词在 words 数组中出现的次数。

  4. 滑动窗口:使用滑动窗口的方法遍历字符串 s,窗口大小为单词长度。在遍历过程中,我们检查窗口内的单词是否在哈希表中,并且它们的计数是否正确。

  5. 更新答案:每当我们找到一个有效的串联子串,我们就记录下这个子串在 s 中的起始索引,并将其添加到结果列表中。

  6. 返回结果:最后,我们返回包含所有有效起始索引的列表。

三、具体代码

import java.util.*;class Solution {public List<Integer> findSubstring(String s, String[] words) {List<Integer> result = new ArrayList<>();if (s == null || words == null || words.length == 0 || words[0].length() == 0) {return result;}int wordLen = words[0].length();int totalLen = words.length * wordLen;Map<String, Integer> wordMap = new HashMap<>();for (String word : words) {wordMap.put(word, wordMap.getOrDefault(word, 0) + 1);}int sLen = s.length();if (sLen < totalLen) {return result;}for (int i = 0; i <= sLen - totalLen; i++) {boolean valid = true;Map<String, Integer> windowMap = new HashMap<>(wordMap);for (int j = i; j < i + totalLen; j += wordLen) {String windowWord = s.substring(j, j + wordLen);if (!windowMap.containsKey(windowWord)) {valid = false;break;}windowMap.put(windowWord, windowMap.get(windowWord) - 1);if (windowMap.get(windowWord) < 0) {valid = false;break;}}if (valid) {result.add(i);}}return result;}
}

四、时间复杂度和空间复杂度

1. 时间复杂度
  • 初始化哈希表的时间复杂度是 O(N),其中 N 是 words 数组的长度。
  • 遍历字符串 s 的外层循环的时间复杂度是 O(S - totalLen + 1),其中 S 是 s 的长度。
  • 内层循环的时间复杂度是 O(M),其中 M 是 words 数组中每个单词的长度,也就是单词的固定长度。
  • 内层循环中的哈希表操作(查找和更新)的时间复杂度平均是 O(1)。
  • 将这些组合起来,总的时间复杂度是 O(N + (S - totalLen + 1) * M)。
  • 由于 M 是常数,我们可以将其简化为 O(N + S)。
2. 空间复杂度
  • 哈希表 wordMap 存储了所有单词及其出现次数,空间复杂度是 O(N)。
  • 在遍历过程中,我们创建了一个与 wordMap 大小相同的临时哈希表 windowMap,其空间复杂度也是 O(N)。
  • 结果列表 result 的空间复杂度取决于找到的串联子串的数量,最坏情况下是 O(S - totalLen + 1),但这是一个与输入数据相关的值,不是固定的。
  • 综合考虑,总的空间复杂度是 O(N + (S - totalLen + 1)),其中 O(N) 是主要部分,因为结果列表的大小通常不会超过 O(N)。
  • 在实际应用中,我们通常会忽略常数因子和较小的项,所以可以简化为 O(N)。

五、总结知识点

1. 字符串处理

  • 使用 String 类的 substring 方法来获取字符串的子串。

2. 数据结构

  • 使用 HashMap 来存储单词及其出现次数,这允许我们快速地进行查找和更新操作。
  • 使用 ArrayList 来存储结果,这是一个动态数组,可以方便地添加元素。

3. 循环结构

  • 使用 for 循环来遍历字符串 s 的所有可能的子串起始位置。
  • 使用嵌套的 for 循环(滑动窗口)来检查当前窗口内的单词是否符合要求。

4. 条件判断

  • 使用 if 语句和 boolean 类型的变量 valid 来判断当前窗口是否包含所有单词。

5. 异常处理

  • 在代码开始处,对输入参数进行空值检查,确保 swords 不为 null,且 words 数组不为空,且每个单词的长度不为零。

6. 边界条件处理

  • 在开始遍历之前,检查字符串 s 的长度是否足够包含所有单词的串联,如果不够,则直接返回空的结果列表。

7. 空间复用

  • 在每次外层循环迭代时,创建一个新的 HashMap windowMap 来跟踪当前窗口内的单词出现次数,这样可以避免在内层循环中修改外部循环的状态。

8. 集合操作

  • 使用 MapgetOrDefault 方法来获取键对应的值,如果键不存在则返回默认值(这里默认值为 0)。

9. 返回值处理

  • 在找到有效的串联子串时,将起始索引添加到结果列表中,并在最后返回这个列表。

10.代码的可读性和维护性

  • 使用有意义的变量名(如 wordLen, totalLen, wordMap, windowMap, valid)来提高代码的可读性。
  • 使用 boolean 变量 valid 来简化条件判断,使代码更加清晰。

以上就是解决这个问题的详细步骤,希望能够为各位提供启发和帮助。

这篇关于LeetCode题练习与总结:串联所有单词的子串的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/791615

相关文章

Python一次性将指定版本所有包上传PyPI镜像解决方案

《Python一次性将指定版本所有包上传PyPI镜像解决方案》本文主要介绍了一个安全、完整、可离线部署的解决方案,用于一次性准备指定Python版本的所有包,然后导出到内网环境,感兴趣的小伙伴可以跟随... 目录为什么需要这个方案完整解决方案1. 项目目录结构2. 创建智能下载脚本3. 创建包清单生成脚本4

Python中logging模块用法示例总结

《Python中logging模块用法示例总结》在Python中logging模块是一个强大的日志记录工具,它允许用户将程序运行期间产生的日志信息输出到控制台或者写入到文件中,:本文主要介绍Pyt... 目录前言一. 基本使用1. 五种日志等级2.  设置报告等级3. 自定义格式4. C语言风格的格式化方法

Spring 依赖注入与循环依赖总结

《Spring依赖注入与循环依赖总结》这篇文章给大家介绍Spring依赖注入与循环依赖总结篇,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录1. Spring 三级缓存解决循环依赖1. 创建UserService原始对象2. 将原始对象包装成工

MySQL中查询和展示LONGBLOB类型数据的技巧总结

《MySQL中查询和展示LONGBLOB类型数据的技巧总结》在MySQL中LONGBLOB是一种二进制大对象(BLOB)数据类型,用于存储大量的二进制数据,:本文主要介绍MySQL中查询和展示LO... 目录前言1. 查询 LONGBLOB 数据的大小2. 查询并展示 LONGBLOB 数据2.1 转换为十

在Java中实现线程之间的数据共享的几种方式总结

《在Java中实现线程之间的数据共享的几种方式总结》在Java中实现线程间数据共享是并发编程的核心需求,但需要谨慎处理同步问题以避免竞态条件,本文通过代码示例给大家介绍了几种主要实现方式及其最佳实践,... 目录1. 共享变量与同步机制2. 轻量级通信机制3. 线程安全容器4. 线程局部变量(ThreadL

Spring Boot 与微服务入门实战详细总结

《SpringBoot与微服务入门实战详细总结》本文讲解SpringBoot框架的核心特性如快速构建、自动配置、零XML与微服务架构的定义、演进及优缺点,涵盖开发环境准备和HelloWorld实战... 目录一、Spring Boot 核心概述二、微服务架构详解1. 微服务的定义与演进2. 微服务的优缺点三

Java通过驱动包(jar包)连接MySQL数据库的步骤总结及验证方式

《Java通过驱动包(jar包)连接MySQL数据库的步骤总结及验证方式》本文详细介绍如何使用Java通过JDBC连接MySQL数据库,包括下载驱动、配置Eclipse环境、检测数据库连接等关键步骤,... 目录一、下载驱动包二、放jar包三、检测数据库连接JavaJava 如何使用 JDBC 连接 mys

JavaSE正则表达式用法总结大全

《JavaSE正则表达式用法总结大全》正则表达式就是由一些特定的字符组成,代表的是一个规则,:本文主要介绍JavaSE正则表达式用法的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下... 目录常用的正则表达式匹配符正则表China编程达式常用的类Pattern类Matcher类PatternSynta

Python打印对象所有属性和值的方法小结

《Python打印对象所有属性和值的方法小结》在Python开发过程中,调试代码时经常需要查看对象的当前状态,也就是对象的所有属性和对应的值,然而,Python并没有像PHP的print_r那样直接提... 目录python中打印对象所有属性和值的方法实现步骤1. 使用vars()和pprint()2. 使

Python pip下载包及所有依赖到指定文件夹的步骤说明

《Pythonpip下载包及所有依赖到指定文件夹的步骤说明》为了方便开发和部署,我们常常需要将Python项目所依赖的第三方包导出到本地文件夹中,:本文主要介绍Pythonpip下载包及所有依... 目录步骤说明命令格式示例参数说明离线安装方法注意事项总结要使用pip下载包及其所有依赖到指定文件夹,请按照以