Leetcode 串联所有单词的子串

在这里插入图片描述

算法思想(中文解释)

这道题目要求我们在字符串 s 中找到所有子串,这些子串是字符串数组 words 中所有单词的串联,并且每个单词只能使用一次,且顺序可以任意。下面是代码的算法思想:


1. 核心思路

分解问题

  • 因为每个单词长度相同,我们可以使用一个滑动窗口(Sliding Window)来检查所有可能的子串。
  • 判断一个子串是否是所有单词的串联,可以通过比较单词的频次。

2. 步骤讲解

(1)初始化:
  • 单词长度:用 wordLength 表示 words 中每个单词的长度(因为题目保证它们长度相同)。
  • 总串联长度totalLength = wordLength * words.length,因为子串的长度一定是所有单词的长度之和。
  • 构造单词频次表:用 wordMap 记录 words 中每个单词的出现次数,便于后续比较。
(2)滑动窗口遍历:
  • 从字符串 s 的每个位置开始,以长度为 totalLength 的窗口进行检查:
    • 提取窗口中的子串 sub
    • 检查这个子串是否包含了 words 中所有单词且频次正确。
(3)子串验证:
  • 对于窗口中的子串 sub,将其按照 wordLength 分割成一个个小单词。
  • 检查这些小单词是否在 wordMap 中,并验证它们的出现频次是否超出限制:
    • 如果某个单词不在 wordMap 中,立即返回 false
    • 如果某个单词出现的次数超过了在 wordMap 中的次数,也返回 false
  • 如果所有单词验证通过,则说明当前窗口位置是符合要求的,记录下起始索引。

3. 时间复杂度分析

  1. 构造单词频次表O(m),其中 mwords 的长度(即单词个数)。
  2. 滑动窗口遍历:外层遍历最多需要 n - totalLength + 1 次,n 是字符串 s 的长度。
  3. 验证子串:每次验证需要遍历窗口中的所有单词,复杂度为 O(m * wordLength)

因此,总复杂度为
[ O((n - totalLength + 1) \cdot m \cdot wordLength) ]
通常可以简化为 O(n * m),适用于 s 较长和 words 较短的场景。


4. 代码逻辑解释

主函数:
  1. wordMap:统计 words 中每个单词的出现频次。
  2. 滑动窗口遍历:通过 for 循环,遍历从 0 到 s.length() - totalLength 的所有可能起始位置。
  3. 子串验证:调用辅助函数 isValid() 检查是否符合要求。
辅助函数 isValid
  1. 将子串 sub 分割成长度为 wordLength 的小单词。
  2. 使用 seen 哈希表记录窗口内每个单词的频次。
  3. wordMap 进行比较,判断是否匹配。

5. 关键优化点

  1. 滑动窗口:避免暴力检查所有子串,只检查可能的窗口,减少不必要的计算。
  2. 哈希表:使用 wordMapseen 快速判断频次关系,而不是逐一比较。
  3. 提前退出:在验证过程中,一旦发现不匹配的单词,立即退出验证,避免冗余计算。

6. 适用场景

该算法非常适用于以下情况:

  • 单词长度固定,字符串较长。
  • words 中的单词个数适中(否则频次表的维护开销较大)。

通过滑动窗口和哈希表的结合,这个算法能够高效解决题目要求。

java solution

