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