Leetcode 每日一题 30.串联所有单词的子串

server/2024/11/29 5:01:48/

目录

问题描述

示例

问题分析

算法设计

1. 初始化

2. 滑动窗口

3. 窗口扩展和收缩

4. 检查子串

5. 返回结果

过题图片

代码实现

题目地址

总结


问题描述

给定一个字符串 s 和一个字符串数组 wordswords 中所有字符串长度相同。s 中的串联子串是指一个包含 words 中所有字符串以任意顺序排列连接起来的子串。我们需要返回所有串联子串在 s 中的开始索引。

示例

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

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

  3. 输入:s = "barfoofoobarthefoobarman", words = ["bar","foo","the"] 输出:[6,9,12]

问题分析

这个问题可以通过滑动窗口和哈希表的方法来解决。我们需要检查字符串 s 中的每个可能的子串,看它是否由 words 数组中的所有单词组成。由于 words 中的单词长度相同,我们可以利用这个特性来优化我们的搜索。

算法设计

1. 初始化

  • 创建一个空的 ArrayList 来存储结果。
  • 检查输入字符串 s 和单词数组 words 是否为空,如果为空则直接返回空列表。
  • 获取单词数组中每个单词的长度 oneLen
  • 使用 HashMap 来存储每个单词出现的次数。

2. 滑动窗口

  • 外层循环从 0 到 s.length() - oneLen * words.length,这是因为我们需要检查 s 中所有可能的子串。
  • 对于每个起始位置 i,我们使用两个指针 left 和 right 来表示当前窗口的边界,并在窗口内维护一个哈希表 tem 来记录当前窗口中单词的出现次数。

3. 窗口扩展和收缩

  • 内层循环通过移动 right 指针来扩展窗口,直到窗口的大小超过字符串 s 的长度。
  • 如果当前窗口中的字符串 str 不在 map 中,清空 tem 并重置 left 指针,重新开始计数。
  • 如果 str 在 map 中,更新 tem 中 str 的计数。
  • 如果 tem 中 str 的计数超过了 map 中的计数,收缩窗口直到 tem 中 str 的计数不超过 map 中的计数。

4. 检查子串

  • 如果 tem 中的单词计数与 words 数组中的单词计数相等,则说明找到了一个符合条件的子串,将其起始位置 left 添加到结果列表中。
  • 为了寻找下一个可能的子串,移除当前子串的第一个单词,并更新 left 指针。

5. 返回结果

  • 返回包含所有子串起始位置的列表。

过题图片

代码实现

 

java

class Solution {public List<Integer> findSubstring(String s, String[] words) {List<Integer> res = new ArrayList<>();int m = s.length(), n = words.length;if (m == 0 || n == 0) return res;int oneLen = words[0].length();Map<String, Integer> map = new HashMap<>();for (String word : words) {map.put(word, map.getOrDefault(word, 0) + 1);}for (int i = 0; i <= m - oneLen * n; i++) {Map<String, Integer> tem = new HashMap<>();int count = 0;for (int j = 0; j < n; j++) {String str = s.substring(i + j * oneLen, i + (j + 1) * oneLen);if (!map.containsKey(str) || tem.getOrDefault(str, 0) >= map.get(str)) {i += oneLen * (j - count);tem.clear();count = 0;} else {tem.put(str, tem.getOrDefault(str, 0) + 1);count++;}}if (count == n) {for (int k = 0; k < oneLen; k++) {res.add(i);i += oneLen;for (int j = 0; j < n - 1; j++) {String str = s.substring(i + j * oneLen, i + (j + 1) * oneLen);tem.put(str, tem.getOrDefault(str, 0) - 1);if (tem.get(str) == 0) {i += oneLen * (n - 1 - count);tem.clear();count = 0;break;}}}}}return res;}
}

题目地址

30. 串联所有单词的子串 - 力扣(LeetCode)

总结

这个问题考察了滑动窗口和哈希表的应用,通过维护一个当前窗口内单词的出现次数,我们可以有效地检查每个可能的子串是否满足条件。这种方法的时间复杂度为 O(n * m),其中 n 是 words 数组的长度,m 是字符串 s 的长度。


http://www.ppmy.cn/server/145819.html

相关文章

Python 使用 OpenCV 将 MP4 转换为 GIF图

以下是使用 Python 和 OpenCV 将 MP4 转换为 GIF 的示例代码&#xff1a; python import cv2 import imageiodef mp4_to_gif(mp4_path, gif_path, fps10, start_timeNone, end_timeNone):"""将MP4视频转换为GIF动图。:param mp4_path: 输入MP4视频的路径。:pa…

【探寻密码的奥秘】-000:密码相关概念定义及介绍(持续更新~~)

密码相关概念 1、密码学 1、密码学 密码学是研究密码与密码活动本质和规律&#xff0c;以及指导密码实践的科学&#xff0c;主要探索密码编码和密码分析的一般规律&#xff0c;它是一门结合数学、计算机科学、信息通信系统等多门学科为一体的综合性学科。 密码学的常见应用场景…

算法篇:贪心算法

题目一&#xff1a;均分纸牌 有n堆纸牌&#xff0c;编号分别为 1&#xff0c;2&#xff0c;…,n1&#xff0c;2&#xff0c;…,n。每堆上有若干张&#xff0c;但纸牌总数必为nn的倍数。可以在任一堆上取若干张纸牌&#xff0c;然后移动。 移牌规则为&#xff1a;在编号为11的…

读书笔记_《创华为.任正非传》_精华书摘

人生经历 43岁&#xff0c;开始创建华为 爷爷:金华火腿乡间厨师 父亲: 1910年生&#xff0c;北平民大经济系读书->职业学校任教->国民党兵工厂会计&#xff0c;组织读书会(读书会后来有很多人在新中国成立后成为高级干部。) 母亲: 高中毕业&#xff0c;乡村教师&#xf…

MacBook上安装 Windows 10 后,System 进程 CPU 占用 100% 的问题

在 MacBook 2014 上安装 Windows 10 后&#xff0c;System 进程 CPU 占用 100% 的问题通常与以下因素有关&#xff1a; 1. 驱动程序问题 在 Mac 上运行 Windows 通常需要通过 Boot Camp 提供正确的驱动程序。不兼容或缺失的驱动可能导致 CPU 高占用。 解决方法 检查驱动程序是…

14、保存与加载PyTorch训练的模型和超参数

文章目录 1. state_dict2. 模型保存3. check_point4. 详细保存5. Docker6. 机器学习常用库 1. state_dict nn.Module 类是所有神经网络构建的基类&#xff0c;即自己构建一个深度神经网络也是需要继承自nn.Module类才行&#xff0c;并且nn.Module中的state_dict包含神经网络中…

【杂谈】-Linux中的GUI与图形栈

Linux中的GUI与图形栈 在本文中&#xff0c;我们将探讨基于Linux操作系统中使用的图形栈。我们将了解使图形应用程序成为可能的不同技术&#xff0c;以及它们是如何相互交互的。我们将从基础开始&#xff0c;逐步引导至高级的GUI工具包。 最后&#xff0c;我们将讨论这些技术…

使用 Go 语言封装 MinIO 相关操作

目录 使用 Go 语言封装 MinIO 相关操作背景介绍代码实现结构体定义初始化 MinIO 客户端上传文件下载文件列出文件删除文件获取文件的预签名 URL 使用示例总结 使用 Go 语言封装 MinIO 相关操作 背景介绍 MinIO 是一个高性能的对象存储服务&#xff0c;兼容 Amazon S3 API&…