滑动窗口算法多用于处理数组(Array), 字符串(String)或者链表(LinkedList)中关于子字符串(Substrings), 子数组(Subarrays, Sublists)等连续问题。该算法可以将多重嵌套的循环转化为单循环,从而降低时间复杂度(O(n))。滑动窗口是同向双指针的一个类型。
注意上述的滑动窗口示意图是固定大小,而现实中窗口大小也可以是不固定的。
下面给出滑动窗口算法的一个模板,来源于leetcode并做了一些理解上的修改。注意模板给出的是一个非固定大小窗口的模板,关键步骤都已经注释了。
public static List<Integer> slidingWindowTemplate(String s, String t) {
// 初始化返回结果的集合
List<Integer> result = new LinkedList<>();
if (t.length() > s.length()) return result;
//创建一个hashmap去保存目标字符串的子字符
//(K, V) = (字符, 字符出现的频率)
Map<Character, Integer> tmap = new HashMap<>();
for (char c : t.toCharArray()) {
tmap.put(c, tmap.getOrDefault(c, 0) + 1);
}
//维持一个counter去检查是否已经匹配了目标字符串.
int counter = tmap.size(); //must be the tmap size, NOT the string size because the char may be duplicate.
//Two Pointers: left - left pointer of the window; right - right pointer of the window
int left = 0, right = 0;
//
// //the length of the substring which match the target string.
// int len = Integer.MAX_VALUE;
// 查找直到左侧指针已经移动到最后一个字符
while (right < s.length()) {
char c = s.charAt(right);//get a character
if (tmap.containsKey(c)) {
tmap.put(c, tmap.get(c) - 1);// 找到一个字符就 - 1
if (tmap.get(c) == 0) counter--; // 该字符减小到符合要求,整个counter