題目
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).
分析
這道題真的惡心到我了。一個下午都沒寫出來。不過后來弄出來之后又覺得異常簡單。
思路:由words可知最終組成的子串的長度,枚舉子串的開頭,依次判斷是否符合規則即可。
實現一
class Solution {
public:
vector<int> findSubstring(string s, vector<string>& words){
vector<int> ans;
int wl=words[0].size(), sl=s.size(), n=words.size();
unordered_map<string, int> dict;
for(int i=0; i<n; i++)
dict[words[i]]++;
unordered_map<string, int> times;
for(int left=0; left+wl*n<=sl; left++){
//init
bool valid = true;
for(int i=left; i<left+wl*n; i+=wl){
string str = s.substr(i, wl);
if(!dict.count(str)){
times.clear();
valid = false;
break;
}
times[str]++;
}
if(!valid) continue;
//valid?
for(int i=0; i<n; i++){
if(times.count(words[i])==0 || dict[words[i]]!=times[words[i]]){
valid=false;
break;
}
}
if(valid){
ans.push_back(left);
}
//next
times.clear();
}
return ans;
}
};
思考一
提交成功后發現所有選手的運行時間的分布有兩個明顯的駝峰,而我的方法在后一個駝峰。所以考慮還有更好的算法。原算法的復雜度為O(slwln)思考后發現如果假設s是由與words中字符串長度相等的子串組成的話,會簡單很多。那么可以根據words中字符串的長度wl來將答案分為wl類,這樣可以將復雜度降為O(sl/wlwln)=O(sl*n)。而在每一組中,以wl為間隔枚舉開頭,并且在計算下一組的狀態時,可以通過“掉前一組的頭,加上這一組的尾”來實現。
實現二
class Solution {
public:
vector<int> findSubstring(string s, vector<string>& words) {
vector<int> ans;
int wl=words[0].size(), sl=s.size(), n=words.size();
unordered_map<string, int> dict;
for(int i=0; i<n; i++)
dict[words[i]]++;
for(int group=0; group<wl; group++){
unordered_map<string, int> times;
for(int count=0, left=group; left+n*wl<=sl; left+=wl){
for(int i=left+count*wl; count<n && i+wl<=sl; i+=wl){
string str = s.substr(i, wl);
times[str]++;
count++;
}
if(count<n)
return ans;
bool valid=true;
for(int i=0; i<n; i++){
if(times.count(words[i])==0 || dict[words[i]]!=times[words[i]]) {
valid=false;
break;
}
}
if(valid){
ans.push_back(left);
}
string str=s.substr(left, wl);
times[str]--;
count--;
}
}
return ans;
}
};
思考二
果然改變算法之后進入了第一梯隊,開心。