类似题
Leetcode 076最小覆盖子串
https://blog.csdn.net/qq_52934831/article/details/121734390
地址
https://leetcode-cn.com/problems/substring-with-concatenation-of-all-words/
描述
思想
添加一个新单词到window里时:
1.如果该单词是有效单词:
(1) 首先window[word]自增;
(2) 如果window[word] <= total[word],证明该单词是有价值的,因为是先自增在判断。如果自增前该单词在window的数量已经达到了total的需求,自增后window[word]应该大于total[word].所以如果自增后小于等于total[word],证明该word的添加对结果有贡献作用,cnt++;
2.如果该单词是无效单词,则total[word]为0,所以自增后的window[word] > total[word],cnt不自增。
因此可以用if(window[word] <= total[word]) cnt++;来统一。
从window中删除word。
1.如果该单词是有效单词:
即删除该单词会导致删除后window[word] < total[word]。注意此处不能包括等于,假设我原来需要两个,你删之前有三个,删完之后有两个,这个被删除的依然不是必须的,所以必须window[word] 严格小于 total[word]才能使cnt–;
2,如果该单词是无效单词。
total[word]恒为0,删除后window[word]最差也为0.
因此可以用if(window[word] < total[word]) cnt --;来统一
代码
class Solution {
public:
vector<int> findSubstring(string s, vector<string>& words) {
//存放答案下标
vector<int> res;
if(words.empty()) return res;
//n->字符串长度,m->匹配串的个数,w->单词的长度
int n=s.size(),m=words.size(),w=words[0].size();
unordered_map<string ,int> tot;
//统计words集合中,每个单词出现的次数
for(auto word:words) tot[word]++;
for(int i=0;i<w;i++){
//采用滑动窗口思想
unordered_map<string ,int> wd;
//cnt 存储的是wd窗口中有多少单词是tot集合里已经出现过的
int cnt=0;
for(int j=i;j+w<=n;j+=w){
//最开始窗口大小不一定有m*w
if(j>=i+m*w){
//每次向后移动,需要删除窗口的前一个单词
auto word=s.substr(j-m*w,w);
wd[word]--;
//删除的是有效的单词,cnt--
if(wd[word]<tot[word]) cnt--;
}
//把下一个单词加入
auto word=s.substr(j,w);
wd[word]++;
//加入的是一个有效的单词
if(wd[word]<=tot[word]) cnt++;
if(cnt==m) res.push_back(j-(m-1)*w);
}
}
return res;
}
};