滑动窗口算法
- 框架
- 实例
- 76.最小覆盖子串
- 567.字符串的排列
- 438.找到字符串中所有字母的异位词
- 3.无重复字符的最长子串
框架
slideWindow (s, t) {
// 定义需要个数的对象、当前窗口对象
const need = {}
const window = {}
// 定义左右索引
let left = 0
let right = 0
// valid种类数
let valid = 0
// 找最小子串
let start = 0
let len = Infinity
// 结果数组: 多个异位词、最长子串长度
let res = []
<!--需要对象赋值-->
for (const i of t) {
need[i] = (need[i] || 0) + 1
}
<!--遍历子串s-->
while (right < s.length) {
<!--右索引移动-->
const r = s[right]
right++
<!--更新窗口:-->
// 当前字符串为需要,窗口对象属性值+1,加1后若当前属性个数与需要个数相等,种类数valid++
// 无重复子串窗口更新只需: 窗口数window[r]+1
if (need[r]) {
window[r] = (window[r] || 0) + 1
if (window[r] === need[r]) valid++
}
<!--收缩窗口-->
// 1、最小覆盖子串:当前种类数等于需要的种类数(结果长度!==需要长度)
// 2、字符串排列、异位词:当前范围大于等于需要的长度(结果长度===需要长度)
// 3、无重复子串:窗口属性个数window[r] > 1
while (valid === Object.keys(need).length) {
// while (right - left >= t.length)
// while (window[r] > 1)
const l = s[left]
<!--判断当前满足条件则处理结果-->
// 1、最小覆盖子串:如果当前范围小于上次算的子串长度,则更新最小覆盖子串开始索引和长度
if (right - left < len) {
start = left
len = right - left
}
// 2、字符串排列、异位词:如果种类数===需要对象属性长度,则产生结果
if (valid === Object.keys(need).length) {
return true
// 异位词: res.push(left)
}
// 3、无重复子串无需处理:再外部循环判断
<!--左索引移动-->
left++
<!--更新窗口-->
// 当前字符串需要,如果窗口数===需要数,种类--,下次则退出循环
// 窗口数--
// 1、2、3:最小覆盖子串、字符串排列、异位词
if (need[l]) {
if (window[l] === need[l]) valid--
window[l]--
}
// 4:无重复子串只需
window[l]--
}
// 无重复子串在收缩窗口后更新结果
res = Math.max(res, right - left)
}
<!--while循环后返回结果-->
return len === Infinity ? '' : s.substr(start, len)
return false
return res
}
实例
76.最小覆盖子串
const s = 'agblalbu'
const t = 'ab'
console.error(this.minCoverSubstring(s, t))
输出:agb
minCoverSubstring (s, t) {
// 定义需要字符串个数的对象、当前窗口需要字符串个数的对象
const need = {}
const window = {}
// 定义左右索引、当前种类数
let left = 0
let right = 0
let valid = 0
// 定义最小字符串的起始索引和长度
let start = 0
let len = Infinity
<!--需要对象赋值-->
for (const i of t) {
need[i] = (need[i] || 0) + 1
}
// 遍历子串
while (right < s.length) {
// 右索引右移
const r = s[right]
right++
// 如果当前字符串在需要列表中则当前窗口对应的字符串的个数加1
if (need[r]) {
// window[r]++
window[r] = (window[r] || 0) + 1
// 如果当前字符串需要的个数已全,则种类数加1
if (window[r] === need[r]) valid++
}
// 判断收缩窗口(当前种类数等于需要的种类数)
while (valid === Object.keys(need).length) {
// 更新最小覆盖子串
if (right - left < len) {
start = left
len = right - left
}
// 左索引右移
const l = s[left]
left++
// 如果当前字符串在需要的窗口,当前窗口的种类数-1,且如果当前字符的种类数和需要种类数,种类数-1,
// 一旦减1则不再满足条件,退出循环
if (need[l]) {
if (window[l] === need[l]) valid--
window[l]--
}
}
}
return len === Infinity ? '' : s.substr(start, len)
}
567.字符串的排列
const s1 = 'agbalapbu'
const t1 = 'ab'
console.error(this.stringRank(s, t))
输出:true
stringRank (s, t) {
// 定义需要字符串个数的对象、当前窗口需要字符串个数的对象、结果
const need = {}
const window = {}
// 定义左右索引、种类值
let left = 0
let right = 0
let valid = 0
// 需要对象赋值
for (const i of t) {
need[i] = (need[i] || 0) + 1
}
// 遍历s字符串
while (right < s.length) {
const r = s[right]
right++
// 右移右索引,如果当前字符串为需要的则更新当前窗口,更新后如果个数与需要相同,则种类数+1
if (need[r]) {
window[r] = (window[r] || 0) + 1
if (window[r] === need[r]) valid++
}
// 当当前范围大于等于t长度,则收缩窗口或判断结果
while (right - left >= t.length) {
// 如果种类数等于需要对象长度,则true,
// 否则如果当窗口数为种类数,则种类数减1、当前窗口数减1,继续缩小窗口
const l = s[left]
if (valid === Object.keys(need).length) {
return true
}
left++
if (need[l]) {
if (window[l] === need[l]) valid--
window[l]--
}
}
}
return false
}
438.找到字符串中所有字母的异位词
const s2 = 'cabhbacj'
const t2 = 'abc'
console.error(this.HeterotopicWords(s2, t2))
输出:[0, 4]
HeterotopicWords (s, t) {
// 定义需要、当前
const need = {}
const window = {}
const res = []
// 定义左右索引,种类数
let left = 0
let right = 0
let valid = 0
// 赋值
for (const i of t) {
need[i] = (need[i] || 0) + 1
}
// 遍历s
while (right < s.length) {
// right++
const r = s[right]
right++
// 如果当前值为需要,窗口window++,如果窗口window和需要need的个数相同,则种类++
if (need[r]) {
window[r] = (window[r] || 0) + 1
if (window[r] === need[r]) valid++
}
// 收缩窗口(注意>=)
while (right - left >= t.length) {
const l = s[left]
// 种类数valid为需要数则索引入数组
if (valid === Object.keys(need).length) {
res.push(left)
// res.push(s.substr(left, t.length))
}
left++
// 如果当前为需要,且如果窗口数=需要数,种类数--,窗口数--
if (need[l]) {
if (window[l] === need[l]) valid--
window[l]--
}
}
}
return res
},
3.无重复字符的最长子串
const s3 = 'pwwkew'
console.error(this.maxNoRepeatSubString(s3))
输出:3 (wke)
maxNoRepeatSubString(s) {
// 定义需要、当前窗口、左右索引、结果
const window = {}
let left = 0
let right = 0
let res = 0
// 遍历s
while (right < s.length) {
const r = s[right]
right++
// 窗口更新
window[r] = (window[r] || 0) + 1
// 收缩
while (window[r] > 1) {
const l = s[left]
left++
window[l]--
}
res = Math.max(res, right - left)
}
return res
}
```/