对应力扣第3题:右指针前移,左指针也动态移动
1. 滑动窗口的 3 个 "核心装备"
实现滑动窗口只需要 3 个关键变量,作用单一,记清楚就行:
- 左指针
left:窗口的左边界,初始值0(从字符串开头开始),控制窗口收缩; - 哈希集合
set:记录当前窗口内的所有字符,利用集合 "元素唯一" 的特性,快速判断新字符是否重复; - 最大长度
maxLen:记录遍历过程中,无重复字符窗口的最大宽度,初始值0。
2. 滑动窗口的 "核心规则"(唯一需要记的)
右指针right遍历字符串的每个字符(从0到s.length-1),每一步只做 3 件事,循环执行直到遍历结束:
- 判断重复 :如果当前字符
s[right]在集合中 (窗口内有重复),就把左指针指向的字符 从集合中删除,然后左指针left++(窗口左边界收缩),直到集合中没有s[right]; - 加入集合 :把当前字符
s[right]加入集合(窗口右边界扩张,包含新字符); - 更新最大长度 :计算当前窗口的宽度 (
right - left + 1),如果比maxLen大,就更新maxLen。
javascript
/**
* @param {string} s
* @return {number}
*/
var lengthOfLongestSubstring = function (s) {
let left = 0
let maxLen = 0
const set = new Set()
const n = s.length
for (let right = 0; right < n; right++) {
while (set.has(s[right])) {
set.delete(s[left])
left++
}
set.add(s[right])
maxLen = Math.max(maxLen, right - left + 1)
}
return maxLen
};
力扣438题
这个题目也是滑动窗口,但是窗口是固定大小的(等于p.length)
思路是开两个数组存26个字母各自在窗口中出现的次数,如果两个数组相等,那就是当前窗口是p的异位词。然后把开头的下标记录下来,窗口右移一个单位,同时左指针指的字母个数-1,右指针指到的+1
javascript
/**
* @param {string} s
* @param {string} p
* @return {number[]}
*/
var findAnagrams = function (s, p) {
const result = []
const sLen = s.length
const pLen = p.length
const aCode = 'a'.charCodeAt(0)
const pCount = new Array(26).fill(0)
const sCount = new Array(26).fill(0)
if (sLen < pLen) return result
for (const c of p) {
pCount[c.charCodeAt(0) - aCode]++
}
for (let i = 0; i < pLen; i++) {
sCount[s[i].charCodeAt(0) - aCode]++
}
if (arrEqual(pCount, sCount)) {
result.push(0)
}
for (let start = 1; start <= sLen - pLen; start++) {
const leftChar = s[start - 1]
sCount[leftChar.charCodeAt(0) - aCode]--
const rightChar = s[start + pLen - 1]
sCount[rightChar.charCodeAt(0)-aCode]++
if (arrEqual(pCount, sCount)) {
result.push(start)
}
}
function arrEqual(arr1, arr2) {
for (let i = 0; i < 26; i++) {
if (arr1[i] !== arr2[i]) return false
}
return true
}
return result
};