【小f的刷题笔记】(JS)双指针 - 滑动窗口 四类典型问题(附JS模版和详细注释代码)LeetCode76 & LeetCode567 & LeetCode438 & LeetCode3

【滑动窗口】

JS模版

利用map对象建立滑动窗口,相关题目都可以通过套框架来解决

LeetCode76 最小覆盖子串
LeetCode567 字符串的排列
LeetCode438 找到字符串中所有字母异位词
LeetCode3 无重复字符的最长子串

var slidingWindow = function(s) {
    const window = new Map()
    let left = 0, right = 0
    while(rigth < s.length) {
        // 拿到right的对应字符,并自增扩大窗口
        let c = s[right]
        right++
        // 对窗口的更新操作
        …………
        
        // 判断左侧窗口是否需要收缩
        while(window needs shink condition) {
            // 拿到left对应的字符,是要被移出去的,故left还需自减
            let d = s[left]
            left++
            // 对窗口的更新操作
            …………
        }
    }
}

1 最小覆盖子串:

LeetCode76

链接:

76.最小覆盖子串

题目:

在这里插入图片描述

思路:

在这里插入图片描述

代码:
/**
 * @param {string} s
 * @param {string} t
 * @return {string}
 */
var minWindow = function(s, t) {
    // 先定义一个need来储存字符串t每个字符的个数,之后跟window进行比较
    const need = new Map()
    // 这里是先判断need中是否已有c,有的话在这个基础上加1,没有的话赋为1
    for(const c of t) {
      need.set(c, (need.get(c) ? (need.get(c)+1) : 1))              
    }

    const window = new Map()
    // valid表示有几个字符已经满足了need的需要
    let left = 0, right = 0, valid = 0
    // len先赋最大值,表示子串长度
    let start = 0, len = Number.MAX_VALUE
    while(right < s.length) {
        // 拿到right对应的字符,并right自增扩大窗口
        let c = s[right++]
        // 更新窗口,直到valid等于need的数量
        if(need.get(c)) {
            // 如果该字符也在need中存在,在window中的数量加1
            window.set(c, (window.get(c) ? (window.get(c)+1) : 1))
            // 如果window和need中该字符的数量是一样的,valid自增1
            if(window.get(c) === need.get(c)) valid++
        }

        // 当valid等于need的size就说明可以收缩了
        while(valid === need.size) {
            // start和left当然是不一样的,start和len都是等到出现了更优解才更新的
            if(right - left < len) {
                start = left
                len = right - left
            }
            // d 表示要移出去的字符,并left自增减小窗口
            let d = s[left++]
            // 如果要移出去的字符在need中存在,valid--,在window中的数量减1
            if(need.get(d)) {
                if(window.get(d) === need.get(d)) valid--
                window.set(d, window.get(d)-1)
            }
        }
    }
    return len === Number.MAX_VALUE ? "" : s.substr(start, len)
};

2 字符串的排列:

LeetCode567

链接:

567.字符串的排列

题目:

在这里插入图片描述

思路:

跟上一题一样,这里就是去s2中找,是否存在s1的不包含其他字符子串

代码:
/**
 * @param {string} s1
 * @param {string} s2
 * @return {boolean}
 */
var checkInclusion = function(s1, s2) {
    // 1 定义所有变量
    const need = new Map()
    const window = new Map()
    let left = 0, right = 0, valid = 0

    // 2 存s1到need
    for(const c of s1) {
        need.set(c, need.get(c) ? need.get(c)+1 : 1)
    }

    // 3 窗口
    while(right < s2.length) {
        let c = s2[right++]
        if(need.get(c)) {
            window.set(c, window.get(c) ? window.get(c)+1 : 1)
            if(window.get(c) === need.get(c)) valid++
        }

        while(right - left >= s1.length) {
            if(need.size === valid) return true
            let d = s2[left++]
            if(need.get(d)) {
                if(window.get(d) === need.get(d)) valid--
                window.set(d, window.get(d)-1)
            }
        }
    }
    return false
};

3 找到字符串中所有字母异位词:

LeetCode438

链接:

438.找到字符串中所有字母异位词

题目:

在这里插入图片描述

思路:

在s中找到p的所有排列,并返回索引

代码:
/**
 * @param {string} s
 * @param {string} p
 * @return {number[]}
 */
var findAnagrams = function(s, p) {
    const need = new Map()
    const window = new Map()
    const res = new Array()
    let left = 0, right = 0, valid = 0

    for(const c of p) {
        need.set(c, need.get(c) ? need.get(c)+1 : 1)
    }

    while(right < s.length) {
        let c = s[right++]
        if(need.get(c)) {
            window.set(c, window.get(c) ? window.get(c)+1 : 1)
            if(window.get(c) === need.get(c)) valid++
        }

        while(right - left >= p.length) {
            if(valid === need.size) {
                res.push(left)
            }
            let d = s[left++]
            if(need.get(d)) {
                if(window.get(d) === need.get(d)) valid--
                window.set(d, window.get(d)-1)
            }
        }
    }
    return res
};

4 无重复字符的最长子串:

LeetCode3

链接:

3.无重复字符的最长子串

题目:

在这里插入图片描述

思路:

这题跟之前的稍有不同,但反而更简单了
只需定义一个window来存储s中的字符,当某个字符的数量大于1时,说明出现了重复字符,这时候就记录长度,继续寻找

代码:
/**
 * @param {string} s
 * @return {number}
 */
var lengthOfLongestSubstring = function(s) {
    const window = new Map()
    let left = 0, right = 0, res = 0
    while(right < s.length) {
        let c = s[right++]
        window.set(c, window.get(c) ? window.get(c)+1 : 1)
        // 当值大于1时,就说明存在重复字符,不符合条件
        while(window.get(c) > 1) {
            let d = s[left++]
            window.set(d, window.get(d)-1)
        }
        res = Math.max(res, right - left)
    }
    return res
};

写在最后:
滑动窗口算是玩明白了
强推labuladong
用的就是大佬的模版转换成了js
花了好多时间在js的语法上
继续加油吧,朋友们!

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值