题目描述:
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.
题目理解:
本题的意思是在给定字符串中寻找特定字符串,该特定字符串是由所给字符串向量中的所有字符串按任意顺序拼接成的,只要找到了任意一种组合情况,就将起始的索引点加入到answer中,最后输出answer
不过该题有个比较坑的点,你必须认真读题,它声明的是字符串向量中的每个字符都相等,但是它的第二个例子却并不符号这个要求,如果光看例子不读题的话,就会吃亏,做题时会比较费劲。。
Example 2:
Input:
s = "wordgoodstudentgoodword",
words = ["word","student"] //!!!这里的student跟word不一样长。。。。
Output: []
在明确了这一点后,就可以着手解决问题了。
- 声明两个哈希表,第一个存储words中每个单词的词频,第二个作为遍历时每个词词频的记录。
- 找到第一个符合条件的字符作为开始,然后每次叠加固定长度的字符,完善第二个哈希表,每次遍历结束后,将两个表进行比较:
- 比较结果相同,则将开始索引点加入结果
- 否则找下一个符合条件的字符串作为新的开始节点。
代码:
class Solution {
public:
vector<int> findSubstring(string s, vector<string>& words) {
vector<int> ans;
if(s.empty()||words.empty()) return ans;
map<string,int> target;
int al = words[0].size();
int len = al * words.size();
if(len > s.size()) return ans;
for(int i=0;i<words.size();i++){
target[words[i]]++;
}
int start = 0;
while(target[s.substr(start,al)]==0) start++;
while(start<s.size()){
map<string,int> tmp;
int count = 0;
for(int i=start;i<s.size()-al+1;i+=al){
string str = s.substr(i,al);
//cout<<str<<' ';
if(target[str]!=0){
//cout<<"!!"<<target[str]<<' ';
tmp[str]++;
count++;
}else{
break;
}
if(count == words.size()){
break;
}
}
//cout<<endl;
bool flag = true;
for(int i=0;i<words.size();i++){
if(target[words[i]] != tmp[words[i]] || tmp[words[i]]==0){
flag = false;
break;
}
}
if(flag){
ans.push_back(start);
}
start++;
while(target[s.substr(start,al)]==0 && start<s.size()-al) start++;
}
return ans;
}
};
后记:
我的代码的时间复杂度是O(n^2),查看discuss后发现可以降到O(n)来解决问题,使用的滑动窗口法。那么这里就可以给自己提个醒,在进行匹配问题,尤其是大中找小的这种问题,就应该想到滑动窗口法。