滑动窗口算法实战:串联所有单词的子串与最小覆盖子串
15. 串联所有单词的子串
题目描述
给定一个字符串 s 和一些长度相同的单词 words,找出 s 中恰好包含 words 中所有单词的串联子串的起始索引。
解题思路
这道题的核心在于将每个单词视为一个整体字符。如果我们将单词拆解成字母,问题就变成了寻找异位词;但这里我们需要处理的是单词级别的匹配。
关键点:
- 使用哈希表统计
words中每个单词的出现频次。 - 滑动窗口的步长固定为单词长度
len。 - 需要遍历
len次,每次从不同的偏移量开始,确保覆盖所有可能的起始位置。
C++ 实现
class Solution {
public:
vector<int> findSubstring(string s, vector<string>& words) {
vector<int> ret;
if (words.empty() || s.empty()) return ret;
unordered_map<string, int> hash1;
// 统计 words 中所有单词出现的频次
for (const auto& word : words) {
hash1[word]++;
}
int len = words[0].size();
int m = words.size();
int n = s.size();
// 遍历 len 次,每次从 i 开始作为窗口起点
for (int i = 0; i < len; ++i) {
unordered_map<string, int> hash2;
int count = 0;
int left = i;
// 注意 right 的类型转换,避免 size_t 与 int 运算溢出
( 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;
}
};


