算法讲解——滑动窗口
·
目录
一、什么是滑动窗口?
滑动窗口是一种用于处理数组/字符串子区间问题的高效算法技巧,通过维护一个动态的窗口(通常是连续的区间),在遍历数据时调整窗口的左右边界,避免重复计算,从而将时间复杂度优化至 O(n)。
核心思想:
-
窗口由左右指针(
left,right)定义,初始时均指向起点。 -
right向右扩展窗口,满足条件时停止。 -
left向右收缩窗口,直到不满足条件。 -
在窗口滑动过程中记录所需结果。
二、滑动窗口的适用场景
-
子串/子数组问题:如“最小覆盖子串”、“最长无重复子串”。
-
连续区间统计:如“和为K的子数组个数”、“平均值最大的子数组”。
-
固定窗口大小问题:如“大小为K的子数组的最大和”。
关键特征:
数据为数组或字符串。
求解目标与连续子序列相关。
暴力解法通常为 O(n²),滑动窗口可优化至 O(n)。
三、滑动窗口的两种类型
(1) 可变窗口大小
-
窗口大小不固定,根据条件动态扩展或收缩。
例题1. 无重复字符的最长子串
链接:3. 无重复字符的最长子串 - 力扣(LeetCode)
给定一个字符串
s,请你找出其中不含有重复字符的 最长 子串 的长度。示例 1:
输入: s = "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是"abc",所以其长度为 3。示例 2:
输入: s = "bbbbb" 输出: 1 解释: 因为无重复字符的最长子串是"b",所以其长度为 1。提示:
0 <= s.length <= 5 * 104s由英文字母、数字、符号和空格组成
代码:
/**
* @param {string} s
* @return {number}
*/
var lengthOfLongestSubstring = function(s) {
let left = 0 , max = 0 , current = ''
if(s.length>=1){
max = 1
current = s[0]
}
for(let i = 1 ; i<s.length ; i++ ){
let index = current.indexOf(s[i])
if(index==-1){
current += s[i]
}else{
left = left + index + 1
current = s.slice(left,i+1)
}
max = max>=i-left+1?max:i-left+1
}
return max
};
解法二:
/**
* @param {string} s
* @return {number}
*/
var lengthOfLongestSubstring = function(s) {
if(s.length<=1) return s.length;
let map = new Map(), left = 0, right = 0, max = 1;
while(right < s.length) {
let item = map.has(s[right]) && map.get(s[right]);
if(item === false || item < left) {
max = max>(right-left+1)?max:right-left+1;
}else {
left = item+1;
}
map.set(s[right],right);
right++;
}
return max;
};
(2) 固定窗口大小
- 适用于窗口大小固定的问题(如子数组最大平均值)。
例题1. 找到字符串中所有字母异位词
链接:438. 找到字符串中所有字母异位词 - 力扣(LeetCode)
给定两个字符串
s和p,找到s中所有p的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。示例 1:
输入: s = "cbaebabacd", p = "abc" 输出: [0,6] 解释: 起始索引等于 0 的子串是 "cba", 它是 "abc" 的异位词。 起始索引等于 6 的子串是 "bac", 它是 "abc" 的异位词。示例 2:
输入: s = "abab", p = "ab" 输出: [0,1,2] 解释: 起始索引等于 0 的子串是 "ab", 它是 "ab" 的异位词。 起始索引等于 1 的子串是 "ba", 它是 "ab" 的异位词。 起始索引等于 2 的子串是 "ab", 它是 "ab" 的异位词。提示:
1 <= s.length, p.length <= 3 * 104s和p仅包含小写字母
代码:
/**
* @param {string} s
* @param {string} p
* @return {number[]}
*/
var findAnagrams = function(s, p) {
let len = p.length , current = 0 , arr = []
for(let i = 0 ; i<s.length ; i++ ){
current = p.indexOf(s[i])!=-1?current+1:0
if(current==len){
let t = 0
for(let j = 0 ; j<len ; j++ ){
t ^= p[j].charCodeAt(0) ^ s[i-j].charCodeAt(0)
}
if(t==0){
arr.push(i-len+1)
}
current--
}
}
return arr
};更多推荐
所有评论(0)