这个系列没啥花头,就是纯 leetcode 题目拆解分析,不求用骚气的一行或者小众取巧解法,而是用清晰的代码和足够简单的思路帮你理清题意。让你在面试中再也不怕算法笔试。
52. 最小覆盖子串 (minimum-window-substring)
标签
- 滑动窗口
- 困难
题目
这里不贴题了,leetcode打开就行,题目大意:
给你一个字符串 s 、一个字符串 t 。返回 s 中 涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 "" 。
注意:如果 s 中存在这样的子串,我们保证它是唯一的答案。
示例
输入:s = "ADOBECODEBANC", t = "ABC"
输出:"BANC"
示例 2:
输入:s = "a", t = "a"
输出:"a"
基本思路
典型的滑动窗口思想,如果不了解,请移步这篇的第三个问题:
那么这个问题可以理解为: 要求在 s 中找到一个最小窗口,这个窗口中包含 t 中所有字符。如果不存在返回空字符串。
基本步骤
- 我们首先得确定这个滑动窗口满足的条件:窗口
子串内包含t的所有字符,注意可能有重复字符,所以不能用排序等粗暴解法,那我们就- 建立一个 Map,
key表示字符,value是出现次数比如t = ABCC=>Map { 'A' => 1, 'B' => 1, 'C' => 2 } - 用 curLessKeysLen 来表示 当前剩余还需要匹配的字符种类
- 那么满足的条件就是
curLessKeysLen === 0表示全部都匹配了,也就是needMap = { 'A' => 0, 'B' => 0, 'C' => 0 }
- 建立一个 Map,
- 滑动右指针扩大窗口
(right++),直到满足条件,比较记录下最优解。 - 此时,我们停止增加right,转而不断增加
left指针缩小窗口[left, right],直到窗口中的字符串不再符合要求curLessKeysLen > 0。同时,每次增加left,我们都要更新一轮结果。 - 重复第 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,我看到就通过,暗号对不上不加哈,加了之后我会尽我所能帮你,但是注意提问方式,建议先看这篇文章:提问的智慧