前端算法面试必刷题系列[30]

334 阅读3分钟

这个系列没啥花头,就是纯 leetcode 题目拆解分析,不求用骚气的一行或者小众取巧解法,而是用清晰的代码和足够简单的思路帮你理清题意。让你在面试中再也不怕算法笔试。

52. 最小覆盖子串 (minimum-window-substring)

标签

  • 滑动窗口
  • 困难

题目

leetcode 传送门

这里不贴题了,leetcode打开就行,题目大意:

给你一个字符串 s 、一个字符串 t 。返回 s涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 "" 。

注意:如果 s 中存在这样的子串,我们保证它是唯一的答案。

示例

输入:s = "ADOBECODEBANC", t = "ABC"
输出:"BANC"
示例 2:

输入:s = "a", t = "a"
输出:"a"

基本思路

典型的滑动窗口思想,如果不了解,请移步这篇的第三个问题:

滑动窗口思想

那么这个问题可以理解为: 要求在 s 中找到一个最小窗口,这个窗口中包含 t 中所有字符。如果不存在返回空字符串。

基本步骤

  1. 我们首先得确定这个滑动窗口满足的条件:窗口子串内包含 t的所有字符,注意可能有重复字符,所以不能用排序等粗暴解法,那我们就
    • 建立一个 Map,key表示字符,value 是出现次数比如 t = ABCC => Map { 'A' => 1, 'B' => 1, 'C' => 2 }
    • 用 curLessKeysLen 来表示 当前剩余还需要匹配的字符种类
    • 那么满足的条件就是 curLessKeysLen === 0 表示全部都匹配了,也就是 needMap = { 'A' => 0, 'B' => 0, 'C' => 0 }
  2. 滑动右指针扩大窗口(right++),直到满足条件,比较记录下最优解
  3. 此时,我们停止增加right,转而不断增加 left 指针缩小窗口 [left, right],直到窗口中的字符串不再符合要求curLessKeysLen > 0。同时,每次增加left,我们都要更新一轮结果。
  4. 重复第 2和第3步,直到right到达字符串s 的尽头。

写法实现

var minWindow = function(s, t) {
  // 声明结果字串,左右指针,原长度
  let [res, left, right, len] = ["", 0, 0, s.length]
  // 声明字典映射表
  let needMap = new Map()
  // 将当前字典表根据 t 填好 假设 t = "ABCC"
  t.split('').map(item => {
    if (needMap.has(item)) {
      needMap.set(item, needMap.get(item) + 1)
    } else {
      needMap.set(item, 1)
    }
  })
  // console.log(needMap)
  // Map { 'A' => 1, 'B' => 1, 'C' => 2 }
  // 当前剩余还需要匹配的字符种类
  let curLessKeysLen = needMap.size;
  // 开始窗口的滑动
  while (right < len) {
    let curR = s[right]
    if (needMap.has(curR)) {
      // 包含进窗口,needMap对应元素 - 1
      needMap.set(curR, needMap.get(curR) - 1)
      // 说明这个对应元素满足了
      if (needMap.get(curR) === 0) {
        curLessKeysLen -= 1;
      }
    }
    // 当剩余需要匹配长度为 0 说明当前窗口已经满足要求
    while (curLessKeysLen === 0) {
      let curL = s[left]
      let nowStr = s.slice(left, right + 1);
      // 把当前满足要求并且是最短的记录下来
      if (res === "" || res.length > nowStr.length) {
        res = nowStr
      }
      // 下面该移动左边框了,左边移动当然needMap要随之改变
      if (needMap.has(curL)) {
        needMap.set(curL, needMap.get(curL) + 1)
        if (needMap.get(curL) === 1) {
          curLessKeysLen += 1;
        }
      }
      left++;
    }
    right++;
  }
  return res
};

let s = "ADOBECODEBANC", t = "ABC"
console.log(minWindow(s, t))

另外向大家着重推荐下这位大哥的文章,非常深入浅出,对前端进阶的同学非常有作用,墙裂推荐!!!核心概念和算法拆解系列

今天就到这儿,想跟我一起刷题的小伙伴可以加我微信哦 搜索我的微信号infinity_9368,可以聊天说地 加我暗号 "天王盖地虎" 下一句的英文,验证消息请发给我 presious tower shock the rever monster,我看到就通过,暗号对不上不加哈,加了之后我会尽我所能帮你,但是注意提问方式,建议先看这篇文章:提问的智慧

参考