题目描述:
给定一个字符串 s 和一个字符串数组 words。 words 中所有字符串 长度相同。
*
* s 中的 串联子串 是指一个包含 words 中所有字符串以任意顺序排列连接起来的子串。
输入:s = "barfoothefoobarman", words = ["foo","bar"]
* 输出:[0,9]
* 解释:因为 words.length == 2 同时 words[i].length == 3,连接的子字符串的长度必须为 6。
* 子串 "barfoo" 开始位置是 0。它是 words 中以 ["bar","foo"] 顺序排列的连接。
* 子串 "foobar" 开始位置是 9。它是 words 中以 ["foo","bar"] 顺序排列的连接。
* 输出顺序无关紧要。返回 [9,0] 也是可以的。
解题思路:
- 一开始的想法是,以字符串数组中单词的长度为单位往前走,反正都是固定长度,然后维护一个map来记录单词出现的情况,但是忽略了单词可以重复出现,所以遇到相同的单词的时候会出现问题,因为我的map里已经有一个了,然后我直接跳过去了。
- 这个时候我发现一个map 没办法来判断单词出现的次数是不是符合本来要出现的次数,还需要一个基准map,所以用到了两个map来判断出现的次数是不是对的。
- 但是忽略了一种情况是单词是可以截断的,他出现的位置不一定就是按照单词的长度的整数倍来出现的,比如:
findSubstring('lingmindraboofooowingdingbarrwingmonkeypoundcake', ["fooo","barr","wing","ding","wing"])
这个如果我按照4为步长前进,是找不到答案的。
- 所以步长更改为1,出现某些情况的时候从头开始来判断。这样做出来性能很差,只能算是暴力解法了。
解法一(暴力哈希):
function findSubstring(s, words) {
let step = words[0].length;
let start = 0;
let end = step;
let res = [];
// 存放单词应该出现的次数
let map = new Map();
// 计算行进过程中出现了对的单词,就让次数减1,减到0说明个数到了
let wordMap = new Map();
// 先记录所有单词出现的次数
for (let i = 0; i < words.length; i++) {
if (map.get(words[i])) {
map.set(words[i], map.get(words[i]) + 1);
wordMap.set(words[i], wordMap.get(words[i]) + 1);
continue;
}
map.set(words[i], 1);
wordMap.set(words[i], 1);
}
while (end <= s.length) {
// 当前正在判断的单词
let word = s.substring(end - step, end);
// 如果目标里没有这个单词,就往前进一个,同时清空记录的表
if (!map.has(word)) {
map.forEach((value, key) => {
wordMap.set(key, value);
});
start = start + 1;
end = start + step;
continue;
}
// 如果当前单词在目标单词里面,并且这个单词出现次数还没超,就往前进一个单词的长度
if (wordMap.has(word) && wordMap.get(word) > 0) {
wordMap.set(word, wordMap.get(word) - 1);
end = end + step;
} else {
// 如果不需要这个单词,或者这个单词已经次数满了,就从头前进一位,从头再来
map.forEach((value, key) => {
wordMap.set(key, value);
});
start = start + 1;
end = start + step;
}
// 每次判断窗口长度是否超过,如果相等,而前面没有跳出去,说明目前为止都符合,把下标塞进要返回的数组里,再从头开始
if ((end - step - start) / step === words.length) {
res.push(start);
map.forEach((value, key) => {
wordMap.set(key, value);
});
start = start + 1;
end = start + step;
}
}
return res;
};
用时:
// Your runtime beats 16.67 % of typescript submissions
// Your memory usage beats 98.89 % of typescript submissions (48.1 MB)