携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第17天,点击查看活动详情
什么情况下使用滑动窗口?
- 当有确定大小的子序列时,可以通过滑动窗口将嵌套的循环问题,转成单次循环,降低时间复杂度
- TCP中采用滑动窗口来进行传输控制,滑动窗口的大小意味着接收方还有多大的缓冲区可以用于接收数据
例题
存在重复元素 II
- 滑动窗口大小为K,创建一个set,大于K时删除左边第一个元素,这样不断移动,直到数组遍历完成
var containsNearbyDuplicate = function(nums, k) {
let set = new Set()
for (let i = 0; i < nums.length; i++) {
if (set.has(nums[i])) {
return true
}
set.add(nums[i])
set.size > k && set.delete(nums[i-k])
}
return false
};
找到字符串中所有字母异位词
- 我们可以设置两个指针记录滑动窗口,通过右指针向右移,扩充滑动窗口,当窗口大小大于p的长度时,左指针右移,缩减滑动窗口,如此不断向右滑动
- 设置pMap,用来存储p字符串中每个字符出现的个数,设置sMap,用来记录滑动窗口中每个字符出现的个数
- 设置count,用来记录滑动窗口中和p字符串中相同个数的字符种类
- 当出界时,如果相同个数的字符种类相同且长度相同,则记录一个异位词结果
var findAnagrams = function(s, p) {
if (!s.length || !p.length) {
return []
}
let pMap = {}
for (let i = 0; i < p.length; i++) {
let a = p[i]
pMap[a] = (pMap[a] || 0) + 1
}
let l = r = 0
let res = []
let sMap = {}
let count = 0
while (r < s.length) {
let b = s[r]
r++
if (pMap[b]) {
sMap[b] = (sMap[b] || 0) + 1
if (sMap[b] === pMap[b]) {
count++
}
}
if (r - l >= p.length) {
if (count === Object.keys(pMap).length) {
res.push(l)
}
let c = s[l]
l++
if (pMap[c]) {
if (sMap[c] === pMap[c]) {
count--
}
sMap[c]--
}
}
}
return res
};
时间复杂度为O(n),即为s的长度,空间复杂度为O(K),即为pMap的大小