LeetCode 30 - Substring with Concatenation of All Words
一、问题描述
Description: You are given a string,
s , and a list of words,words , that are all of the same length. Find all starting indices of substring(s) ins that is a concatenation of each word inwords exactly once and without any intervening characters.
For example: 
- s:
"barfoothefoobarman"- words:
["foo", "bar"]You should return the indices:
[0,9].
(order does not matter).
给定一个字符串 
假设 
二、解题报告
解法一:暴力枚举
枚举字符串 
判断方法:从起始位置 i 开始时,依次判断接下来的每个单词是否在集合中,如果单词在集合中,就从集合中删除该单词。这里用一个 
class Solution {
public:
    vector<int> findSubstring(string s, vector<string>& words) {
        int word_len = words[0].size();
        int len = words.size()*word_len;
        int n = s.size();
        unordered_map<string, int> m;              // hash_map<单词,出现的次数>
        for(int i=0; i<words.size(); ++i)
        {
            if(m.count(words[i]) == 0)             // 注意count方法的使用
                m.insert(make_pair(words[i], 1));
            else
                ++m[words[i]];
        }
        vector<int> index;
        for(int i=0; i<=n-len; ++i)                // 枚举起始位置
        {
            if(isContain(s.substr(i,len), m, word_len))
                index.push_back(i);
        }
        return index;
    }
    /**
     * 判断子串s是否由集合words里面的单词拼接而成
     */
    bool isContain(string s, unordered_map<string,int> m, int word_len) {
        int i;
        for(i=0; i<s.size(); i+=word_len) {
            string subs = s.substr(i, word_len);
            unordered_map<string,int>::iterator it = m.find(subs);
            if(it!=m.end() && it->second>0)
                --(it->second);
            else
                break;
        }
        if(i==s.size())
            return true;
        else
            return false;
    }
};假设 
解法二:滑动窗口
本解法的思路和《LeetCode 3 - Longest Substring Without Repeating Characters》差不多,都用了一种滑动窗口的方法。因为单词都是定长的,所以本质上和单个字符一样。
比如s = "a1b2c3a1d4",words=["a1", "b2", "c3", "d4"]
窗口最开始为空:
- a1在集合中,加入窗口 - 【a1】b2c3a1d4
- b2在集合中,加入窗口 - 【a1b2】c3a1d4
- c3在集合中,加入窗口 - 【a1b2c3】a1d4
- a1在集合中,但前面a1已经出现了一次,达到了次数上限,不能再加入窗口。此时只需要把窗口向右移动一个单词: - a1【b2c3a1】d4
- d4在集合中,加入窗口 - a1【b2c3a1d4】此时找到了一个匹配。
class Solution {
public:
    vector<int> findSubstring(string s, vector<string>& words) {
        int word_len = words[0].size();
        int len = words.size()*word_len;
        int n = s.size();
        unordered_map<string, int> m;              // <单词,出现的次数>
        for(int i=0; i<words.size(); ++i)
        {
            if(m.count(words[i]) == 0)             // 注意count方法的使用
                m.insert(make_pair(words[i], 1));
            else
                ++m[words[i]];
        }
        vector<int> index;
        for(int i=0; i<word_len; ++i)
        {
            unordered_map<string, int> win;
            int left = i;                           // 窗口左边沿
            int count = 0;                          // 窗口中的单词数目
            for(int right=i; right<=n-word_len; right+=word_len)
            {
                string word = s.substr(right, word_len);
                if(m.find(word) != m.end())         // 在集合中
                {
                    if(win.find(word) == win.end()) // 不在窗口中,即添加
                        win[word] = 1;
                    else
                        ++win[word];                // 在窗口中
                    if(win[word] <= m[word])        // 还没出现相应的次数
                        ++count;
                    else  
                    {
                        // 单词在集合中,但是它已经在窗口中出现了相应的次数,不应该加入窗口
                        // 此时把窗口起始位置想左移动到,该单词第一次出现的位置的下一个单词位置
                        for(int k=left;  ; k+=word_len)
                        {
                            string temp = s.substr(k, word_len);
                            --win[temp];
                            if(temp == word)
                            {
                                left = k + word_len;
                                break;
                            }
                            --count;
                        }
                    }
                    if(count == words.size())
                        index.push_back(left);
                }
                else                                // 不在集合中,从窗口右侧重新开始
                {
                    left = right + word_len;
                    win.clear();
                    count = 0;
                }
            }
        }
        return index;
    }
};此解法的时间复杂度是
由于 
LeetCode答案源代码:https://github.com/SongLee24/LeetCode 
 
                    
                     
                    
                 
                    
                 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号