LeetCode 438. 找到字符串中所有字母的异位词
题目描述
给定两个字符串 s
和 p
,找到 s
中所有 p
的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。
异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。
示例 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" 的异位词。
提示:
1
<=s.length
,p.length
<=3 * 10^4
s
和p
仅包含小写字母
Java 实现代码
java
class Solution {
public List<Integer> findAnagrams(String s, String p) {
int sLength = s.length();
int pLength = p.length();
if (sLength < pLength) {
return new ArrayList<>();
}
int[] sArr = new int[26];
int[] pArr = new int[26];
List<Integer> data = new ArrayList<>();
for (int i = 0; i < pLength; i++) {
sArr[s.charAt(i) - 'a']++;
pArr[p.charAt(i) - 'a']++;
}
for (int i = pLength; i < sLength; i++) {
if (Arrays.equals(sArr, pArr)) {
data.add(i - pLength);
}
int left = i - pLength;
int right = i;
sArr[s.charAt(left) - 'a']--;
sArr[s.charAt(right) - 'a']++;
}
if (Arrays.equals(sArr, pArr)) {
data.add(sLength - pLength);
}
return data;
}
}
解题思路
- 初始化 :创建两个长度为 26 的数组
sArr
和pArr
,分别用于存储字符串s
和p
中每个字符的出现次数。- 填充
pArr
:遍历字符串p
,统计每个字符的出现次数。- 滑动窗口 :使用两个指针
left
和right
表示窗口的边界,right
指针向右移动扩展窗口。- 更新
sArr
:当right
指针移动时,将新进入窗口的字符的计数加一。- 检查异位词 :如果当前窗口的字符计数与
p
相同,则说明找到了一个异位词,记录下left
指针的索引。- 移动
left
指针 :当窗口大小超过p
的长度时,移动left
指针,减少离开窗口的字符的计数。- 返回结果:最终返回所有找到的异位词子串的起始索引。
复杂度分析
- 时间复杂度 :O(n),其中 n 是字符串
s
的长度。每个字符只被访问两次(一次由right
指针,一次由left
指针)。- 空间复杂度:O(1),使用固定大小的数组存储字符计数,不依赖于输入大小。