问题描述:
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.
Example 1:
Input:
s = “barfoothefoobarman”,
words = [“foo”,”bar”]
Output: [0,9]
Explanation: Substrings starting at index 0 and 9 are “barfoor” and “foobar” respectively.
The output order does not matter, returning [9,0] is fine too.
Example 2:
Input:
s = “wordgoodstudentgoodword”,
words = [“word”,”student”]
Output: []
题源:here;完整实现:here
思路:
两种方案:1 递归法;2 滑动窗法。
方案1
我们依次遍历输入数组s,对每一个位置都判断是否是是words的组合,判断部分采用递归的方式。思路和实现都很简单,但是时间复杂度高,提交后超时,代码如下:
bool isSubstring_1(string s, vector<string>& words){
if (words.size() == 0) return true;
for (int i = 0; i < words.size(); i++){
if (s[0] == words[i][0]){
int j = 0;
while (j < words[i].size() && j < s.size() && words[i][j] == s[j]) j++;
if (j == words[i].size()){
string temp = s;
temp.erase(0, j);
vector<string> temp_words = words;
temp_words.erase(temp_words.begin() + i);
return this->isSubstring_1(temp, temp_words);
}
}
}
return false;
}
vector<int> findSubstring_1(string s, vector<string>& words) {
vector<int> result;
if (words.size() == 0 || s.size() == 0) return result;
for (int i = 0; i < s.size(); i++){
string temp = s;
temp.erase(0, i);
if (this->isSubstring_1(temp, words)) result.push_back(i);
}
return result;
}
方案2
我们使用两个指针left和right来表征窗口左右边界,用curr_map来保存left和right之间的单词,用temp_word表示向窗口种新添的元素,则有如下简化流程图:
这个流程图的作用主要是为了展示滑动窗法的思想,具体实现还是得看代码。
在程序种,判断新添加的temp_word是否属于words需要用到map,以减少查询时间,map是真的好。
方案2得代码如下:
vector<int> findSubstring_2(string s, vector<string>& words) {
vector<int> result;
if (words.size() == 0 || s.size() == 0) return result;
map<string, int> word_map;
int word_len = words[0].size();
for (int i = 0; i < words.size(); i++){
if (word_map.find(words[i]) == word_map.end()) word_map.insert(make_pair(words[i], 1));
else word_map[words[i]] += 1;
}
for (int i = 0; i < word_len; i++){
int left = i, right = i+word_len;
map<string, int> curr_map;
while (right <= s.size()){
string temp_word = s.substr(right - word_len, word_len);
if (word_map.find(temp_word) != word_map.end()){
if (curr_map.find(temp_word) == curr_map.end()) curr_map.insert(make_pair(temp_word, 1));
else curr_map[temp_word] += 1;
if (curr_map[temp_word] <= word_map[temp_word]){
if (right - left == words.size()*word_len){
result.push_back(left);
left = left+word_len, right = left + word_len;
curr_map.clear();
continue;
}
right += word_len;
}
else left = left+word_len, right = left + word_len, curr_map.clear();
}
else left = right, right = left + word_len, curr_map.clear();
}
}
return result;
}