这道题是定长滑动窗口,之前没做过,看了下灵神的题解,这里讲下详细思路。
这里我们需要用到两个哈希表,hash_p
用于统计子串p的字符分布情况,hash_s
用于统计滑动窗口内的字符分布情况,当两个哈希表相等时,则此时滑动窗口框住的部分就是p的一个异位词,此时将滑动窗口的左端点下标记录下来即可。当两个哈希表不相等时,则说明当前滑动窗口框住的不是异位词,需要直接将滑动窗口右移,所以我们需要及时将窗口左端的元素移除,在下个循环中,滑动窗口右端会新增一个元素,这样就维持了滑动窗口的长度不变。
这里我依然采用unordered_map
作为哈希表的数据结构,注意,当删除窗口左端的元素时,如果窗口左端的元素计数已经降为0,则将对应的键删除,若不及时删除的话,该键依然会存在于哈希表中,但是滑动窗口内已经没有这个字符了,这就会影响两个哈希表之间的相等判断,即使后面的滑动窗口已经框住了异位词,但由于其他字符的键没有删干净,而导致二者不相等,从而漏掉答案。如果是采用array
这种容器来实现的话应该不用担心这个问题,我只是觉得用unordered_map
更好理解一点。
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
vector<int> result;
unordered_map<char, int> hash_p; //用于统计字符串p的字符分布情况
unordered_map<char, int> hash_s; //用于统计字符串s的字符分布情况
for(int right = 0; right < p.size(); right++) //统计字符串p的字符分布情况
hash_p[p[right]]++;
//下面开始在s中查找p的异位词子串
for(int right = 0; right < s.size(); right++){
hash_s[s[right]]++; //将右指针指向的字符存入哈希表中
int left = right - p.size() + 1; //确定left的起始位置
if(left < 0) //left还没进入字符串p
continue;
//能够执行到这里,就说明左指针和右指针都已经进入了字符串p,可以开始统计了
if(hash_p == hash_s)
result.emplace_back(left); //收获结果
hash_s[s[left]]--; //及时清除左指针指向的字符,相当于定长滑动窗口的左端点提前右移一位
if(hash_s[s[left]] == 0) //对于次数已经将为0的字符,需要及时将其键抹除,否则会影响两个哈希表的比较判断
hash_s.erase(s[left]);
}
return result;
}
};