【滑动窗口】
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
链接:
题目:
思路:
代码:
/**
* @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
链接:
题目:
思路:
跟上一题一样,这里就是去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
链接:
题目:
思路:
在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
链接:
题目:
思路:
这题跟之前的稍有不同,但反而更简单了
只需定义一个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的语法上
继续加油吧,朋友们!