被这道题卡了很久,现在过了,把思路整理一下。
因为给定单词长度都是相等的,一开始就想把s按单词长度分割,用哈希表比对。然而s中可能有其他单词,这种方法不合适。
一个字母一个字母扫肯定会超时,那还是要借助哈希表,利用每个单词长度相等这个信息来进行比较。这时候,感恩一位老哥写的题解,让我茅塞顿开:
s barfoofoobarthefoobarman
words "bar", "foo", "the"
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
b a r f o o f o o b a r t h e f o o b a r m a n
i=0
滑动窗口start = 0 b a r f o o f o o
滑动窗口start = 3 f o o f o o b a r
滑动窗口start = 6 f o o b a r t h e
滑动窗口start = 9 b a r t h e f o o
滑动窗口start = 15 t h e f o o b a r
滑动窗口start = 15 f o o b a r m a n
i=1
滑动窗口start =1 a r f o o f o o b
滑动窗口start = 4 o o f o o b a r t
滑动窗口start = 7 o o b a r t h e f
滑动窗口start = 10 a r t h e f o o b
滑动窗口start = 13 h e f o o b a r m
这种处理的方法是将s分成一个个符合words长度的单词(就简称为基本单位吧),先从下标为0的位置开始分割,那还有很多种分割方式没有考虑到啊,不急,再从下标为1的位置开始分割,如此重复,一直到完成从下标为words的长度 - 1的分割过程,当我们想继续分割的时候,欸~,已经完成一个周期了,在分下去就是从下标为1的位置开始分割除去第一个基本单位的模样了,那自然就不用考虑了呀。
既然所有种类都分割出来了,我们就要一一比对了。这里我们借助哈希表就可以轻松完成。比对的详解我就写在代码注释里面啦
class Solution {
public:
vector<int> findSubstring(string s, vector<string>& words) {
vector<int> ans;
int m = words.size();
int w = words[0].size();
int n = s.size();
unordered_map<string, int> count;
for(auto word : words){
count[word]++;//先遍历words,确认窗口中各个单词需要出现的次数。
}
for(int i = 0; i < w; i++){//进行分割处理,找到所有分割类别
int cnt = 0;//记录窗口中有几个合规(出现在words中,且不多于出现次数)的单词,在cnt == words总数时自然就找到啦
unordered_map<string, int> window;
for(int j = i; j + w <= n; j += w){//每次加一个基本单位长度,可以理解成一格一格
if(j - i >= w * m){//窗口装不下啦,窗口左边就要向右移动
string word = s.substr(j - m * w, w);//将最左边的基本单位记录下来
window[word]--;//出去了,所以窗口中这个单位出现的次数 - 1
if(window[word] < count[word]){//满足这个条件,说明刚刚移出去的基本单位是合规的,那cnt就要 - 1 啦
cnt--;
}
}
string word = s.substr(j, w);//判断窗口右边新加进来的单位是否合规
window[word]++;
if(window[word] <= count[word]){
cnt++;
}
if(cnt == m){//因为窗口只装的下 m * w个长度,cnt == m的话,自然就满足题目要求啦
ans.push_back(j - w * (m - 1));//j此时是最右边,答案要的是字符串最左边的位置
}
}
}
return ans;
}
};
希望对你有所帮助:D