自己想了一个暴力解法,但是运行时间超限制:
//先将P中的每个字符出现次数保存下来,再在s中遍历,遇到一个字符就把该字符对应的次数减1。
//前提是在P中必须连续遇到
/*错误:超出时间限制*/
vector<int> findAnagrams(string s, string p) {
int right = 0;
int length = 0;
unordered_map<char, int> p_char_num, temp;
vector<int> res;
for (int i = 0; i < p.length(); i++) {
p_char_num[p[i]]++;
/*temp[p[i]]++;*/
}
copy(p_char_num.begin(), p_char_num.end(), inserter(temp, temp.begin()));
for (int j = 0; j < s.length(); j++) {
while (p_char_num.count(s[right]) && p_char_num[s[right]] != 0) {
p_char_num[s[right]]--;
right++;
length++;
if (length == p.length()) {
res.push_back(j);
//因为如果遇到不满足的字符可能p_char_num[s[right]]--也会执行,就会造成从头开始判断时p_char_num已经出错
//所以需要将p_char_num内清除干净并重新拷贝一份
p_char_num.clear();
copy(temp.begin(), temp.end(), inserter(p_char_num, p_char_num.begin()));
break;
}
}
p_char_num.clear();
copy(temp.begin(), temp.end(), inserter(p_char_num, p_char_num.begin()));
right = j + 1;
length = 0;
}
/*for (auto it = p_char_num.begin(); it != p_char_num.end(); it++) {
cout << it->first;
cout << " ";
cout << it->second;
}*/
return res;
}
看了官方解答后重新修改了以后:
滑动窗口
①使用两个指针构造一个和p字符串一样长的“滑动窗口”
②首先判断两个字符串长度是否合法
③然后将p字符串中出现的每个字符次数累加保存在一个26大小的vector中,同样将s中同样长度的“窗口”里的每个字符次数累加
④接着先判断最初的窗口是否满足条件,满足则将第一个下标存储
⑤最后维护left和right两个指针,同时向右移动,并且每次判断窗口内的字符出现次数是否和p中出现次数相同
vector<int> findAnagrams(string s, string p) {
vector<int> s_num(26), p_num(26);
vector<int> res;
int right = 0;
int left = 0;
if (s.length() < p.length())
return res;
for (int i = 0; i < p.length(); i++) {
p_num[p[i]-'a']++;
s_num[s[i]-'a']++;
}
if (p_num == s_num) {
res.emplace_back(0);
}
while (right < s.length()-p.length()) {
s_num[s[left]-'a']--;
s_num[s[right+p.length()]-'a']++;
right++;
if (s_num == p_num) {
res.emplace_back(left + 1);
}
left++;
}
return res;
}