滑动窗口+哈希表
哈希表 t o t tot tot 存 w o r d s words words 所有单词的出现次数。
维护滑动窗口,窗口长度 m × w m\times w m×w , m m m 是单词数量 w w w是单词长度 , 窗口长度对应可行解的长度。哈希表 w d wd wd 维护滑动窗口内每个单词的出现次数。
维护有效串总数 c n t cnt cnt ,当 c n t = m cnt=m cnt=m 时,找到一个可行解。当右窗口右移,加入的单词是需要的, c n t + + cnt++ cnt++ , 当左窗口右移,移除的单词是需要的, c n t − − cnt-- cnt−− 。 对照 w d wd wd 和 t o t tot tot 判断单词是否需要 。
提示 : 滑动窗口达到最大长度后,维护左窗口。
将 s s s 分成 w w w 组,起点从 0 0 0 到 w − 1 w-1 w−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) , n n n 是字符串 s s s 的长度, w w w 是单词长度。遍历 w w w 组的时间复杂度 O ( w ) O(w) O(w) ,每组 n w \dfrac n w wn 个单词的时间复杂度 O ( n w ) 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) , m m m 是单词总数 w o r d s words words 的长度 , w w w 是单词长度。 哈希表 t o t tot tot 的空间复杂度是 O ( w × m ) O(w\times m) O(w×m) , 哈希表 t o t tot tot 的空间复杂度是 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) 。
博主致语
理解思路很重要!
欢迎读者在评论区留言,作为日更博主,看到就会回复的。