输入:s = "wordgoodgoodgoodbestword", words = ["word","good","best","word"] 输出:[]
暴力解法
解题思路:
用 map 来存储 words,把 words 中的单词作为 key,单词出现的次数作为 value
循环字符串 s,然后每次从字符串 s 中截取一段长度为 words 单词总长的字符串,然后按照单个 words 单词的长度,对其进行拆分成单词
使用拆分后的单词去 map 中查询,如果存在,则将其 value - 1,否则表明当前字符串不符合要求
内层循环结束后,如果 map 所有的 value 都为 0,则表明当前子字符串符合要求,将其起始索引放入结果集中
最后返回结果集
var findSubstring = function (s, words) { if (!s || !words || !words.length) return []; let wordLen = words[0].length; let allWordsLen = wordLen * words.length; let len = s.length; let map = {}; let ans = [];
for (let word of words) { map[word] ? map[word]++ : (map[word] = 1); }
for (let i = 0; i <= len - allWordsLen; i++) { let vm = { ...map }; for (let j = i; j <= i + allWordsLen - wordLen; j += wordLen) { // 将字符串切割成长度为 wordLen 的子字符串 let w = s.slice(j, j + wordLen); if (vm[w]) { vm[w]--; } else { break; } }
if (Object.values(vm).every((item) => item === 0)) { ans.push(i); } }
return ans; };
滑动窗口解法
var findSubstring = function (s, words) { if (!s || !words || !words.length) return []; let wordLen = words[0].length; let allWordsLen = wordLen * words.length; let len = s.length; let windows = {}; // 存储滑动窗口收集到的目标 words let needs = {}; // 存储目标 words
for (let word of words) { needs[word] ? needs[word]++ : (needs[word] = 1); }
let needsKeyLen = Object.keys(needs).length; let left = 0; let right = 0; let match = 0; // 若 windows[word] === needs[word], 则 match + 1 let ans = [];
// 只需遍历一个 word 的长度,就可知道切割成一个 word 长度的子字符串的所有情况 for (let i = 0; i < wordLen; i++) { windows = {}; right = left = i; match = 0;
while (right <= len - wordLen) { // 滑动窗口右边界以一个 word 的长度为单位进行递增,并截取子字符串 let w1 = s.slice(right, right + wordLen); right += wordLen;
// 若切割得到的子字符串不是目标 word, 直接让左边界等于右边界,重新滑动窗口 if (!needs[w1]) { windows = {}; left = right; match = 0; continue; }
windows[w1] ? windows[w1]++ : (windows[w1] = 1);
if (windows[w1] === needs[w1]) match++;
while (match === needsKeyLen) { // 若滑动窗口长度等于目标 words 的所有长度, 则将左边界添加到结果中, // 例如 s:"barbarfoothefoobarman",words:["foo","bar"],第一次进入 while 循环时,needs = {foo: 1, bar: 1}; windows {bar: 2, foo: 1} if (right - left === allWordsLen) { ans.push(left); }
// 此时 windows 内的存储的 word 值多余 needs, 故需要滑动窗口左边界向右移动 let w2 = s.slice(left, left + wordLen); left += wordLen; if (needs[w2]) { windows[w2]--; if (windows[w2] < needs[w2]) match--; } } } }