题目描述
给定两个字符串 s 和 p,找到 s 中所有 p 的异位词的子串,返回这些子串的起始索引。不考虑答案的顺序。
异位词指由相同字母重排列形成的字符串(包括相同的字符串)。
示例: 输入:s = "cbaebabacd", p = "abc" 输出:[0,6] 解释: 起始索引等于 0 的子串是 "cba", 它是 "abc" 的异位词。 起始索引等于 6 的子串是 "bac", 它是 "abc" 的异位词。
解题思路
这道题的核心在于利用滑动窗口来维护一个固定长度的区间,并快速判断该区间内的字符分布是否与目标字符串 p 一致。
既然要找的是异位词,那目标子串的长度必然和 p 一致。我们可以在字符串 s 上构造一个长度为 p.size() 的滑动窗口,并在移动过程中动态维护窗口内每种字符的数量。
具体实现时,可以用两个长度为 26 的数组分别模拟哈希表:
hash1统计字符串 p 中每个字符出现的次数。hash2统计当前滑动窗口内每个字符出现的次数。
当 hash2 与 hash1 完全匹配时,说明当前窗口内的子串就是 p 的一个异位词。为了优化性能,我们可以引入一个计数器 count,记录当前窗口中满足频次要求的字符数量,避免每次遍历整个数组进行比较。
代码实现
C++ 版本
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
vector<int> ret;
int hash1[26] = {0}; // 统计字符串 p 中每个字符出现的次数
for (auto ch : p) hash1[ch - 'a']++;
int hash2[26] = {0}; // 统计窗口里面每个字符出现的个数
int m = p.size();
for (int left = 0, right = 0, count = 0; right < s.size(); right++) {
char in = s[right];
// 进窗口 + 维护 count
if (++hash2[in - 'a'] <= hash1[in - ]) count++;
(right - left + > m) {
out = s[left++];
(hash2[out - ]-- <= hash1[out - ]) count--;
}
(count == m) ret.(left);
}
ret;
}
};


