news 2026/4/23 13:39:42

LeetCode 438. 找到字符串中所有字母异位词(滑动窗口解法,附完整代码)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
LeetCode 438. 找到字符串中所有字母异位词(滑动窗口解法,附完整代码)

本文针对 LeetCode 中等难度题目 438. 找到字符串中所有字母异位词,采用滑动窗口思路实现解题,附完整可运行Java代码、详细思路拆解、代码注释及复杂度分析,新手也能轻松理解,复制即可发布到CSDN。

题目链接:LeetCode 438. 找到字符串中所有字母异位词

一、题目描述(清晰易懂,贴合原题)

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

核心定义:字母异位词指由相同字母按不同顺序组成的字符串(例如 "abc" 和 "cba"、"bac" 都是异位词)。

示例 1

输入: s = "cbaebabacd", p = "abc" 输出: [0,6] 解释: 起始索引等于 0 的子串是 "cba", 它是 "abc" 的异位词。 起始索引等于 6 的子串是 "bac", 它是 "abc" 的异位词。

示例 2

输入: s = "abab", p = "ab" 输出: [0,1,2] 解释: 起始索引等于 0 的子串是 "ab", 它是 "ab" 的异位词。 起始索引等于 1 的子串是 "ba", 它是 "ab" 的异位词。 起始索引等于 2 的子串是 "ab", 它是 "ab" 的异位词。

二、解题思路(滑动窗口核心逻辑)

本题核心是找到 s 中所有长度等于 p 的子串,且该子串与 p 是字母异位词。由于异位词的本质是「字符种类和数量完全相同,仅顺序不同」,因此可以借助「排序 + 滑动窗口」的思路解题,步骤如下:

  1. 边界判断:如果 s 的长度小于 p 的长度,直接返回空列表(不可能存在符合条件的子串);

  2. 预处理 p:将 p 转换为字符数组并排序,排序后,所有异位词的排序结果都与 p 的排序结果一致(核心关键);

  3. 初始化滑动窗口:窗口长度固定为 p 的长度(因为异位词长度必须与 p 一致),左指针 left 初始为 0,右指针 right 初始为 pLen - 1(窗口初始范围 [0, pLen-1]);

  4. 滑动窗口遍历 s:

    1. 提取当前窗口的子串,转换为字符数组并排序;

    2. 比较当前窗口排序后的字符数组与 p 排序后的字符数组,若相等,则当前窗口是 p 的异位词,将左指针(子串起始索引)加入结果列表;

    3. 窗口滑动:左指针和右指针同时向右移动 1 位,保持窗口长度不变,继续遍历,直到右指针超出 s 的范围。

思路优势:逻辑简单、易于理解,无需复杂的数据结构,适合新手入门滑动窗口题型,代码可读性高。

三、完整解题代码(带详细注释,可直接运行)

代码采用 Java 编写,严格按照上述思路实现,注释清晰,可直接复制到 IDE 运行,也可直接提交到 LeetCode 通过所有测试用例。

