首页 > 代码库 > Substring with Concatenation of All Words leetcode

Substring with Concatenation of All Words leetcode

You are given a string, S, and a list of words, L, that are all of the same length. Find all starting indices of substring(s) in S that is a concatenation of each word in L exactly once and without any intervening characters.

For example, given:
S"barfoothefoobarman"
L["foo", "bar"]

You should return the indices: [0,9].
(order does not matter).

题目的意思是在S中找到包含所有L中出现字符子串的开始下标,不能出现不存在L中,假设L中的单词个数为N,每一个单词的长度为M,对于下标i,

那么有   i   到    i+N*M中的单词刚好包含L中的所有单词一次。

那么就可以这样想了,我们每次就判断一个长度 为  N*M的字符子串 就是    

先用两个  map  来保存   总共需要找的单词   totalnumber   和   已经找到的单词   aredyfind     类似   Minimum Window Substring leetcode

1、令 i=0  表示  从 i=0 开始      i最大为    S.size()-N*M   ,最大能取

2、然后 依次将 i  到  i+N*M的字符转为单词 ,并且在map中寻找,同时标记找到的

3、如果刚好L中的单词出现了一次,就保存i  

否则  跳出来   判断  i+1   到  i+1 + N*M的字符了

代码如下:

class Solution {
public:
    vector<int> findSubstring(string S, vector<string> &L) {
   
        vector<int> result;  
       map<string,int> totalnumber;
       map<string,int> aredyfind;
       
        int i,j;
       
        int words=L.size();
        int wordlength=L[0].size();
        
        for(i=0;i<L.size();i++)
            ++totalnumber[L[i]];
          
        for(i=0;i<=int(S.size())-words*wordlength;i++)
        {
            
            aredyfind.clear();
            
            for(j=0;j<words;j++)
            {
                string str=S.substr(i+j*wordlength,wordlength);
                
                if(totalnumber.find(str)==totalnumber.end())
                    break;
                ++aredyfind[str];
                if(aredyfind[str]>totalnumber[str])
                    break;
                
            }
            if(j==words){
                result.push_back(i);
             //   i=i+words*wordlength;
            }
        }
        return result;
    }
};

刚开始我还以为 输出的下标之间的字符不能重用,  如  aaa    L={a,a}

我以为 输出  [  0  ]   其实 0 ,1都是

网上还有一种滑动窗口,上面虽然也算是一种滑动的,但是有些东西需要重新遍历   复杂度为   (S.size()- N*M)*N*M  , N为L中单词个数,M为单词长度

其他博客的滑动机制如下:


比如s = “a1b2c3a1d4”L={“a1”,“b2”,“c3”,“d4”}

窗口最开始为空,

a1在L中,加入窗口 【a1】b2c3a1d4                            

b2在L中,加入窗口 【a1b2】c3a1d4

c3在L中,加入窗口 【a1b2c3】a1d4

a1在L中了,但是前面a1已经算了一次,此时只需要把窗口向右移动一个单词a1【b2c3a1】d4

d4在L中,加入窗口a1【b2c3a1d4】找到了一个匹配

如果把s改为“a1b2c3kka1d4”,那么在第四步中会碰到单词kk,kk不在L中,此时窗口起始位置移动到kk后面a1b2c3kk【a1d4


代码如下:

class Solution {
public:
    vector<int> findSubstring(string S, vector<string> &L) {
        unordered_map<string, int>wordTimes;//L中单词出现的次数
        for(int i = 0; i < L.size(); i++)
            if(wordTimes.count(L[i]) == 0)
                wordTimes.insert(make_pair(L[i], 1));
            else wordTimes[L[i]]++;
        int wordLen = L[0].size();
         
        vector<int> res;
        for(int i = 0; i < wordLen; i++)
        {//为了不遗漏从s的每一个位置开始的子串,第一层循环为单词的长度
            unordered_map<string, int>wordTimes2;//当前窗口中单词出现的次数
            int winStart = i, cnt = 0;//winStart为窗口起始位置,cnt为当前窗口中的单词数目
            for(int winEnd = i; winEnd <= (int)S.size()-wordLen; winEnd+=wordLen)
            {//窗口为[winStart,winEnd)
                string word = S.substr(winEnd, wordLen);
                if(wordTimes.find(word) != wordTimes.end())
                {
                    if(wordTimes2.find(word) == wordTimes2.end())
                        wordTimes2[word] = 1;
                    else wordTimes2[word]++;
                     
                    if(wordTimes2[word] <= wordTimes[word])
                        cnt++;
                    else
                    {//当前的单词在L中,但是它已经在窗口中出现了相应的次数,不应该加入窗口
                     //此时,应该把窗口起始位置想左移动到,该单词第一次出现的位置的下一个单词位置
                        for(int k = winStart; ; k += wordLen)
                        {
                            string tmpstr = S.substr(k, wordLen);
                            wordTimes2[tmpstr]--;
                            if(tmpstr == word)
                            {
                                winStart = k + wordLen;
                                break;
                            }
                            cnt--;
                        }
                    }
                     
                    if(cnt == L.size())
                        res.push_back(winStart);
                }
                else
                {//发现不在L中的单词
                    winStart = winEnd + wordLen;
                    wordTimes2.clear();
                    cnt = 0;
                }
            }
        }
        return res;
    }
};

算法时间复杂度为O(S.zize()*M))M是单词的长度  

http://www.cnblogs.com/TenosDoIt/p/3807055.html    该博客地址


Substring with Concatenation of All Words leetcode