一、 题目
二、 示例
三、 思路与代码
1. 思路
- 本题采用滑动窗口算法, 维护的是定长窗口;
- 定义windows(窗口中字符的计数器)和needs(排列子串字符的计数器);
- 首先, right 指针移动扩大窗口, 当窗口中的某一字符与needs计数器中的字符匹配(数量也要匹配)时, val++(代表窗口中满足 needs 条件的字符个数)
- 窗口收缩的时机为:当
right - left
(窗口字符串的长度)超过了待排列字符串的长度时, 窗口就要进行收缩了;此时, 若val == needs.size()
说明找到了符合的字符串;否则, 进行窗口的收缩(left++, 将字符移出窗口, 且需判断val是否需要更新);
2. 代码
class Solution {
public:
bool checkInclusion(string s1, string s2) {
// 套用模板, 注意条件的判断
// 这一题的特色就是 定长窗口的维护, right 移动, left 移动
// 与76题进行对比
int left = 0;
int right = 0;
unordered_map<char, int> windows, needs;
for (char c : s1) {
needs[c]++;
}
int val = 0; // 计数0
int s_len = s2.size();
while (right < s_len) {
// 移动窗口
char c = s2[right]; // 待移入窗口的字符
right++; // 移动指针, 扩大窗口
if (needs.count(c)) {
// 如果 needs 序列中(即子串序列) 包含了 字符d
windows[c]++;
// 若匹配(满足个数匹配, 才让val++)
if (windows[c] == needs[c]) {
val++; // 则计数++
}
}
// 更新窗口收缩 | 定长滑动窗口往后移动
// >= 子串的长度
while (right - left >= s1.size()) {
// 若子串的序列长度都不一样,肯定不匹配
// needs.size 容器中存有键值对的个数
if (val == needs.size()) {
return true;
}
// 待移出窗口的字符
char d = s2[left];
left++;
// 进行窗口内数据的更新
if (needs.count(d)) {
if (windows[d] == needs[d]) {
val--;
}
windows[d]--;
}
}
}
// 找不到符合条件的子串
return false;
}
};