原题:438. 找到字符串中所有字母异位词 - 力扣(LeetCode)
题目解析:
本题要在一个字符串中找另一个字符串的异位词。
这个异位词其实有个特点就是组成的元素都是相同的,只是顺序不同(类似化学同素异形体的概念)
如果用暴力查找枚举每一种排序情况是很麻烦的,换一种思路。
我们其实只要知道在同样长度的字符串中出现的字符个数是否和目标字符串(p)一样即可。
因为只要他们的构成元素一致,那么其中一个字符串必然是另一个字符串的异位词。
而要统计对比两个字符串的字符出现个数,可以用两个哈希表实现。
算法原理:
先用一个哈希表 hash_p 将p字符串的字符信息都录入
然后在s字符串上遍历。当
使用双指针维护遍历的字符串。保持其长度和p字符串一致,那么就可以发现,双指针一直是往右移动的。
所以可以用滑动窗口优化。且这个窗口大小是固定的。
此时只要比较两个哈希表中的字符个数是否一致即可。
因为比较两个哈希表需要每一次都遍历哈希表,进一步优化,设置一个有效数count来记录哈希表hash_s中有效的字符个数,即hash_p(目标字符串的哈希表)中有的,hash_s也有时就为有效。
这样,只要比较count和p字符串的长度大小即可。省去了每一次要遍历哈希表的时间。
直接进入滑动窗口四步走
1.进窗口
先将右指针指向的字符信息取出(保存到一个临时变量 char in;)。
在 哈希表hash_s 录入right指针指向的字符
如果在hash_s中这个字符记录的个数小于或等于 hash_p中的个数
那么表示窗口中的有效个数增加。
2.判断
如果窗口长度超过目标字符串长度时,要进行出窗口操作
3.出窗口
将左指针指向字符信息先取出来(保存到一个临时变量 char out;)。
然后左指针向右移动一位。
判断 如果出窗口字符 out(最开始保存的)在hash_s中的个数要小于等于在hash_p中的个数,表示这个出窗口的字符是有效字符,有效个数count减小一个(判断条件没有大于,是因为如果是大于的话,那么这个字符本身就是多余的,在先前的入窗口中就不会增加有效个数,所以这里也就没必要减小有效个数)
4.更新状态
当窗口内的有效个数等于p字符串的长度,表示找到异位词,将左指针的下标给返回值数组
代码编写:
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
int hash_s[26] = {0},hash_p[26] = {0};
vector<int>ret;
//初始化哈希表
for(auto ch:p)
{
hash_p[ch - 'a']++;
}
int len = p.size();
int count = 0;//存放有效个数
for(int left = 0,right = 0;right < s.size();right++)
{
//进窗口
char in = s[right];//right的更新在循环结束后,所以这里不++,先不移动right
if(++hash_s[in - 'a'] <= hash_p[in-'a'])//先更新哈希表再比较
{
count++;
}
//判断
if(right-left+1 > len) //因为是窗口大小是固定的,所以用if语句即可
{
//出窗口
char out = s[left++];
if(hash_s[out - 'a']-- <= hash_p[out - 'a'])//先比较再更新哈希表
{
count--;
}
}
//更新
if(count == len)//有效数一致 ----- 为字母异位词
{
ret.push_back(left);
}
}
return ret;
}
};