给定一个字符串 s 和一些长度相同的单词 words。找出 s 中恰好可以由 words 中所有单词串联形成的子串的起始位置。
注意子串要与 words 中的单词完全匹配,中间不能有其他字符,但不需要考虑 words 中单词串联的顺序。
示例 1:
输入:
s = "barfoothefoobarman",
words = ["foo","bar"]
输出:[0,9]
解释:
从索引 0 和 9 开始的子串分别是 "barfoo" 和 "foobar" 。
输出的顺序不重要, [9,0] 也是有效答案。
示例 2:
输入:
s = "wordgoodgoodgoodbestword",
words = ["word","good","best","word"]
输出:[]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/substring-with-concatenation-of-all-words
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
naive 的想法是,将 words 里面的单词组合成字符串,然后到 s 里面去找有没有跟它一样的子串。但是,这样子时间复杂度太高了,因为 words 的组合有 words.length!
种,总复杂度差不多就是 s.length * words.length!
了。
/**
* @param {string} s
* @param {string[]} words
* @return {number[]}
*/
var findSubstring = function(s, words) {
const wordLen = words[0].length;
const substrLen = wordLen * words.length;
const initialWordsMap = words.reduce((map, w) => {
map[w] = (map[w] || 0) + 1;
return map;
}, {})
const res = [];
for (let i = 0; i <= s.length - substrLen; i++) {
const wordsMap = {...initialWordsMap};
for (let j = i; j < i + substrLen; j += wordLen) {
const word = s.slice(j, j + wordLen);
if (!(word in wordsMap) || wordsMap[word] == 0) break;
wordsMap[word]--;
}
if (usedUpWords(wordsMap)) res.push(i);
}
return res;
// ******************************************
function usedUpWords(map) {
return Object.values(map).every(n => n == 0);
}
};
/**
* @param {string} s
* @param {string[]} words
* @return {number[]}
*/
var findSubstring = function (s, words) {
const wordSize = words[0].length;
const substringLen = wordSize * words.length;
const wordsCount = {};
words.forEach(w => (wordsCount[w] = (wordsCount[w] || 0) + 1));
const res = [];
for (let i = 0; i <= s.length - substringLen; i++) {
const tempCount = { ...wordsCount };
let count = words.length;
for (let j = i; j < i + substringLen; j += wordSize) {
const word = s.slice(j, j + wordSize);
if (!(word in tempCount) || tempCount[word] <= 0) break;
tempCount[word]--;
count--;
}
if (count === 0) res.push(i);
}
return res;
};