目录
- 一、找到字符串中所有字母异位词
- 二、串联所有单词的子串
一、找到字符串中所有字母异位词
题目:
思路:
用一个变量count来统计有效字符的个数。哈希表2统计字符串p的每个字符出现的个数,然后遍历字符串s,先进窗口,相同的映射位置,哈希表1该位置的个数<=哈希表2的个数,count++(比目标数小才要++,超过了就不需要++,有等号是因为先进窗口)。滑动窗口是固定大小的,所以right-left+1不能大于字符串p的长度。如果超过固定长度,先判断哈希表的位置,哈希表1该位置的个数<=哈希表2的个数,count- -(比目标数大去掉也无效,小于了有效数就减少,等于是因为先判断的,后面要哈希表位置要减减),然后出窗口。判断count等于字符串p的长度,更新结果(大于等于怎么办?不会出现)。
代码:
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
vector<int> ret;
int hash1[26] = { 0 };
int hash2[26] = { 0 };
for (auto e : p) hash2[e - 'a']++;
int left = 0, right = 0, count = 0;
while (right < s.size())
{
hash1[s[right] - 'a']++;//先进窗口,再判断
if (hash1[s[right] - 'a'] <= hash2[s[right] - 'a']) count++;
while (right - left + 1 > p.size())
{
if (hash1[s[left] - 'a'] <= hash2[s[left] - 'a']) count--;//先判断
hash1[s[left] - 'a']--;//再出窗口
++left;
}
if (count == p.size()) ret.push_back(left);
++right;
}
return ret;
}
};
二、串联所有单词的子串
题目:
思路:滑动窗口+哈希表
整体思路与上一道题相同,但是有些区别。
容器使用:unordered_map<string, int>
循环次数:是单词的个数(每个单词的个数是相同的)
定义窗口的指针(下标)left、right每次从 i 开始(多次循环的缘故)
固定窗口大小:words的长度 * 单词长度
截取字符串:substr(从哪开始,截取几个)
移动步长:单词的长度
细节:第一个unordered_map用来统计不同单词的个数,第二个unordered_map要放在循环里面,因为每次算进去的单词可能会变化
整体思路:进窗口、判断、出窗口、更新结果
代码:
class Solution {
public:
vector<int> findSubstring(string s, vector<string>& words) {
vector<int> ret;
unordered_map<string, int> hash1;//容器
for (auto e : words) hash1[e]++;//先放入,便于判断
for (int i = 0; i < words[0].size(); i++)//单词个数的循环次
{
//循环里的容器,注意!每次循环该容器的内容不一样了!
//所以是临时的(每次循环)
unordered_map<string, int> hash2;
int left = i, right = i, count = 0;//注意从i开始
while (right < s.size())//遍历字符串s
{
string str1 = s.substr(right, words[0].size());//截取字符串
hash2[str1]++;//先进窗口
if (hash2[str1] <= hash1[str1]) count++;//再判断
while (right - left + 1 > words.size() * words[0].size())//固定窗口大小
{
string str2 = s.substr(left, words[0].size());//截取字符串
if (hash2[str2] <= hash1[str2]) count--;//先判断
hash2[str2]--;//再出窗口
left += words[0].size();//移动步长
}
if (count == words.size()) ret.push_back(left);//更新结果
right += words[0].size();//移动步长
}
}
return ret;
}
};