每日算法之二十六:Substring with Concatenation of All Words
變相的字符串匹配
給定一個字符串,然後再給定一組同樣長度的單詞列表,要求在字符串中查找滿足下面條件的起始位置:
1)從這個位置開始包括單詞列表中全部的單詞。且每一個單詞僅且必須出現一次。
2)在出現的過程中不能出現其它的幹擾單詞。
3)出現的位置可能有多個。
4)單詞的出現順序不做要求。
以下是一個樣例:
S:"barfoothefoobarman"
L:"foo","bar"
位置0是出現位置,。兩個單詞均出現僅出現一次,且沒有幹擾。
相同位置9也是滿足的。
原題要求例如以下:
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.
思路例如以下:
首先初始化一個map容器,內含單詞列表中出現的單詞,以及單詞出現的次數。
把容器當做比較的模板。
string | int |
bar | 1 |
foo | 1 |
由於中間幹擾詞的長度是不確定的。因此i僅僅能是逐一的後移來尋找匹配的位置。
我們首先獲得字符串中的第一個單詞,bar。查看在上述的容器中是否有這個單詞,假設沒有,直接指針後移匹配下一個位置開始的單詞。查找後是有的,因此我們把這個單詞增加到一個新的map容器中,這個容器存儲的是從當前指針位置開始滿足單詞列表的單詞。這這個樣例中就是bar在初始化的容器中存在,那麽就把他增加新容器中。同一時候。統計次數也要遞增,接下來查看這個單詞在新容器中出現的次數是否小於等於初始化容器中的次數。假設大於說明這是錯誤的。也須要指針後移。
最後,當我們後移單詞列表中指定個數的單詞或者由於不匹配而終止從指針位置i開始的查找時。在循環外面我們要推斷一下單詞匹配的個數是否和單詞列表中的次數一樣,假設一樣說明從當前指針的位置是匹配的。那麽就把這個指針位置保存起來。如此循環往復就可以。代碼例如以下。順著走一遍就明確了。
class Solution { public: vector<int> findSubstring(string S, vector<string> &L) { map<string,int> words,cur; int wordNum = L.size(); int wordLen = L[0].size(); vector<int> res; for(int k = 0;k<wordNum;k++) words[L[k]]++;//初始化容器 for(int i = 0;i<=static_cast<int>(S.length()-wordLen*wordNum);i++) { cur.clear();//每次使用之前要清空,這個容器是不斷變化的 int j; for(j = 0;j<wordNum;j++) { string word = S.substr(i+j*wordLen,wordLen);//獲取這個單詞 if(words.find(word) == words.end())//這個單詞不是單詞列表中的 break; cur[word]++; if(words[word]<cur[word])//出現的次數多了 break; } if(j == wordNum)//這時候是匹配的 res.push_back(i); } return res; } };
每日算法之二十六:Substring with Concatenation of All Words