leetcode30 串联所有单词的子串

先对words中的单词排列组合,然后对s滑窗操作;部分样例超时,代码如下:

class Solution {
public:
    vector<int> findSubstring(string s, vector<string>& words) {
        //dfs找出words所有组合,然后在s滑窗

        //排除异常情况
        int len=0;
        for(auto w:words){
            len+=w.size();
        }
        if(len==0 || s.size()==0 || len>s.size()) return {};
        
        //排列组合words
        set<string> s_words;
        vector<int> indexs;

        for(int i=0;i<words.size();i++){
            indexs.push_back(i);
        }
        do{
            string tmp="";
            for(int i=0;i<indexs.size();i++){
                tmp+=words[indexs[i]];
            }
            s_words.insert(tmp);

        }while(next_permutation(indexs.begin(),indexs.end()));

        //在s中滑窗寻找起始位置,O(m*n*k) m为s长度,n为s_words字符串个数,k为subs的长度;
        vector<int> res;     
        for(int i=0;i<=s.length()-len;i++){
            string subs=s.substr(i,len);           
            if(s_words.find(subs)!=s_words.end()){
                res.push_back(i);
            }
        }
        return res;
    }
};

下面也超时,均执行至148/173

class Solution {
public:
    vector<int> findSubstring(string s, vector<string>& words) {
        //dfs找出words所有组合,然后在s滑窗

        //排除异常情况
        int len=0;
        for(auto w:words){
            len+=w.size();
        }
        if(len==0 || s.size()==0 || len>s.size()) return {};

        //排列组合words
        set<string> s_words;
        vector<int> indexs;

        for(int i=0;i<words.size();i++){
            indexs.push_back(i);
        }
        do{
            string tmp="";
            for(int i=0;i<indexs.size();i++){
                tmp+=words[indexs[i]];
            }
            s_words.insert(tmp);

        }while(next_permutation(indexs.begin(),indexs.end()));

        //在s中滑窗寻找起始位置,O(m*n*k) m为s长度,n为s_words字符串个数,k为subs的长度;
        vector<int> res;     
        for(int i=0;i<=s.length()-len;i++){
            string subs=s.substr(i,len);           
            for(auto it=s_words.begin();it!=s_words.end();it++){
                string tmp=*it;
                int flag=1;
                for(int j=0;j<len;j++){
                    if(tmp[j]!=subs[j]){
                        flag=0;break;
                    }
                }
                if(flag==1) {
                    res.push_back(i);break;
                }
            }
        }
        return res;
    }
};

想办法对暴力算法进行提速,
以下为别人的提速方案,可行;
作者:Xdo
链接:https://leetcode-cn.com/problems/substring-with-concatenation-of-all-words/solution/bao-li-suan-fa-jia-ru-qu-zhong-you-hua-10bei-ti-su/
思路就是,先把存在的字符串,放到 hashmap ,可以快速比较,然后每一个位置都进行匹配
但这里会有很多的重复计算,就可以使用一个小技巧,先计算目标串的每个字母的 ASCII 和,
然后和当前要匹配的字符串的每个字母的 ASCII 进行比较,如果不相等就不用进行下面的匹配过程了

class Solution {
public:
    vector<int> findSubstring(string s, vector<string>& words) {
        vector<int> res;
        if(words.size()<1 || s.size()<1 || s.size() < words[0].size()*words.size()) return res;
        int wordLen = words[0].size(), lens = wordLen*words.size(), target = 0, cur = 0;
        unordered_map<string,int> allWord;
        for(auto& it:words){
            allWord[it]++;
            for(auto& i:it) target += i;
        }
        for(int i=0; i<lens; i++) cur += s[i];
        // 先看当前字符串的 ASCII 码相加是否相等 方便去重
        for(int i=0, j; i<=s.size()-lens; cur -= s[i], cur += s[lens + i++]){
            // 快速去重
            if(cur != target) continue;
            // 确认一下,是否为真的匹配
            unordered_map<string,int> tem(allWord);
            for(j=i; j<i+lens; j+=wordLen)
                if(tem[s.substr(j, wordLen)]-- == 0) break;
            if(j == i+lens) res.push_back(i);
        }
        return res;
    }
};
posted @ 2019-12-20 10:16  Joel_Wang  阅读(178)  评论(0编辑  收藏  举报