题目
给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。
这道题沿用上一题的思路,我会这么做
cpp
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
unordered_map<string, vector<int>> mp;
string p_p = p;
sort(p_p.begin(), p_p.end());
int i = 0, j = p.size();
while (i + j <= s.size()) {
string str = s.substr(i, j);
sort(str.begin(), str.end());
mp[str].emplace_back(i);
i++;
}
return mp[p_p];
}
};
代码是简洁了,思路也清晰,就是这个循环加上sort、substr这个时间开销太大了,导致最后运行超时
那么改如何优化呢
cpp
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
vector<int> ans;
int n = s.size(), k = p.size();
if(k > n) return ans; // p比s长,直接返回空
vector<int> cntP(26,0);
vector<int> cntS(26,0);
// 统计p的字符频次
for(char ch : p){
cntP[ch - 'a']++;
}
// 先初始化第一个窗口 [0 , k‑1]
for(int i = 0; i < k; i++){
cntS[s[i] - 'a']++;
}
// 计算diff:频次不相等的字母总个数
int diff = 0;
for(int i = 0; i < 26; i++){
if(cntS[i] != cntP[i]) diff++;
}
if(diff == 0){
ans.emplace_back(0);
}
// 滑动窗口,窗口起点从1开始
for(int l = 1; l <= n - k; l++){
// 1.要移出窗口的字符:s[l‑1]
char out = s[l - 1];
int idxOut = out - 'a';
// 移出之前,如果两边不等,移出之后有可能相等,diff变化
if(cntS[idxOut] == cntP[idxOut]) diff++; //相等的话就要加,说明改字符后不匹配的
cntS[idxOut]--; //正常移动窗口提走字母
if(cntS[idxOut] == cntP[idxOut]) diff--; //如果相减后匹配,则说明diff可以减一
// 2.新进入窗口的字符:s[l + k -1]
char in = s[l + k -1];
int idxIn = in - 'a';
if(cntS[idxIn] == cntP[idxIn]) diff++;
cntS[idxIn]++;
if(cntS[idxIn] == cntP[idxIn]) diff--;
// diff为0,窗口匹配
if(diff == 0){
ans.emplace_back(l);
}
}
return ans;
}
};
移动窗口不熟悉,多想想