原题
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).
题意是在一个字符串s里面,找到恰好由words里字符串组成的字符串,返回它们的首下标组。
发现几个关键的点:
1. words里的字符串长度相同,因此最后的总字符串也长度固定。
2. 按照相等的步长进行遍历,只需要循环word.length次。
3. 设定两个下标指针,分别记录当前搜索的起点和终点,遍历一次只需O(n)的时间复杂度。
4. 遍历过程中,应该用map记录哪个词出现了多少次,由此决定如何移动下标指针。
代码
class Solution {
public:
vector<int> findSubstring(string s, vector<string>& words) {
vector<int> ret;
if(words.empty() || s.size() == 0) {
return ret;
}
map<string, int> m;
for(auto w : words) {
if(m.find(w) != m.end()) {
m[w]++;
} else {
m[w]=1;
}
}
int wLen = words[0].length();
int sLen = s.length();
// cout << wLen << endl;
for(int i=0; i<wLen; i++) {
map<string, int> cur;
int count = 0;
int start = i;
// cout << "Start: " << start << endl;
for(int j=i; j+wLen <= sLen; j+=wLen) {
auto tmp = s.substr(j, wLen);
// cout << tmp << endl;
if(m.find(tmp) == m.end()) {
cur.clear();
count = 0;
start = j+wLen;
} else {
count++;
if(cur.find(tmp) == cur.end()) {
cur[tmp] = 1;
} else {
cur[tmp] ++;
}
while(cur[tmp] > m[tmp]) {
auto tttmp = s.substr(start, wLen);
// cout << "TTTMP: " << tttmp << endl;
cur[tttmp]--;
count--;
start += wLen;
// cout << "Start: " << start << endl;
}
}
if(count == words.size()) {
// cout << "I: " << i << " J: " << j << " Start: " << start << endl;
ret.push_back(start);
}
}
}
return ret;
}
};