滑动窗口的核心就是,右指针给窗口扩容,直至抵达扩容限制条件或抵达边界;左指针则是给窗口缩容,以释放限制条件的约束,保证窗口继续向边界移动。
需求讲解
给定一个字符串 str ,请找出其中不含有重复字符的最长子串的长度。
public static int lengthOfLongestSubstring(String str) {
// 记录窗口内字符
Set<Character> set = new HashSet<>();
int max = 0; // 最长不重复字符子串的长度
int left = 0, right = 0; // 滑动窗口的左右边界
while (right < str.length()) {
char c = str.charAt(right);
// 如果字符在窗口内出现过,则滑动左边界
while (set.contains(c)) {
set.remove(str.charAt(left));
left++;
}
// 将字符加入窗口
set.add(c);
// 更新最大长度
max = Math.max(max, right - left + 1);
// 右边界右移
right++;
}
return max;
}
此算法通常应用此类场景:在大区间,寻找(满足某种特征的)小区间结果。比如:
数组中的最大/最小子序列问题
例如,“最大连续子数组和”,“最小覆盖子串”等。这些问题通常需要找出数组或字符串中的一段连续子区间,使其满足某种条件(如和最大或最小,或者包含所有指定字符等)。
计数类问题
例如,“和为K的子数组个数”,“所有字母异位词”等。这类问题需要统计满足特定条件的子数组或子字符串的数量。
字符串匹配问题
例如,“KMP算法”,“Boyer-Moore算法”等。这类问题需要在字符串中找到指定模式的所有出现位置。
其他
滑动窗口算法还可以用于解决一些其他问题,例如:
- 寻找最长公共子串
- 寻找最长上升子序列
- 寻找最长回文子串
- 计算滑动平均值
滑动窗口算法的优点在于,它可以将这些看似复杂的问题转化为线性复杂度,大大提高了算法的运行效率。
以下是一些具体的应用案例:
-
在网络协议中,滑动窗口算法可以用于流量控制和拥塞控制。
-
在数据库中,滑动窗口算法可以用于查询优化。
-
在机器学习中,滑动窗口算法可以用于特征提取。