(滑动窗口,哈希表)Leetcode030串联所有单词的字串

地址

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;
    }
};

猜你喜欢

转载自blog.csdn.net/qq_52934831/article/details/121443501