题目:
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.
For example, given:
S: "barfoothefoobarman"
L: ["foo", "bar"]
You should return the indices: [0,9]
.
(order does not matter).
思路:
假设len表示L字串的长度,num表示L字串的数目。
需要用S中的字母与L中的字符串中的字母一个一个去比较,所有比较成功则产生一个结果,否则会发生回溯。由于有回溯存在,势必需要字符串会被重复比较。因此我们可以利用动态规划的观点来存储S中的字串与L的关系。 sameWord用来存储这个结果,sameWord[k]表示从k开始,长度为L中字符串长度的S中字符串与L中的第几个字符串匹配。
第二个问题是,L中的字符串可能有重复。所以我们需要有一个map结果来保存字符串与其对应的编号。L中的重复字符串就应当对应相应的编号。代码中的words就是这样的结果。
第三个问题是,我们不仅要用编号来排除重复的字符串,还需要保存字符串重复的次数。因此我们引入了dict来保持重复次数。
以上问题解决之后,我们只需要带回溯的循环一次来依次查看从i开始,长度为len*num的S字串与L所有字串的关系。
代码:
class Solution {
public:
vector<int> findSubstring(string S, vector<string> &L) {
vector<int> r;
int len=L[0].size();
int num=L.size();
unordered_map<string,int> words;
vector<int> dict;
int count=0;
for(int i=0;i<L.size();i++)
{
unordered_map<string,int>::const_iterator got = words.find (L[i]);
if(got==words.end())
{
pair<string,int> item(L[i],count);
words.insert(item);
dict.push_back(1);
count++;
}
else
{
dict[got->second]++;
}
}
//建立L中字符串(重复)与其对应的编号,以及每个编号字符串出现的次数
int* sameWord = new int [S.size()];
for(int i=0;i+len<=S.size();i++)
{
unordered_map<string,int>::const_iterator got = words.find (S.substr(i,len));
if(got != words.end())
{
sameWord[i] = got->second;
}
else
{
sameWord[i] = -1;
}
}
//建立动态规划方程来记录i开始,长度为len的S字串与L字符串的关系
for(int k=0;k+len*num<=S.size();k++)
{
int begin=k;
vector<int> tmp = dict;
bool found = true;
int total = num;
while(total>0)
{
int index = sameWord[begin];
if(index == -1)
{
found = false;
break;
}
else
{
if(tmp[index]>0)
{
tmp[index]--;
total--;
begin+=len;
}
else
{
found = false;
break;
}
}
};
if(found)
{
r.push_back(k);
}
}
//每次循环查看,长度为len*num的字串能否涵盖所有的L字串
return r;
}
};