当前位置: 首页 > news >正文

LeetCode LCR 015. 找到字符串中所有字母异位词 (Java)

LCR 015. 找到字符串中所有字母异位词

题目描述

给定两个字符串 sp,要求找到 s 中所有是 p 的变位词(字母相同但排列不同)的子串,并返回这些子串的起始索引。例如:

  • 输入 s = "cbaebabacd", p = "abc",输出 [0, 6],因为子串 "cba""bac""abc" 的变位词。
  • 输入 s = "abab", p = "ab",输出 [0, 1, 2],因为每个长为 2 的子串都是 "ab" 的变位词。

初始思路:暴力滑动窗口
核心思想
  1. 固定窗口长度:窗口长度为 p.length(),逐个遍历 s 中所有可能的窗口。
  2. 统计字符频率:对每个窗口,统计字符出现次数,与 p 的字符频率比对。
  3. 记录匹配结果:若窗口字符频率与 p 完全一致,记录当前窗口的起始索引。
代码实现
public static List<Integer> findAnagrams_2(String s, String p) {int windowLen = p.length();List<Integer> result = new ArrayList<>();int[] pCount = new int[26];// 统计 p 的字符频率for (char c : p.toCharArray()) {pCount[c - 'a']++;}for (int left = 0; left <= s.length() - windowLen; left++) {int[] sCount = new int[26];int sign = 1;// 统计当前窗口的字符频率for (int j = left; j < left + windowLen; j++) {sCount[s.charAt(j) - 'a']++;}// 比对频率是否一致for (int j = 0; j < 26; j++) {if (sCount[j] != pCount[j]) {sign = 0;break; // 优化点:发现不一致立即跳出}}if (sign == 1) {result.add(left);}}return result;
}
复杂度分析
  • 时间复杂度:O(n * m),其中 ns 的长度,mp 的长度。每次窗口需要遍历 m 个字符,共遍历 n - m + 1 次。
  • 空间复杂度:O(1),固定使用两个长度为 26 的数组。

优化思路:动态滑动窗口
核心改进
  1. 减少重复计算:维护一个固定长度的窗口,每次移动窗口时,只需更新移除的字符和新增的字符。
  2. 差异计数器:通过一个变量记录当前窗口与 p 的频率差异,避免每次全量比对。
优化代码
public List<Integer> findAnagrams(String s, String p) {List<Integer> result = new ArrayList<>();if (s.length() < p.length()) return result;int[] pCount = new int[26];int[] sCount = new int[26];int windowLen = p.length();// 初始化 p 的字符频率和第一个窗口的 s 字符频率for (int i = 0; i < windowLen; i++) {pCount[p.charAt(i) - 'a']++;sCount[s.charAt(i) - 'a']++;}int diff = 0;for (int i = 0; i < 26; i++) {if (sCount[i] != pCount[i]) diff++;}if (diff == 0) result.add(0);// 滑动窗口:逐个右移,动态更新频率和差异for (int right = windowLen; right < s.length(); right++) {int leftChar = s.charAt(right - windowLen) - 'a';int rightChar = s.charAt(right) - 'a';// 移除左边界字符if (sCount[leftChar] == pCount[leftChar]) diff++;sCount[leftChar]--;if (sCount[leftChar] == pCount[leftChar]) diff--;// 添加右边界字符if (sCount[rightChar] == pCount[rightChar]) diff++;sCount[rightChar]++;if (sCount[rightChar] == pCount[rightChar]) diff--;if (diff == 0) {result.add(right - windowLen + 1);}}return result;
}
关键点解释
  • 窗口初始化:初始化 p 和第一个窗口的字符频率,计算初始差异值 diff
  • 滑动更新
    • 移除左边界字符:若该字符原本频率匹配,则移除后差异增加,更新后若重新匹配则差异减少。
    • 添加右边界字符:同理更新差异值。
  • 差异判断:当 diff == 0 时,当前窗口是变位词。
复杂度分析
  • 时间复杂度:O(n),仅遍历 s 一次。
  • 空间复杂度:O(1),固定使用两个长度为 26 的数组。

总结

暴力滑动窗口法直观易懂,但时间复杂度较高,适用于小规模数据。优化后的动态滑动窗口通过减少重复计算,显著提升了效率,是解决此类问题的标准方法。核心在于维护窗口的字符频率差异,避免全量比对,将时间复杂度从 O(n * m) 优化到 O(n)。

http://www.dtcms.com/a/192572.html

相关文章:

  • 【重磅】配电网智能软开关和储能联合规划
  • ZFile与Cpolar技术结合实现远程数据实时访问与集中管理的可行性分析
  • 2025认证杯数学建模第二阶段C题:化工厂生产流程的预测和控制,思路+模型+代码
  • 计算图存储采用矩阵吗,和张量关系
  • 有什么工地现场施工进度成本管理软件?工程企业数字化转型的必要性?
  • 【滑动窗口】串联所有单词的子串
  • 图片、音频、视频都能转?简鹿格式工厂了解一下
  • 深入理解 Cortex-M 的中断输入和挂起行为
  • 网络爬虫学习之httpx的使用
  • 增强 HTNN 服务网格功能:基于 Istio 的BasicAuth 与 ACL 插件开发实战
  • 【js】JavaScript的变量提升、函数声明提升
  • 知识图谱系列(2):知识图谱的技术架构与组成要素
  • 【补充笔记】修复“NameError: name ‘ZhNormalizer‘ is not defined”的直接方法
  • Kafka如何实现高性能
  • Unity碰撞检测:射线与胶囊体投射/Layer(层)、LayerMask(遮罩层)
  • Unity3D开发AI桌面精灵/宠物系列 【六】 人物模型 语音口型同步 LipSync 、梅尔频谱MFCC技术、支持中英文自定义编辑- 基于 C# 语言开发
  • Linux云计算训练营笔记day08(MySQL数据库)
  • 【上位机——WPF】Window标签常用属性
  • 【学习心得】2025年Docker Desktop安装记录
  • 阿里云ECS部署Dify
  • 阿里云CMH镜像迁移与SMC整机迁移对比及功能详解(同地域跨主体账号场景)
  • 配置VScodePython环境Python was not found;
  • 「Java EE开发指南」如何使用MyEclipse的可视化JSF编辑器设计JSP?(二)
  • PC:使用WinSCP密钥文件连接sftp服务器
  • ANTsPy:医学影像处理python库
  • Java集合详解:LinkedBlockingQueue
  • 26考研 | 王道 | 计算机组成原理 | 一、计算机系统概述
  • Window下Jmeter多机压测方法
  • 128.在 Vue 3 中使用 OpenLayers 实现绘制矩形截图并保存地图区域
  • OpenShift AI - 用 ModelCar 构建容器化模型,提升模型弹性扩展速度