題目描述:
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)來解決問題,使用的滑動窗口法。那麼這裏就可以給自己提個醒,在進行匹配問題,尤其是大中找小的這種問題,就應該想到滑動窗口法。