面试题 17.18. 最短超串(滑动窗口模块)

223 阅读1分钟

每日刷题第12天 2021.1.7

最短超串

  • 难度:中等
  • 方法:滑动窗口

题目

  • 假设你有两个数组,一个长一个短,短的元素均不相同。找到长数组中包含短数组所有的元素的最短子数组,其出现顺序无关紧要。
  • 返回最短子数组的左端点和右端点,如有多个满足条件的子数组,返回左端点最小的一个。若不存在,返回空数组。

示例

输入:
big = [7,5,9,0,2,1,3,5,7,9,1,1,5,8,8,9,7]
small = [1,5,9]
输出: [7,10]
输入:
big = [1,2,3]
small = [4]
输出: []

提示

  • big.length <= 100000
  • 1 <= small.length <= 100000

解法

/**
* @param {number[]} big
* @param {number[]} small
* @return {number[]}
*/
var shortestSeq = function(big, small) {
  // 处理数据
  let map1 = new Map();
  // 长数组的长度
  let lenB = big.length;
  // 短数组的长度
  let lenS = small.length;
  for (let i = 0; i < lenS; i++) {
    if (map1.has(small[i])) {
      map1.set(small[i], map1.get(small[i]) + 1);
    }else {
      map1.set(small[i], 1);
    }
  }
// console.log('处理后的数据集', map1);
// 开始指针
let start = 0;
// 结束指针
let end = 0;
// 存储最终的结果
let ans = [];
// 记录符合数据的长度
let len = 0;
// 新的map集合,存储遍历过程中存储的数字个数
let map2 = new Map();
// 临时比较数据
let tempt = Infinity;
// 标记变量,记录是否是第一次
let flag = true;
while (end < lenB) {
// 不符合要求,动end
  if (map1.has(big[end])) {
  // console.log('map2',map1.has(big[end]),'send',big[end],'end', end);
  // map1中存在,map2记录
    if (map2.has(big[end])) {
      map2.set(big[end], map2.get(big[end]) + 1);
    }else {
      map2.set(big[end], 1);
    }
    // console.log('处理过后的map2', map2);
    // 如果没有超过既定的值,就需要len++
    if (map2.get(big[end]) <= map1.get(big[end])) {
      len++;
      console.log('len++',len);
    }
    // 打破循环,动start
    while(len >= lenS) {
    // console.log('执行打破循环',len,'start',start,'lenS',lenS);
    // 长度相等,取结果
      if (flag) {
        // 是第一次
        ans = [start, end];
        tempt = Math.min(tempt, end - start + 1);
        flag = false;
        // console.log('首次记录结果', ans,tempt);
      }else {
        // 不是第一次
        if(len == lenS && tempt > (end - start + 1)) {
          ans = [start, end];
          tempt = Math.min(tempt, end - start + 1);
          // console.log('记录结果', ans,tempt);
        }
      }
    // 存在,弹出就需要更改个数
    if (map2.has(big[start])) {
      map2.set(big[start], map2.get(big[start]) - 1);
    }
    // 如果map2中的值小于map1中的值,就len--
    if (map2.get(big[start]) < map1.get(big[start])) {
      len--;
    }
    start++;
    }
  }
 end++;
// console.log('执行完成一次',len);
 }
return ans;
};

附录

  • 滑动窗口,一次AC