滑动窗口+哈希表
哈希表 tottottot 存 wordswordswords 所有单词的出现次数。
维护滑动窗口,窗口长度 m×wm\times wm×w , mmm 是单词数量 www是单词长度 , 窗口长度对应可行解的长度。哈希表 wdwdwd 维护滑动窗口内每个单词的出现次数。
维护有效串总数 cntcntcnt ,当 cnt=mcnt=mcnt=m 时,找到一个可行解。当右窗口右移,加入的单词是需要的,cnt++cnt++cnt++ , 当左窗口右移,移除的单词是需要的,cnt−−cnt--cnt−− 。 对照 wdwdwd 和 tottottot 判断单词是否需要 。
提示 : 滑动窗口达到最大长度后,维护左窗口。
将 sss 分成 www 组,起点从 000 到 w−1w-1w−1 ,遍历每一组,得到答案。
class Solution {
public:
vector<int> findSubstring(string s, vector<string>& words) {//字符串哈希
vector<int> ans;
if(words.empty()) return ans;
unordered_map<string,int> tot;
for(auto &x:words) tot[x]++;
int n = s.size(),m = words.size(),w = words[0].size();
for(int i = 0;i<w;i++){
int cnt = 0;
unordered_map<string,int> wd;
for(int j = i ;j<=n;j+=w){
if(j >= i + m*w){//滑动窗口满了,维护左窗口
auto s1 = s.substr(j-m*w,w);
wd[s1]--;
if(tot[s1]>wd[s1]) cnt--;//减去了有效串
}
auto s2 = s.substr(j,w);
wd[s2]++;
if(tot[s2]>=wd[s2]) cnt++;//增加了有效串
if(m == cnt) ans.push_back(j-(m-1)*w);
}
}
return ans;
}
};
- 时间复杂度 : O(w×n)O(w\times n)O(w×n) , nnn 是字符串 sss 的长度, www 是单词长度。遍历 www 组的时间复杂度 O(w)O(w)O(w) ,每组 nw\dfrac n wwn 个单词的时间复杂度 O(nw)O(\dfrac n w)O(wn) ,遍历字母得到单词的时间复杂度 O(w)O(w)O(w) ,三者是相乘关系,总时间复杂度 O(w×n)O(w\times n)O(w×n)。
- 空间复杂度 : O(w×m)O(w\times m)O(w×m) , mmm 是单词总数 wordswordswords 的长度 , www 是单词长度。 哈希表 tottottot 的空间复杂度是 O(w×m)O(w\times m)O(w×m) , 哈希表 tottottot 的空间复杂度是 O(w×m)O(w\times m)O(w×m) ,总空间复杂度是 O(2×w×m)O(2\times w\times m)O(2×w×m) 。 忽略常数空间复杂度 O(w×m)O(w\times m)O(w×m) 。
博主致语
理解思路很重要!
欢迎读者在评论区留言,作为日更博主,看到就会回复的。
AC

本文介绍了一种使用滑动窗口结合哈希表的方法来解决特定字符串匹配问题。通过维护两个哈希表来跟踪目标单词及其在当前滑动窗口内的出现次数,实现了高效查找所有符合要求的子串起始位置。
698

被折叠的 条评论
为什么被折叠?