import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class Solution { public List<Integer> findAnagrams(String s, String p) { // 存放结果的列表,用于存储所有符合条件的子串起始索引 List<Integer> result = new ArrayList<>(); // 获取字符串 s 和 p 的长度,用于后续边界判断和窗口初始化 int sLen = s.length(); int pLen = p.length(); // 边界判断:如果 s 的长度小于 p 的长度,不可能存在异位词,直接返回空列表 if (sLen < pLen) { return result; } // 将 p 转换成字符数组,并进行排序 // 核心逻辑:异位词排序后结果完全一致,以此作为判断依据 char[] pArray = p.toCharArray(); Arrays.sort(pArray); // 排序后 pArray 例如 "abc" -> ['a','b','c'] // 初始化滑动窗口的左右指针 int left = 0; // 左指针,指向当前窗口的起始索引(即子串的起始索引) int right = pLen - 1; // 右指针,指向当前窗口的结束索引,窗口长度固定为 pLen // 当右指针没有超出 s 的范围时,继续滑动窗口遍历 while (right < sLen) { // 提取当前窗口的子串(substring 左闭右开,因此 right+1) String windowStr = s.substring(left, right + 1); // 将窗口子串转为字符数组,便于排序和比较 char[] windowArray = windowStr.toCharArray(); // 对窗口内的字符数组进行排序 Arrays.sort(windowArray); // 比较排序后的窗口字符数组和排序后的 p 字符数组 // 若相等,说明当前窗口是 p 的异位词,将左指针(起始索引)加入结果列表 if (Arrays.equals(windowArray, pArray)) { result.add(left); } // 滑动窗口:左指针和右指针同时向右移动一位,保持窗口长度不变 left++; right++; } // 返回所有符合条件的子串起始索引 return result; } }

四、代码测试验证(贴合示例,确保正确)

针对题目给出的两个示例,测试代码运行结果,确保与预期一致,验证代码正确性。

测试示例 1

输入:s = "cbaebabacd", p = "abc"

运行过程:

  • p 排序后为 ['a','b','c'],窗口长度为 3;

  • 窗口 [0,2](子串 "cba"),排序后为 ['a','b','c'],与 p 相等,加入 0;

  • 依次滑动窗口,直到窗口 [6,8](子串 "bac"),排序后为 ['a','b','c'],加入 6;

  • 最终输出:[0,6],与示例一致。

测试示例 2

输入:s = "abab", p = "ab"

运行过程:

  • p 排序后为 ['a','b'],窗口长度为 2;

  • 窗口 [0,1](子串 "ab"),排序后匹配,加入 0;

  • 窗口 [1,2](子串 "ba"),排序后匹配,加入 1;

  • 窗口 [2,3](子串 "ab"),排序后匹配,加入 2;

  • 最终输出:[0,1,2],与示例一致。

五、复杂度分析(面试高频考点)

分析代码的时间复杂度和空间复杂度,帮助理解算法效率,应对面试提问。

1. 时间复杂度

设 s 的长度为 n,p 的长度为 m。

  • 预处理 p:将 p 转为字符数组并排序,时间复杂度为 O(m log m);

  • 滑动窗口遍历:窗口数量为 n - m + 1 个,每个窗口的子串排序时间为 O(m log m);

  • 总时间复杂度:O(m log m + (n - m + 1) * m log m) = O(n * m log m)。

说明:该复杂度适合中等难度题目要求,对于数据量不大的场景完全适用;若想优化时间复杂度,可采用「哈希表计数」替代排序,将时间复杂度优化为 O(n),后续可补充优化思路。

2. 空间复杂度

O(m):主要用于存储 p 的字符数组和窗口的字符数组,空间大小取决于 p 的长度 m;结果列表的空间不计入算法本身的空间复杂度(属于输出所需空间)。

六、注意事项(避坑指南)

  • 边界处理:必须先判断 sLen < pLen 的情况,否则会出现数组越界或无效窗口;

  • substring 方法:Java 中 substring(left, right) 是左闭右开区间,因此提取窗口子串时,右边界需写 right + 1;

  • 排序一致性:必须保证 p 和窗口子串的排序逻辑一致(均使用 Arrays.sort()),否则会出现匹配错误;

  • 窗口滑动:左指针和右指针必须同时移动,保持窗口长度固定为 p 的长度,不可只移动一个指针。

七、总结

本题是滑动窗口的经典应用,核心利用「异位词排序后一致」的特性,将复杂的异位词判断转化为简单的数组比较,思路简洁、代码易实现,非常适合新手入门练习。

如果想进一步优化效率,可替换排序逻辑为「哈希表计数」:统计 p 中每个字符的出现次数,再用滑动窗口维护当前窗口的字符计数,通过比较计数是否一致来判断是否为异位词,可将时间复杂度优化至 O(n),感兴趣的可以自行尝试实现。

本文代码可直接复制运行,提交 LeetCode 可通过所有测试用例,欢迎点赞、收藏,如有疑问或优化建议,可在评论区留言交流。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 13:37:24

3步构建:用Finnhub Python打造专业金融数据系统

3步构建&#xff1a;用Finnhub Python打造专业金融数据系统 【免费下载链接】finnhub-python Finnhub Python API Client. Finnhub API provides institutional-grade financial data to investors, fintech startups and investment firms. We support real-time stock price,…

作者头像 李华
网站建设 2026/4/23 13:36:30

删掉一个用户的 SAP HANA Secondary Credentials,不只是执行一条 DROP CREDENTIAL

在做 SAP HANA 联邦访问治理时,最容易被低估的一步,不是建 remote source,也不是把用户映射好,而是把已经不该存在的凭据干净地回收掉。很多系统平时跑得很稳,远程表能查,数据同步任务也在走,于是大家天然会把注意力放在连通性、适配器、证书和权限上。可一旦账号轮换、…

作者头像 李华
网站建设 2026/4/23 13:32:46

思源宋体TTF:零成本获取专业中文排版终极方案

思源宋体TTF&#xff1a;零成本获取专业中文排版终极方案 【免费下载链接】source-han-serif-ttf Source Han Serif TTF 项目地址: https://gitcode.com/gh_mirrors/so/source-han-serif-ttf 还在为中文设计项目的字体选择而苦恼吗&#xff1f;商业字体价格高昂&#xf…

作者头像 李华
网站建设 2026/4/23 13:29:27

如何用HTTrack快速搭建网站离线镜像:免费开源工具完整指南

如何用HTTrack快速搭建网站离线镜像&#xff1a;免费开源工具完整指南 【免费下载链接】httrack HTTrack Website Copier, copy websites to your computer (Official repository) 项目地址: https://gitcode.com/gh_mirrors/ht/httrack HTTrack是一款功能强大的免费开源…

作者头像 李华