class Solution {public List<Integer> findSubstring(String s, String[] words) {List<Integer> result = new ArrayList<>();if(s == null || s.length() == 0 || words.length == 0 || words == null) return result;//初始化辅助变量int wordsLength = words.length;int wordLength = words[0].length();int totalLength = wordLength * wordsLength;//创建频率统计哈希表Map<String, Integer> freq = new HashMap<>();for(String word:words) {freq.put(word, freq.getOrDefault(word, 0) + 1);}//变量字符串sfor(int i = 0; i <= s.length() - totalLength; i++) {//首先获取窗口内的子串String sub = s.substring(i, i + totalLength); //substring 是左闭右开//然后验证此时窗口内的子串if(isValid(sub, freq, wordLength)) {result.add(i);}}return result;}private boolean isValid(String sub, Map<String, Integer> freq, int wordLength) {Map<String, Integer> seen = new HashMap<>(); //存储子串中的单词频次for(int j = 0; j < sub.length(); j += wordLength) {//提取子串中的单词String word = sub.substring(j, j + wordLength);if(!freq.containsKey(word)) { //如果这个单词不在freq频率表中,return false;}seen.put(word, seen.getOrDefault(word, 0) + 1); //更新seen中的频次if(seen.get(word) > freq.get(word)) { //如果频次超过freq的限制return false; }}return true;}
}

182 个测试用例通过了 181 个,被全 a 的测试用例卡住了(超时),

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

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

相关文章

解析在OceanBase创建分区的常见问题|OceanBase 用户问题精粹

在《分区策略和管理分区计划的实践方案》这篇文章中&#xff0c;我们介绍了在ODC中制定分区策略及有效管理分区计划的经验。有不少用户在该帖下提出了使用中的问题&#xff0c;其中一个关于创建分区的限制条件的问题&#xff0c;也是很多用户遭遇的老问题。因此本文以其为切入&…

有哪些免费的 ERP 软件可供选择?哪些 ERP 软件使用体验较好?

想找个 “免费” 的 ERP 软件&#xff1f; 咱得知道&#xff0c;ERP 那可是涉及财务、人力、供应链、采购、销售等好多方面的重要企业软件。功能这么全&#xff0c;能免费才怪呢&#xff01;真要是有免费的&#xff0c;早就火遍大江南北&#xff0c;说不定把市场都垄断了&…

centos-stream9系统安装docker

如果之前安装过docker需要删除之前的。 sudo dnf -y remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine 安装yum-utils工具&#xff1a; dnf -y install yum-utils dnf-plugin…

了解cuda的统一内存

1. CUDA 6中的统一内存 在CUDA 6中&#xff0c;从Kepler GPU架构&#xff08;计算能力3.0或更高&#xff09;开始&#xff0c;在64位Windows 7、8和Linux操作系统&#xff08;内核2.6.18&#xff09;上开始支持统一内存. 从CUDA 6开始&#xff0c;NVIDIA推出了CUDA平台历史上…

Pytorch | 从零构建MobileNet对CIFAR10进行分类

Pytorch | 从零构建MobileNet对CIFAR10进行分类 CIFAR10数据集MobileNet设计理念网络结构技术优势应用领域 MobileNet结构代码详解结构代码代码详解DepthwiseSeparableConv 类初始化方法前向传播 forward 方法 MobileNet 类初始化方法前向传播 forward 方法 训练过程和测试结果…

Electronjs+Vue如何开发PC桌面客户端(Windows,Mac,Linux)

electronjs官网 https://www.electronjs.org/zh/ Electron开发PC桌面客户端的技术选型非常适合已经有web前端开发人员的团队。能够很丝滑的过渡。 Electron是什么&#xff1f; Electron是一个使用 JavaScript、HTML 和 CSS 构建桌面应用程序的框架。 嵌入 Chromium 和 Node.…

【1.排序】

排序 笔记记录 1.排序的基本概念1.1 排序的定义 2. 插入排序2.1 直接插入排序2.2 折半插入排序2.3 希尔排序 3. 交换排序3.1 冒泡排序3.2 快速排序 4. 选择排序4.1 简单选择排序4.2 堆排序 5. 归并排序、基数排序和计数排序5.1 归并排序4.2 基数排序4.3 计数排序 6. 各种内部排…

Linux Swap: 深入解析 mkswap, mkfs.swap, 和 swapon

文章目录 Linux Swap: 深入解析 mkswap, mkfs.swap, 和 swapon什么是 Swap&#xff1f;主要命令介绍1. mkswap2. mkfs.swap3. swapon 创建和管理 Swap 的步骤1. 创建 Swap 分区2. 初始化 Swap3. 激活 Swap4. 持久化配置5. 查看 Swap 状态 删除 Swap 分区或文件1. 停用 Swap2. 删…

取子串(指针)

#include <stdio.h> #include <string.h>char* substr(char *s, int startloc, int len) {static char result[51]; // 定义一个足够大的静态数组来存储结果static char result1[] {N,U,L,L,\0};int i, j;// 检查startloc是否在字符串的范围内if (startloc < 1…

「Mac畅玩鸿蒙与硬件45」UI互动应用篇22 - 评分统计工具

本篇将带你实现一个评分统计工具&#xff0c;用户可以对多个选项进行评分。应用会实时更新每个选项的评分结果&#xff0c;并统计平均分。这一功能适合用于问卷调查或评分统计的场景。 关键词 UI互动应用评分统计状态管理数据处理多目标评分 一、功能说明 评分统计工具允许用…

递归实现指数型枚举(递归)

92. 递归实现指数型枚举 - AcWing题库 每个数有选和不选两种情况 我们把每个数看成每层&#xff0c;可以画出一个递归搜索树 叶子节点就是我们的答案 很容易写出每dfs函数 dfs传入一个u表示层数 当层数大于我们n时&#xff0c;去判断每个数字的选择情况&#xff0c;输出被选…

Linux相关概念和易错知识点(25)(信号原理、操作系统的原理、volatile)

目录 1.信号的产生 &#xff08;1&#xff09;kill &#xff08;2&#xff09;raise、abort 2.对block、pending、handler表的管理 &#xff08;1&#xff09;信号集&#xff08;sigset_t&#xff09; &#xff08;2&#xff09;block表的管理 ①操作相关的函数 ②sigpr…

opencv中的色彩空间及其转换

在 OpenCV 中&#xff0c;色彩空间&#xff08;Color Space&#xff09;指的是表示颜色的一种方式&#xff0c;或是用数学模型对颜色的表达。不同的色彩空间采用不同的方式来描述颜色的三要素&#xff08;如亮度、饱和度、色调&#xff09;&#xff0c;因此可以在不同的应用场景…

大模型微调---Prompt-tuning微调

目录 一、前言二、Prompt-tuning实战2.1、下载模型到本地2.2、加载模型与数据集2.3、处理数据2.4、Prompt-tuning微调2.5、训练参数配置2.6、开始训练 三、模型评估四、完整训练代码 一、前言 Prompt-tuning通过修改输入文本的提示&#xff08;Prompt&#xff09;来引导模型生…

Edge Scdn用起来怎么样?

Edge Scdn&#xff1a;提升网站安全与性能的最佳选择 在当今互联网高速发展的时代&#xff0c;各种网络攻击层出不穷&#xff0c;特别是针对网站的DDoS攻击威胁&#xff0c;几乎每个行业都可能成为目标。为了确保网站的安全性与稳定性&#xff0c;越来越多的企业开始关注Edge …

通信技术以及5G和AI保障电网安全与网络安全

摘 要&#xff1a;电网安全是电力的基础&#xff0c;随着智能电网的快速发展&#xff0c;越来越多的ICT信息通信技术被应用到电力网络。本文分析了历史上一些重大电网安全与网络安全事故&#xff0c;介绍了电网安全与网络安全、通信技术与电网安全的关系以及相应的电网安全标准…

批量提取zotero的论文构建知识库做问答的大模型(可选)——含转存PDF-分割统计PDF等

文章目录 提取zotero的PDF上传到AI平台保留文件名代码分成20个PDF视频讲解 提取zotero的PDF 右键查看目录 发现目录为 C:\Users\89735\Zotero\storage 写代码: 扫描路径‘C:\Users\89735\Zotero\storage’下面的所有PDF文件,全部复制一份汇总到"C:\Users\89735\Downl…

精准采集整车信号:风丘混合动力汽车工况测试

一 背景 混合动力汽车是介于纯电动汽车与燃油汽车两者之间的一种新能源汽车。它既包含纯电动汽车无污染、启动快的优势&#xff0c;又拥有燃油车续航便捷、不受电池容量限制的特点。在当前环境下&#xff0c;混合动力汽车比纯电动汽车更符合目前的市场需求。 然而&#xff0c…

带标题和不带标题的内部表

什么是工作区&#xff1f; 什么是工作区&#xff1f;简单来说&#xff0c;工作区是单行数据。它们应具有与任何内部表相同的格式。它用于一次处理一行内部表中的数据。 内表和工作区的区别 &#xff1f; 一图胜千言 内表的类型 有两种类型的内表&#xff1a; 带 Header 行…

【图像分类实用脚本】数据可视化以及高数量类别截断

图像分类时&#xff0c;如果某个类别或者某些类别的数量远大于其他类别的话&#xff0c;模型在计算的时候&#xff0c;更倾向于拟合数量更多的类别&#xff1b;因此&#xff0c;观察类别数量以及对数据量多的类别进行截断是很有必要的。 1.准备数据 数据的格式为图像分类数据集…