Substring with Concatenation of All Words——解題報告(視窗移動法)

來源:互聯網
上載者:User

標籤:leetcode   substring   map   視窗移動法   字串匹配   


    【題目】

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) in s that is a concatenation of each word in wordsexactly once and without any intervening characters.

For example, given:
s: "barfoothefoobarman"
words: ["foo", "bar"]

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


    【分析】

    本題目解法有兩個,第一個是常規思路,第二個是視窗移動法,這個方法需要掌握。


    解法一:先把words存在一個map中,key是單詞字串,value是出現的次數。然後逐個位置遍曆字串s(注意遍曆結束位置不必到最後,剩餘長度小於單詞總長度即停止),判斷其後面的和檔次總長度相同的子串中的每個單詞是否和words一樣。如果一樣,這push_back進去;否則,遍曆下一個字元。時間複雜度:O(LNw),L是s的長度,N是words的個數,w是word的長度。

    代碼:

class Solution {public:    vector<int> findSubstring(string s, vector<string>& words) {        vector <int> res;        int N = words.size(); // number of words        if(N == 0)            return res;        int len = words[0].length();  // length of each word        int strLen = s.length();  // length of string                map<string, int> countWords;  // get the wordCount map        for(int i = 0; i < N; i ++)        {            if(countWords.count(words[i]))                countWords[words[i]]++;            else                countWords[words[i]] = 1;        }                map<string, int> counting;        for(int i = 0; i <= strLen - len * N; i++)  // first loop        {            counting.clear();            bool flag = true;            for(int j = i; j < i + N*len; j += len)  // second loop            {                string w = s.substr(j, len);                if(countWords.count(w) == 0)  //  if not exist in countWords, break directly                {                    flag = false;                     break;                }                else                {                    if(counting.count(w))  // if not new                        counting[w]++;                    else                        counting[w] = 1;                }            }            if(!flag)                continue;            else            {                if(compare(counting, countWords))                    res.push_back(i);                else                    continue;            }        }            }    bool compare(map<string, int> counting, map<string, int> countWords)    {        map<string, int>::iterator iter;        for(iter = countWords.begin(); iter != countWords.end(); iter++)        {            if(counting[iter->first] != iter->second)                return false;        }        return true;    }};


    解法二:視窗移動法。

    首先,初始化一個長度為0的視窗,定義頭部是begin,尾部是tail。判斷tail後面的一個單詞,如果在words裡面,則tail往後移動,即視窗伸長一個單詞的量;如果tail後面的單詞壓根兒不在words裡面,那麼把begin後移到最後位置,重新初始化視窗,繼續判斷;如果tail後面的單詞是之前出現過,不過words中沒有這個單詞的容量,那麼begin後移到該單詞第一次出現的位置,繼續判斷。這個方法的時間複雜度為O(Lw)。

    代碼:

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

另外還有一個代碼,沒有調試成功,後續修改ing。

class Solution {public:    vector<int> findSubstring(string s, vector<string>& words) {        vector <int> res;        int N = words.size(); // number of words        if(N == 0)            return res;        int len = words[0].length();  // length of each word        int strLen = s.length();  // length of string                map<string, int> countWords;  // get the wordCount map        for(int i = 0; i < N; i ++)        {            if(countWords.count(words[i]))                countWords[words[i]]++;            else                countWords[words[i]] = 1;        }                map<string, int> counting = countWords;        int begin = 0, tail = begin;        while(tail < strLen)        {            if(tail - begin + 1 == N * len)  // get results            {                res.push_back(begin);                begin = tail + 1;                tail = begin;                counting = countWords;                continue;            }                        string w = s.substr(tail, len);                        int kind = moveClass(w, counting);  // get the manner how to move the tail                        if(kind == 1)  // if w not in countWords            {                begin = tail + 2;                tail = begin;                counting = countWords;                continue;            }            if(kind == 2) // if w in countWords now            {                tail += len;                continue;            }            if(kind == 3)  // if w in countWords in past            {                string tmp = s.substr(begin, tail - begin + 1);                begin = tmp.find(w) + 1;                tail = begin;                counting = countWords;                continue;            }        }        return res;     }        int moveClass(string w, map<string, int>& counting)    {        if(counting.count(w) == 0)            return 1;        else if(counting[w] >= 1)        {            counting[w]--;            return 2;        }        else            return 3;    }};









Substring with Concatenation of All Words——解題報告(視窗移動法)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.