持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第12天,点击查看活动详情
面试题 17.18. 最短超串
假设你有两个数组,一个长一个短,短的元素均不相同。找到长数组中包含短数组所有的元素的最短子数组,其出现顺序无关紧要。
返回最短子数组的左端点和右端点,如有多个满足条件的子数组,返回左端点最小的一个。若不存在,返回空数组。
「示例1:」
输入:
big = [7,5,9,0,2,1,3,5,7,9,1,1,5,8,8,9,7]
small = [1,5,9]
输出: [7,10]
「示例2:」
输入:
big = [1,2,3]
small = [4]
输出: []
「提示:」
big.length <= 100000
1 <= small.length <= 100000
解题思路
我们利用两个指针指向长数组,两个指针里面的内容,就是我们的窗口
我们用 map 来记录短数组中的元素在长数组中出现的次数,初始化为 1,出现一次数量减一
我们用数量 count 来代表,窗口中还没有出现过的短数组中元素的个数,当我们窗口中出现一个短数组中的数量时, count 的数量减一,当我们的count为0的时候,我们从窗口中就包含所有短数组中的元素
我们来计算窗口的宽度,如果宽度小于最小宽度,更新结果
找到一个结果后,我们从左边开始收缩窗口,收缩的是否符合条件的话,更新结果,直到我们的窗口中不包含短数组中的值,再从右边扩充窗口去寻找合适的结果
代码实现
/**
* @param {number[]} big
* @param {number[]} small
* @return {number[]}
*/
var shortestSeq = function(big, small) {
const bigLen = big.length
const map = new Map, ret = []
for (const num of small) {
map.set(num, 1)
}
// 在滑动窗口计算大数组的数字
let l = 0, min = Infinity, count = small.length
while(!map.has(big[l])) l++
if (l < bigLen) {
let cou = map.get(big[l])
cou--
if (!cou) count--
map.set(big[l], cou)
if (!count) {
ret[0] = ret[1] = l
min = 1
}
}
let r = l + 1
while(r < bigLen) {
if (map.has(big[r])) {
let cou = map.get(big[r])
cou--
if (!cou) count--
map.set(big[r], cou)
while (!count) {
const differ = r - l
if (differ < min) {
min = differ
ret[0] = l
ret[1] = r
}
let cou = map.get(big[l])
cou++
if (cou > 0) count++
map.set(big[l], cou)
l++
while (!map.has(big[l]) && big[l] !== big[r]) l++
}
}
r++
}
return ret;
};
如果你对这道题目还有疑问的话,可以在评论区进行留言;