leetcode 438. 找到字符串中所有字母异位词
分析:本题采用哈希表+滑动窗口的方法来实现。
- 首先定义一个哈希表用来存储要匹配的子串(p)的字符和字符出现频率,即key为不同的字符,value为字符出现的次数;
- 再定义一个哈希表来存储在s字符串上进行滑动的窗口中字符的频率;
- 再用一个整数来记录两个哈希表中频率相同的字符串的个数;
- 滑动窗口的大小为
right-left
,通过更新right和left来控制滑动窗口的大小
解题步骤:
-
定义左右指针和字符数量,遍历字符串p,将字符及其出现次数存储到哈希表
pMap
中;int left = 0, right = 0, count = 0; for (char n : p) { pMap[n]++; }
-
遍历字符串s, 更新右边界,如果
pMap
中存在s[right]
,更新sMap
中的s[right]
的次数,如果sMap[s[right]] == pMap[s[right]]
,说明sMap
中存在和pMap
中字符频率相同的字符,count
加1, 更新右边界;if (pMap.count(s[right])) { sMap[s[right]]++; if (sMap[s[right]] == pMap[s[right]]) { count++; } } right++;
-
当
count == pMap.size()
, 即当前滑动窗口内包含了字符串p中所有的字符,且每种字符的频率都与字符串p中对应,并且如果right - left == pLen
,即滑动窗口的大小也等于字符串p的大小,就可以将左边界添加到答案数组中了,这里为什么还要再判断right - left == pLen
是因为,但sMap
中存在所有pMap
中的字符且频率对应的时候,还可能存在pMap
中不存在的字符,所以只有当right - left == pLen
才是匹配的字符串,例如在示例1中,当left = 1,right =9时,sMap
包含pMap
中的字符及其出现频率,但是此时并不是匹配的子串; -
添加结果以后,判断当
pMap
中是否存在s[left]
时,若存在要对sMap
中s[left]
的频率减1,因为滑动窗口的左边界将被更新,不再包含此时的left
,如果sMap[s[left]] < pMap[s[left]]
,则count
也要减1,表示此时当前窗口不再和字符串p匹配,最后向右移动left指针;while (count == pMap.size()) { if (right - left == pLen) { res.push_back(left); } if (pMap.count(s[left])) { sMap[s[left]]--; if (sMap[s[left]] < pMap[s[left]]) { count--; } } left++; }
-
最后返回结果
res
.
完整代码:
vector<int> findAnagrams(string s, string p) {
unordered_map<char, int> pMap, sMap;
int sLen = s.size();
int pLen = p.size();
if (sLen < pLen) return {};
int left = 0, right = 0, count = 0;
vector<int> res;
for (char n : p) {
pMap[n]++;
}
while (right < sLen) {
if (pMap.count(s[right])) {
sMap[s[right]]++;
if (sMap[s[right]] == pMap[s[right]]) {
count++;
}
}
right++;
while (count == pMap.size()) {
if (right - left == pLen) {
res.push_back(left);
}
if (pMap.count(s[left])) {
sMap[s[left]]--;
if (sMap[s[left]] < pMap[s[left]]) {
count--;
}
}
left++;
}
}
return res;
}