一、题目描述
给定一个字符串 s 和一些长度相同的单词 words。找出 s 中恰好可以由 words 中所有单词串联形成的子串的起始位置。
注意子串要与 words 中的单词完全匹配,中间不能有其他字符,但不需要考虑 words 中单词串联的顺序。
示例 1:
输入:
s = "barfoothefoobarman",
words = ["foo","bar"]
输出:[0,9]
解释:
从索引 0 和 9 开始的子串分别是 "barfoor" 和 "foobar" 。
输出的顺序不重要, [9,0] 也是有效答案。
示例 2:输入:
s = "wordgoodgoodgoodbestword",
words = ["word","good","best","word"]
输出:[]来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/substring-with-concatenation-of-all-words
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
二、解题思路
滑动窗口法,所有words的单词总长度为窗口大小len,单个单词长度为单位len_w。先通过一个map,count_words统计所有单词的个数
1、遍历窗口的起始位置index = 0~len_w。left = index,right = index + len,进入循环,从right往前移动,left_inner为当前偏移位置,每次往前移len_w长度,通过map count_now统计当前单词的总数。
1)当前单词不在count_words里或者当前单词在count_now里的统计个数大于count_words里的个数的时候,说明这个窗口的子串肯定不满足匹配words所有单词,此时left偏移到left_inner+len_w的位置,right = left+len。
2)当inner_left == left并且不满足条件一的时候说明,子串满足匹配words所有单词。此时将left记录。同时往前偏移len的长度将left = right,right = left + len。
3)当不满足条件1和条件2的时候,说明从left_inner到right的区间内的单词是在words里的并且个数没有超过count_words里的个数,此时left_inner继续往前移动,left_inner = left_inner - len_w。最后肯定会遇到条件1或者条件2进入下一个循环
当起始位置index = 0~len_w(因为起始位置限定在0~len_w之间,是因为如果其实位置为n*len_w+i的时候,相当于其实位置i的滑动窗口往前移动了n步(len_w为1步)的结果,已经遍历过了没有必要重复遍历)都遍历过了之后将所有可能匹配的索引都找到了。
三、代码
class Solution {
public:
vector<int> findSubstring(string s, vector<string>& words) {
vector<int> save;
if(words.size() == 0)
return save;
map<string,int> word_counts;
int lenw = words[0].size();
for(int i = 0; i < words.size(); i ++)
{
word_counts[words[i]] ++;
}
int words_size = words[0].size()*words.size();
for(int i = 0; i < words[0].size(); i++)
{
int left = i;
int right = i + words_size;
while(right <= s.size())
{
int inner_left = right - lenw;
map<string,int> word_now;
while(inner_left >= left)
{
//cout<<"left="<<left<<endl;
//cout<<"left_inner="<<inner_left<<endl;
string stmp = s.substr(inner_left,lenw);
if(word_counts[stmp] == 0 || word_now[stmp] + 1 > word_counts[stmp])
{
left = inner_left + lenw;
right = left + words_size;
break;
}
else
{
if(inner_left <= left)
{
save.push_back(inner_left);
left = left + lenw;
right = left + words_size;
break;
}
word_now[stmp]++;
inner_left -= lenw;
}
}
}
}
return save;
}
};