一、 题目
二、 示例
三、 思路与代码
1. 思路
- 本题采用滑动窗口算法, 维护的是定长窗口, 可以参考
力扣 567. 字符串的排列
; - 主要考虑三个问题:
-
- 什么时候应该移动 right 指针扩大窗口?往窗口中加入字符时,要更新哪些数据(窗口计数器
windows
和 窗口中满足 need 条件的字符个数val
)?
- 什么时候应该移动 right 指针扩大窗口?往窗口中加入字符时,要更新哪些数据(窗口计数器
-
- 何时收缩窗口?窗口收缩时应该做什么操作?
-
- 题目答案应该在扩大窗口还是收缩窗口的时候更新?
-
2. 代码
- 代码中包含详细的注释
class Solution {
public:
// 本题, 注意同576一样也是 定长滑动窗口
vector<int> findAnagrams(string s, string p) {
unordered_map<char, int> needs, windows; // 定义窗口windows和需求needs
// 接收子串起始索引
vector<int> vIndex;
// 初始化
for (char c : p) needs[c]++;
int left = 0;// 滑动指针 left right 区间范围为左闭右开 [0, 0)
int right = 0;
int s_len = s.size();
int p_len = p.size();
int val = 0; // 计数
while (right < s_len) {
// 窗口扩大
char c = s[right];
right++;
// 将字符移入窗口
if (needs.count(c)) {
windows[c]++;
if (windows[c] == needs[c]) {
val++;
}
}
// 定长滑动窗口更新
while (right - left >= p_len) {
// 若子串的序列长度都不一样,肯定不匹配
// needs.size 容器中存有键值对的个数
if (val == needs.size()) {
vIndex.push_back(left);
}
char d = s[left];
left++;
if (needs.count(d)) {
if (windows[d] == needs[d]) {
val--;
}
windows[d]--;
}
}
}
return vIndex;
}
};