滑动窗口算法实战
滑动窗口是处理字符串匹配问题的经典技巧,特别适合解决连续子串相关的优化问题。本文将深入解析两道高频算法题:串联所有单词的子串(LeetCode 30)与最小覆盖子串(LeetCode 76)。
1. 串联所有单词的子串
题目链接: 30. 串联所有单词的子串 - 力扣
题目描述:
给定一个字符串 s 和一些长度相同的单词 words,找出 s 中恰好包含 words 中所有单词的串联子串的起始索引。
题目示例:

解法思路
这道题的核心在于将'单词'视为'字符'。如果我们把每个单词看作一个整体单元,问题就转化为了寻找字符串中所有单词的异位词组合。
有几个关键点需要注意:
- 哈希表统计频次:使用
unordered_map<string, int>记录words中每个单词出现的次数。 - 步长控制:由于单词长度固定为
len,左右指针移动的步长也应为len。 - 多轮遍历:因为起始位置可能不是
len的倍数,所以我们需要从0到len-1分别作为起始偏移量进行len次滑动窗口遍历。
C++ 代码实现
class Solution {
public:
vector<int> findSubstring(string s, vector<string>& words) {
vector<int> ret;
unordered_map<string, int> hash1; // 统计 words 中所有单词出现的频次
for(auto e : words) {
hash1[e]++;
}
int len = words[].();
m = words.();
n = s.();
( i = ; i < len; i++) {
unordered_map<string, > hash2;
count = ;
left = i;
( right = i; right + len <= n; right += len) {
string str1 = s.(right, len);
hash2[str1]++;
(hash2[str1] <= hash1[str1]) {
count++;
}
(right - left + > len * m) {
string str2 = s.(left, len);
(hash2[str2] <= hash1[str2]) {
count--;
}
hash2[str2]--;
left += len;
}
(count == m) {
ret.(left);
}
}
}
ret;
}
};





