. - 力扣(LeetCode)
题目解析
题目要求找出字符串中所有的字母异位词。所谓字母异位词指的是两个字符串中字符出现的次数相同,但顺序可以不同的情况。
思路分析
-
固定窗口:使用滑动窗口技巧,窗口大小固定为待匹配字符串
pp
的长度,来在字符串ss
中寻找所有可能的异位词。 -
进出操作:通过移动窗口的左右边界来实现进出操作,同时维护窗口内字符出现次数的统计。
-
优化可选长度记录:在滑动窗口的过程中,通过比较两个统计数组
hash1
和hash2
来判断当前窗口内的字符是否满足异位词的条件。
代码分析
import java.util.ArrayList;
import java.util.List;
public class FindAllAnagrams {
public List<Integer> findAnagrams(String ss, String pp) {
List<Integer> ret = new ArrayList<>(); // 存储结果的列表
char[] s = ss.toCharArray(); // 将输入字符串转为字符数组
char[] p = pp.toCharArray(); // 将待匹配字符串转为字符数组
int[] hash1 = new int[26]; // 用于统计待匹配字符串中每个字符出现的次数
// 统计待匹配字符串中每个字符出现的次数
for (char c : p) {
hash1[c - 'a']++;
}
int[] hash2 = new int[26]; // 用于统计滑动窗口中每个字符出现的次数
int left = 0, right = 0, count = 0;
// 右指针移动,扩展滑动窗口
while (right < s.length) {
char in = s[right];
hash2[in - 'a']++; // 将右边界字符加入窗口统计
if (hash2[in - 'a'] <= hash1[in - 'a']) {
count++; // 如果当前字符的出现次数不超过待匹配字符中的次数,则 count 加一
}
// 判断是否需要收缩窗口
if (right - left + 1 > p.length) {
char out = s[left++];
if (hash2[out - 'a'] <= hash1[out - 'a']) {
count--; // 如果左边界字符移出窗口后,仍然满足条件,则 count 减一
}
hash2[out - 'a']--; // 左边界字符移出窗口,更新窗口统计
}
// 判断当前窗口是否找到了一个符合条件的字母异位词
if (count == p.length) {
ret.add(left); // 记录滑动窗口的左边界索引
}
right++; // 右边界右移,扩展窗口
}
return ret; // 返回所有符合条件的字母异位词的起始索引列表
}
}