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

相关文章

关于C++中的虚拟继承的一些总结(虚拟继承,覆盖,派生,隐藏)

1.为什么要引入虚拟继承 虚拟继承是多重继承中特有的概念。虚拟基类是为解决多重继承而出现的。如:类D继承自类B1、B2,而类B1、B2都继承自类A,因此在类D中两次出现类A中的变量和函数。为了节省内存空间,可以将B1、B2对A的继承定义为虚拟继承,而A就成了虚拟基类。实现的代码如下: class A class B1:public virtual A; class B2:pu

十五.各设计模式总结与对比

1.各设计模式总结与对比 1.1.课程目标 1、 简要分析GoF 23种设计模式和设计原则,做整体认知。 2、 剖析Spirng的编程思想,启发思维,为之后深入学习Spring做铺垫。 3、 了解各设计模式之间的关联,解决设计模式混淆的问题。 1.2.内容定位 1、 掌握设计模式的"道" ,而不只是"术" 2、 道可道非常道,滴水石穿非一日之功,做好长期修炼的准备。 3、 不要为了

通过高德api查询所有店铺地址信息

通过高德api查询所有店铺地址电话信息 需求:通过高德api查询所有店铺地址信息需求分析具体实现1、申请高德appkey2、下载types city 字典值3、具体代码调用 需求:通过高德api查询所有店铺地址信息 需求分析 查询现有高德api发现现有接口关键字搜索API服务地址: https://developer.amap.com/api/webservice/gui

人工智能机器学习算法总结神经网络算法(前向及反向传播)

1.定义,意义和优缺点 定义: 神经网络算法是一种模仿人类大脑神经元之间连接方式的机器学习算法。通过多层神经元的组合和激活函数的非线性转换,神经网络能够学习数据的特征和模式,实现对复杂数据的建模和预测。(我们可以借助人类的神经元模型来更好的帮助我们理解该算法的本质,不过这里需要说明的是,虽然名字是神经网络,并且结构等等也是借鉴了神经网络,但其原型以及算法本质上还和生物层面的神经网络运行原理存在

Java注解详细总结

什么是注解?         Java注解是代码中的特殊标记,比如@Override、@Test等,作用是:让其他程序根据注解信息决定怎么执行该程序。         注解不光可以用在方法上,还可以用在类上、变量上、构造器上等位置。 自定义注解  现在我们自定义一个MyTest注解 public @interface MyTest{String aaa();boolean bbb()

tensorboard-----summary用法总结

Tensorflow学习笔记——Summary用法         最近在研究tensorflow自带的例程speech_command,顺便学习tensorflow的一些基本用法。 其中tensorboard 作为一款可视化神器,可以说是学习tensorflow时模型训练以及参数可视化的法宝。 而在训练过程中,主要用到了tf.summary()的各类方法,能够保存训练过程以及参数分布图并在

vue3项目将所有访问后端springboot的接口统一管理带跨域

vue3项目将所有访问后端springboot的接口统一管理带跨域 一、前言1.安装Axios2.创建Axios实例3.创建API服务文件4.在组件中使用API服务 二、跨域三、总结 一、前言 在Vue 3项目中,统一管理所有访问后端Spring Boot接口的最佳实践是创建一个专门的API服务层。这可以让你的代码更加模块化、可维护和集中管理。你可以使用Axios库作为HTT

LeetCode--231 2的幂

题目 给定一个整数,编写一个函数来判断它是否是 2 的幂次方。 示例 示例 1:输入: 1输出: true解释: 20 = 1示例 2:输入: 16输出: true解释: 24 = 16示例 3:输入: 218输出: false class Solution {public:bool isPowerOfTwo(int n) {if (n <= 0) return fals

LeetCode--234 回文链表

题目 请判断一个链表是否为回文链表。 示例 示例 1:输入: 1->2输出: false示例 2:输入: 1->2->2->1输出: true /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode(int x) : val

LeetCode--220 存在重复元素 III

题目 给定一个整数数组,判断数组中是否有两个不同的索引 i 和 j,使得 nums [i] 和 nums [j] 的差的绝对值最大为 t,并且 i 和 j 之间的差的绝对值最大为 ķ。 示例 示例 1:输入: nums = [1,2,3,1], k = 3, t = 0输出: true示例 2:输入: nums = [1,0,1,1], k = 1, t = 2输出: true示例