- Find All Anagrams in a String
Given a string s and a non-empty string p, find all the start indices of p’s anagrams in s.
Strings consists of lowercase English letters only and the length of both strings s and p will not be larger than 40,000.
The order of output does not matter.
Example
Given s = “cbaebabacd” p = “abc”
return [0, 6]
The substring with start index = 0 is “cba”, which is an anagram of “abc”.
The substring with start index = 6 is “bac”, which is an anagram of “abc”.
思路:
滑动窗口。但是并不容易写。
有两个思路,分别见解法2和解法3.
解法1:先预处理string p得到bitmap 表。然后滑动窗口每动一下复制bitmap表,如果有match, bitmap表中相应元素频率-1。
由于每次都要复制,效率非常低。
class Solution {
public:
/**
* @param s: a string
* @param p: a string
* @return: a list of index
*/
vector<int> findAnagrams(string &s, string &p) {
int lenS = s.size();
int lenP = p.size();
vector<int> result;
if ((lenS == 0) || (lenP == 0) || (lenS < lenP)) return result;
vector<int> bitmap(26, 0);
for (int i = 0; i < lenP; ++i) {
bitmap[p[i] - 'a'] += 1;
}
int lastPos = lenS - lenP + 1;
for (int i = 0; i < lastPos; ++i) {
int count = 0;
vector<int> newbitmap(bitmap);
for (int j = 0; j < lenP; ++j) {
if (newbitmap[s[i + j] - 'a'] > 0) {
newbitmap[s[i + j] - 'a'] -= 1;
count++;
} else {
break;
}
}
if (count == lenP) result.push_back(i);
}
return result;
}
};
解法2:是在网上看到的。感觉非常不错。效率很高。
class Solution {
public:
/**
* @param s: a string
* @param p: a string
* @return: a list of index
*/
vector<int> findAnagrams(string &s, string &p) {
int lenS = s.size();
int lenP = p.size();
vector<int> result;
if ((lenS == 0) || (lenP == 0) || (lenS < lenP)) return result;
vector<int> table(26, 0);
for (int i = 0; i < lenP; ++i) {
table[p[i] - 'a'] += 1;
}
int start = 0, end = 0, count = 0;
while(end < lenS) {
int index = s[end] - 'a';
if (table[index] > 0) {
count++;
}
table[index]--;
if (end - start + 1 == lenP) {
if (count == lenP) {
result.push_back(start);
}
int origIndex = s[start] - 'a';
if (table[origIndex] >= 0) {
count--;
}
table[origIndex]++;
start++; end++;
} else {
end++;
}
}
return result;
}
};
解法3:同向双指针,思路见
https://blog.csdn.net/roufoo/article/details/127944794?spm=1001.2014.3001.5501
class Solution {
public:
/**
* @param s: a string
* @param p: a string
* @return: a list of index
*/
vector<int> findAnagrams(string &s, string &p) {
int lenS = s.size(), lenP = p.size();
if (lenS < lenP) return {};
vector<int> freq(26, 0);
for (int i = 0; i < lenP; i++) {
freq[p[i] - 'a']++;
}
int count = lenP, j = 0;
vector<int> res;
for (int i = 0; i < lenS; i++) { //i is left border, j is right border of the window
j = max(i, j);
while (count > 0 && j < lenS) {
if (freq[s[j] - 'a'] > 0) count--;
freq[s[j] - 'a']--;
j++;
}
if (count == 0 && j - i == lenP) res.push_back(i);
if (freq[s[i] - 'a'] == 0) count++;
freq[s[i] - 'a']++;
}
return res;
}
};
四刷: 还是同向双指针,不过是逐个移动右指针,后批量移动左指针。上面的做法是批量移动右指针,后逐个移动左指针。
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
int lenS = s.size(), lenP = p.size(), needAccount = 0, validAccount = 0;
vector<int> res;
vector<int> need(128, 0), actual(128, 0);
int p1 = 0, p2 = 0;
for (int i= 0; i < lenP; i++) {
if (need[p[i]] == 0) needAccount++;
need[p[i]]++;
}
while (p2 < lenS) {
char c = s[p2];
if (need[c] > 0) {
actual[c]++;
if (actual[c] == need[c]) {
validAccount++;
}
}
p2++;
while (validAccount == needAccount) {
if (p2 - p1 == lenP) res.push_back(p1);
c = s[p1];
if (need[c] > 0) {
if (actual[c] == need[c]) {
validAccount--;
}
actual[c]--;
}
p1++;
}
}
return res;
}
};