给定一个字符串 s 和一些长度相同的单词 words。找出 s 中恰好可以由 words 中所有单词串联形成的子串的起始位置。
注意子串要与 words 中的单词完全匹配,中间不能有其他字符,但不需要考虑 words 中单词串联的顺序。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/substring-with-concatenation-of-all-words
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
方法一:暴力
通过滑动窗口确定子串,再一个一个匹配word中的string,如果找到相同的,则从向量tmp中删掉,这样考虑到了单词可能有重复的问题,但是不出所料的tle了,主要是败在了几百个ab匹配99个ab单词的问题。
class Solution {
public:
vector<int> findSubstring(string s, vector<string>& words) {
if(s.empty() || words.empty()) return vector<int>();
int strlen = s.length();
int sublen = words[0].length();
int subnum = words.size();
int window = subnum * sublen;
vector<int> res;
int i, j, k;
for (i = 0; i <= strlen - window; i++) {
string curstr = s.substr(i, window);
vector<string> tmp = words;
for (j = 0; j < subnum; j++) {
k = 0;
bool change = false;
while (tmp.size() != 0 && k < tmp.size()) {
if (curstr.substr(j * sublen, sublen) == tmp[k]) {
tmp.erase(tmp.begin() + k);
change = true;
break;
}
else {
k++;
}
}
if (change == false) {
break;
}
}
if (tmp.size()==0) {
res.push_back(i);
}
}
return res;
}
};
方法二:map
因为上面的方法针对word重复很多次的情况效率并不高,故参考了评论里的答案,使用了map来对词数做一个统计
class Solution {
public:
vector<int> findSubstring(string s, vector<string>& words)
{
if (words.size() == 0) return {};
unordered_map<string, int> wordcnt;
for (auto& w : words)
{
wordcnt[w]++;
}
int len = words[0].size();
vector<int> ans;
for (int i = 0; i < len; i++)
{
int left = i;
int right = left;
int cnt = 0;
unordered_map<string, int> window;
while (left + words.size() * len <= s.size())
{
string temp = "";
while (cnt < words.size())
{
temp = s.substr(right, len);
if (wordcnt.find(temp) == wordcnt.end() || window[temp] >= wordcnt[temp]) break;
window[temp]++;
cnt++;
right += len;
}
if (window == wordcnt)
{
ans.push_back(left);
}
if (wordcnt.find(temp) != wordcnt.end())
{
window[s.substr(left, len)]--;
cnt--;
left += len;
}
else
{
right += len;
left = right;
cnt = 0;
window.clear();
}
}
}
return ans;
}
};