Substring with Concatenation of All Words
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 words exactly 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).
這道題相對來說還是比較簡單的, 題意中規定了所有的單詞長度是一樣的.
所以大致考察的就是字符串的查找. 自己做過後網上發現解決的代碼更加清晰, 值得學習, 所以記錄在這裏:
#include <iostream>
#include <vector>
#include <map>
#include <string>
using namespace std;
class Solution {
public:
/* vector<int> findSubstring(string s, vector<string>& words) {
int nWords = words.size();
int wordsLen = words[0].size();
vector<int> ret;
map<string, int> Map;
for(int i=0; i<nWords; i++){
map<string, int>::iterator it = Map.find(words[i]);
if(it == Map.end())
Map[words[i]] = 1;
else
Map[words[i]] = Map[words[i]] + 1;
}
int strLen = s.size();
map<string, int>::iterator it;
int i = 0;
//cout << "strLen = " << strLen << endl;
while(i<strLen) {
map<string, int> Store;
int curSize = 0;
if((strLen - i) < (nWords * wordsLen))
return ret;
string word(s.begin()+i, s.begin()+i+wordsLen);
it = Map.find(word);
//cout << "i = " << i << endl;
if(it == Map.end()){
i++;
continue;
}
else{
Store[word] = 1;
curSize ++;
if(curSize == nWords){
ret.push_back(i);
i ++;
continue;
}
for(int j = i+wordsLen; ; j += wordsLen){
string word(s.begin()+j, s.begin()+j+wordsLen);
//cout << "j is " << j << " and word is " << word << " and curSize is " << curSize << endl;
it = Map.find(word);
if(it == Map.end()){
i ++;
break;
}
else{
map<string, int>::iterator itt;
itt = Store.find(word);
if(itt == Store.end()){
curSize ++;
Store[word] = 1;
//cout << "--------now size is " << curSize << endl;
if(curSize == nWords){
ret.push_back(i);
i ++;
break;
}
}
else{
if(Store[word] == Map[word]){
i ++;
break;
}
else{
curSize ++;
Store[word] = Store[word] + 1;
if(curSize == nWords){
ret.push_back(i);
i ++;
break;
}
}
}
}
}
}
//cout << "i is changed to " << i << endl;
}
return ret;
}
*/
//almost a same solution, but a better implement
vector<int> findSubstring(string s, vector<string>& words) {
int strLen = s.size();
int nWords = words.size();
int wordLen = words[0].size();
vector<int> ret;
map<string, int> Map;
//將單詞放到map中, key爲string, value爲該單詞出現的次數
for(int i=0; i<nWords; i++){
if(Map.find(words[i]) == Map.end())
Map[words[i]] = 1;
else
Map[words[i]]++;
}
//既然題目說明了, 每個單詞的長度是相同的. 那麼我們以後就是按照單詞的長度來判斷一個單詞是否爲words中存在的
//比如單詞長度爲4, 那麼就是每4個字母組成一個單詞進行比較
//要把所有長度爲4的單詞都訪問一遍的方法是用兩層for循環, 像這樣:
//[a ,b, c, d, e, f, g, h] 的話所有長度爲4的單詞有: (abcd, bcde, cdef, defg, efgh)
//for(int i=0; i<4; i++)
// for(int j=i; j<=len-4; j+=l)
// string.substr(j, 4);
for(int i=0; i<wordLen; i++){
map<string, int> Store;
int curSize = 0;
//這個變量用於二層循環的start. 因爲如果abcd不滿足, 還是要繼續查找下去. 接下里就是從efgh開始查找
int windLeft = i;
cout << "i = " << i << endl;
for(int j=i; j<=strLen-wordLen; j+=wordLen){
string word = s.substr(j, wordLen);
if(Map.find(word) == Map.end()){
Store.clear();
curSize = 0;
windLeft = j+wordLen;
continue;
}
//該單詞符合條件, 那麼繼續看是否滿足出現的次數要求. 比如給定的words中出現多個abcd
curSize ++;
if(Store.find(word) == Store.end())
Store[word] = 1;
else
Store[word]++;
//出現次數過多了, 那麼比如我只要兩個, 居然出現了三個. 那麼下次就從第一個這個單詞出現的後面開始繼續查找
string tmp;
if(Store[word] > Map[word]){
do{
tmp = s.substr(windLeft, wordLen);
Store[tmp] --;
curSize --;
windLeft += wordLen;
}while(tmp != word);
}
//出現了滿足題目要求的了,將開始下標(即windLeft)放到結果vector中去
if(curSize == nWords){
ret.push_back(windLeft);
//可能給定的words是{"abcd", "efgh"}
//給定的s是 "abcdefghabcd", 這裏面存在兩對呢.
//於是在得到第一個結果後, 把最左邊的元素"abcd"刪掉, 把efgh作爲開頭繼續尋找
string tmp = s.substr(windLeft, wordLen);
Store[tmp]--;
curSize--;
windLeft += wordLen;
}
}
}
return ret;
}
};
int main()
{
Solution x;
string s("lingmindraboofooowingdingbarrwingmonkeypoundcake");
vector<int> ret;
vector<string> v;
v.push_back("fooo");
v.push_back("barr");
v.push_back("wing");
v.push_back("ding");
v.push_back("wing");
ret = x.findSubstring(s, v);
cout << ret.size() <<endl;
return 0;
}