Problem: 438. 找到字符串中所有字母异位词
题目:给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。

【LeetCode 热题 100】438. 找到字符串中所有字母异位词——(解法一)定长滑动窗口+哈希表
【LeetCode 热题 100】438. 找到字符串中所有字母异位词——(解法三)不定长滑动窗口+数组

整体思路

这段代码同样旨在解决 “在一个字符串 s 中找出所有模式串 p 的异位词” 的问题。与上一个使用 HashMap 的版本相比,此版本采用了 固定大小的数组 作为频率计数的工具,这是一种针对特定字符集(此处为小写英文字母)的常见优化。

算法的核心思路依然是 滑动窗口,但具体实现细节有所不同:

  1. 数据结构选择与预处理

    • 该实现选择了两个大小为 26 的整型数组 cntPcntS 来分别存储模式串 p 和当前滑动窗口的字符频率。
    • 前提与优势:这个选择基于一个重要假设——输入字符串 sp 只包含小写英文字母。利用 char - 'a' 的技巧,可以将每个字符映射到数组的 0-25 索引上,这比 HashMap 更快且内存占用更低。
    • 首先,代码遍历模式串 p,将其字符频率统计到 cntP 数组中。这个数组是固定不变的“目标”。
  2. 一体化的滑动窗口遍历

    • 与上一个版本先初始化窗口再滑动的两步法不同,此版本将窗口的初始化、扩张、校验和收缩整合在一个 for 循环中。
    • 循环由一个 right 指针驱动,从头到尾遍历主串 s
    • 窗口扩张:在每次迭代中,首先将 right 指针指向的字符计入窗口频率数组 cntS
    • 窗口形成与校验:通过 left = right - m + 1 计算出窗口的左边界。
      • if (left < 0) 这个条件用于处理窗口还未形成完整大小(长度为 m)的初始阶段。在窗口大小不足 m 时,只进行扩张,不进行比较和收缩。
      • left >= 0 时,说明窗口已经达到了 m 的长度。此时,使用 Arrays.equals(cntP, cntS) 来比较两个频率数组。Arrays.equals 会逐一比较数组中的每个元素,如果所有元素都相等,则证明当前窗口内的子串是 p 的一个异位词,将其起始索引 left 加入结果列表。
    • 窗口收缩:在完成校验后(无论是否匹配),将 left 指针指向的字符从窗口中移除(即在 cntS 中将其频率减一),为下一次迭代做准备。这样,窗口就整体向右平移了一格。
  3. 返回结果

    • 循环结束后,返回包含所有起始索引的结果列表 ans

这种一体化的实现方式代码更紧凑,逻辑流程非常清晰:每一步都“加一个右边的,(可能的话)比一下,再减一个左边的”。

完整代码

