【LeetCode】每日一题 面试题 17.18. 最短超串

97 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 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;
};

如果你对这道题目还有疑问的话,可以在评论区进行留言;