class Solution {/*** 在字符串 s 中查找 p 的所有异位词的起始索引。* 此版本使用数组进行频率统计,优化了性能。* @param s 主字符串 (假定只包含小写字母)* @param p 模式字符串 (假定只包含小写字母)* @return 一个包含所有匹配起始索引的列表*/public List<Integer> findAnagrams(String s, String p) {// ans 用于存储结果,即所有异位词的起始索引List<Integer> ans = new ArrayList<>();// n 是主串 s 的长度,m 是模式串 p 的长度int n = s.length();int m = p.length();// 如果主串比模式串还短,直接返回空列表if (n < m) {return ans;}// cntS: 存储当前滑动窗口内子串的字符频率// cntP: 存储模式串 p 的字符频率// 使用大小为 26 的数组,因为题目隐含了输入为小写英文字母int[] cntS = new int[26];int[] cntP = new int[26];// 步骤 1: 统计模式串 p 中每个字符的出现次数for (char c : p.toCharArray()) {// 'c' - 'a' 将字符映射到 0-25 的索引cntP[c - 'a']++;}// 步骤 2: 滑动窗口遍历主串 sfor (int right = 0; right < n; right++) {// a. 窗口扩张:将右边界字符加入窗口的频率统计中cntS[s.charAt(right) - 'a']++;// 计算当前窗口的左边界索引int left = right - m + 1;// 判断窗口是否已形成。当 left < 0 时,窗口大小不足 m,跳过比较和收缩步骤。if (left < 0) {continue;}// b. 窗口内校验:当窗口大小正好为 m 时,比较窗口和模式串的频率数组// Arrays.equals() 逐元素比较两个数组,如果完全相同则返回 trueif (Arrays.equals(cntP, cntS)) {// 如果是异位词,将当前窗口的起始索引 left 加入结果列表ans.add(left);}// c. 窗口收缩:将即将移出窗口的左边界字符的频率减一cntS[s.charAt(left) - 'a']--;}// 返回最终的结果列表return ans;}
}

时空复杂度

时间复杂度:O(N + M)
  1. 模式串频率统计for (char c : p.toCharArray()) 循环遍历模式串 p 一次。设 p 的长度为 M,此步骤时间复杂度为 O(M)
  2. 滑动窗口遍历for (int right = 0; right < n; right++) 循环遍历主串 s 一次。设 s 的长度为 N,此循环执行 N 次。
    • 在循环内部:
      • 数组的读写操作(cntS[...]++cntS[...]--)是 O(1) 的。
      • Arrays.equals(cntP, cntS) 操作需要比较两个数组中的所有元素。由于数组大小是固定的 26,所以比较的次数也是常数 26。因此,该操作的时间复杂度为 O(26),即 O(1)
    • 所以,整个循环的时间复杂度是 N 次 O(1) 操作,总计为 O(N)

综合分析
总时间复杂度 = 预处理 p 的时间 + 遍历 s 的时间 = O(M) + O(N) = O(N + M)
由于通常 N 是远大于 M 的,所以有时也近似地称为 O(N),但 O(N + M) 是更精确的表述。

空间复杂度:O(k) 或 O(1)
  1. 主要存储开销:算法使用了两个整型数组 cntScntP
    • 每个数组的大小都是 26,这是一个固定的常数,不随输入字符串 sp 的长度变化而变化。
    • k 在这里代表字符集的大小,即 26。
  2. 其他变量n, m, right, left 等变量占用的是常数空间 O(1)。
  3. 结果列表ans 列表用于存储输出,其空间不计入辅助空间复杂度。

综合分析
算法所需的额外辅助空间主要由两个频率数组决定。由于数组大小是固定的,所以空间复杂度是 O(k),其中 k=26。因为 k 是一个常数,所以也可以表述为 O(1)。这表示算法占用的额外内存是一个常数,非常高效。

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

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

相关文章

PAC 学习框架:机器学习的可靠性工程

PAC&#xff08;Probably Approximately Correct&#xff09; 是机器学习理论的核心框架&#xff0c;用于量化学习算法的可靠性。它回答了一个关键问题&#xff1a; “需要多少训练样本&#xff0c;才能以较高概率学到一个近似正确的模型&#xff1f;” 一、PAC 名称拆解 术语…

嵌入式C语言数组:数组/字符数组

1. 数组 1.1 一维数组 数组是一串连续的地址&#xff1b; 数组名是地址常量&#xff0c;代表数组的起始地址&#xff1b; sizeof&#xff08;数组名&#xff09; 可得出数组的总内存空间&#xff1b; C 语言对数组不做越界检查&#xff0c;使用时应注意&#xff1b; 数组不…

变长字节的数字表示法vb224

开始 数字有大有小&#xff0c;用多少字节表示呢&#xff1f; 本文描述的方案&#xff0c;采用变化的长度。vb是varying bytes的意思&#xff0c;224是表示它特征的一个数。 第一版&#xff1a; 每个字节8比特&#xff0c;最高的1比特用来表示“是否连续”&#xff0c;0表示…

ByteMD+CozeAPI+Coze平台Agent+Next搭建AI辅助博客撰写平台(逻辑清楚,推荐!)

背景&#xff1a; 现在主流的博客平台AI接入不够完善&#xff0c;如CSDN接入的AI助手不支持多模态数据的交互、稀土掘金的编辑器AI功能似乎还没能很好接入&#xff08;哈哈哈&#xff0c;似乎在考虑布局什么&#xff1f;&#xff09; 痛点分析&#xff1a; 用户常常以截图的形式…

【数据标注师】关键词标注

目录 一、 **理解关键词标注的核心逻辑**1. **三大标注原则**2. **关键词类型体系** 二、 **四阶训练体系**▶ **阶段1&#xff1a;基础规则内化**▶ **阶段2&#xff1a;语义浓缩训练**▶ **阶段3&#xff1a;场景化标注策略**▶ **阶段4&#xff1a;工具效率提升** 三、 **五…

for each循环语句

for each循环语句 for each.....nextFor Each 的案例 for each…next 1、循环对象合集 worksheets workbooks range range("区域")selection (选中的区域)usedrange或者currentregion 返回的单元格区域格式&#xff1a; for each 变量名 in 对象集合(范围)循环内容…

基于LQR控制器的六自由度四旋翼无人机模型simulink建模与仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序 4.系统原理简介 5.参考文献 6.完整工程文件 1.课题概述 四旋翼无人机因其结构简单、机动性强和成本低廉等特点&#xff0c;在航拍测绘、物流运输、灾害救援等领域得到广泛应用。六自由度&#xff08;3维平移3维旋转&#xff0…

vftp centos 离线部署

install_ftp_offline.sh vsftpd-3.0.2-28.el7.x86_64.rpm #!/bin/bash# 一键安装配置vsftpd脚本&#xff08;开放根目录&#xff0c;禁用chroot&#xff09;# 安装vsftpd RPM包 echo "正在安装vsftpd..." rpm -ivh vsftpd-3.0.2-28.el7.x86_64.rpm if [ $? -ne 0 …

【数据标注】事件标注1

目录 **一、 深入理解事件标注的核心概念****二、 系统学习&#xff1a;从理论到实践****1. 吃透标注指南****2. 语言学基础补充****3. 事件结构解析训练** **三、 分阶段实践&#xff1a;从简单到复杂****阶段1&#xff1a;基础标注训练****阶段2&#xff1a;进阶挑战****阶段…

在 Ansys Electronics Desktop 中启用额外的 CPU 内核和 GPU

Ansys Electronics Desktop (AEDT) 可以通过利用多个 CPU 内核和 GPU 加速来显著缩短仿真时间。但是,启用其他计算资源除了基本求解器许可证外,还需要适当的高性能计算 (HPC) 许可证。 默认情况下,基本许可证最多允许使用 4 个内核,而无需任何其他 HPC 许可。借助 Ans…

R语言机器学习算法实战系列(二十六)基于tidymodels的XGBoost二分类器全流程实战

禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍加载R包数据准备数据探索转换因子查看属性相关性配对图PCA 可视化缺失值、异常值处理 & 特征标准数据分割构建模型与调参模型评估模型可解释性(变量重要性、SHAP、DALEX)变量…

零基础langchain实战一:模型、提示词和解析器

一&#xff0c;使用python调取大模型api 1&#xff0c;获取api_key 获取api_key 在各个大模型的官网中获取。 2&#xff0c;设置api_key 方式一&#xff1a; 在系统环境中可直接执行python代码&#xff1a;这里以deepseek为例 import os os.environ["DEEPSEEK_API_…

Pytorch分布式通讯为什么要求Tensor连续(Contiguous)

参考资料&#xff1a; https://github.com/pytorch/pytorch/issues/73515 https://www.cnblogs.com/X1OO/articles/18171700 由于业务原因&#xff0c;需要在Pytorch代码中使用分布式通讯来把计算负载平均到多张显卡上。在无数次确认我的业务代码没问题之后&#xff0c;我开始把…

关于前端页面上传图片检测

依赖于前文&#xff0c;linux系统上部署yolo识别图片,远程宿主机访问docker全流程(https://blog.csdn.net/yanzhuang521967/article/details/148777650?spm1001.2014.3001.5501) fastapi把端口暴露出来 后端代码 from fastapi import FastAPI, UploadFile, File, HTTPExcep…

第十三章---软件工程过程管理

仅供参考 文章目录 一、Gantt图是做什么的。二、软件配置的概念 一、Gantt图是做什么的。 Gantt 图&#xff08;甘特图&#xff09;是软件项目管理中用于进度安排和可视化管理的重要工具&#xff0c;主要用于展示任务的时间安排、进度状态及任务之间的依赖关系 Gantt 图是一种…

多模态大语言模型arxiv论文略读(140)

SemiHVision: Enhancing Medical Multimodal Models with a Semi-Human Annotated Dataset and Fine-Tuned Instruction Generation ➡️ 论文标题&#xff1a;SemiHVision: Enhancing Medical Multimodal Models with a Semi-Human Annotated Dataset and Fine-Tuned Instruc…

模型预测控制专题:无差拍预测电流控制

前言&#xff1a; 为了进一步深入探索电机控制这个领域&#xff0c;找到了一些志同道合的同学一起来进行知识的分享。最近群里投票后续更新内容&#xff0c;票数最多的方向就是模型预测控制&#xff1b;无论这个方向目前是否还是很火&#xff0c;至少应大家需求&#xff0c;工…

Youtube双塔模型

1. 引言 在大规模推荐系统中&#xff0c;如何从海量候选物品中高效检索出用户可能感兴趣的物品是一个关键问题。传统的矩阵分解方法在处理稀疏数据和长尾分布时面临挑战。本文介绍了一种基于双塔神经网络的建模框架&#xff0c;通过采样偏差校正技术提升推荐质量&#xff0c;并…

.net8创建tcp服务接收数据通过websocket广播

注册TCP服务器 注册WebSocket中间件 using System.Net; using System.Net.Sockets; using System.Text; using System.Text.Json; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.SignalR.Client; using Microsoft.AspNet…

阅读服务使用示例(HarmonyOS Reader Kit)

阅读服务使用示例&#xff08;HarmonyOS Reader Kit&#xff09; Reader Kit到底能干啥&#xff1f; 第一次搞电子书阅读器&#xff0c;真以为就是“读txt显示出来”这么简单&#xff0c;结果各种格式、排版、翻页动效、目录跳转……全是坑。还好有Reader Kit&#xff0c;救了…