这里摘抄《labuladong的算法小抄》中的一首小诗(东哥大才):
滑动窗口防滑记
链表子串数组题,用双指针别犹豫。双指针家三兄弟,各个都是万人迷。
快慢指针最神奇,链表操作无压力。归并排序找中点,链表成环搞判定。
左右指针最常见,左右两端相向行。反转数组要靠它,二分搜索是弟弟。
滑动窗口最困难,子串问题全靠它。左右指针滑窗口,一前一后齐头进。
labuladong稳若”狗“,一套框架不翻车。一路漂移带闪电,算法变成默写题。
滑动窗口算法技巧的思路非常简单,就是维护一个窗口,不断滑动,然后更新答案。该算法的大致逻辑如下:
int left = 0, right = 0;
while (right < s.size()) {
// 增大窗口
window.add(s[right]);
right++;
while (window needs shrink) {
// 缩小窗口
window.remove(s[left]);
left++;
}
}
这个算法的时间复杂度是O(N),比字符串暴力算法要高效得多。下面是东哥的一套滑动窗口算法的代码框架,连在哪里做输出 debug 都写好了,以后遇到相关的问题,就默写出来如下框架然后修改两个地方就行,还不会出 bug:
package SlidingWindow;import java.util.HashMap;
import java.util.Map;// 算法模板—滑动窗口
public class AlgorithmTemplate {public void slidingWindow(String s, String t) {Map<Character, Integer> need = new HashMap<>();Map<Character, Integer> window = new HashMap<>();for (int i = 0; i < t.length(); i++) {char key = t.charAt(i);need.put(key, need.getOrDefault(key, 0) + 1);}int left = 0, right = 0, valid = 0;while (right < s.length()) {// c 是将要移入窗口的字符char c = s.charAt(right);// 右移窗口right++;// 进行窗口内数据的一系列更新System.out.println("进行窗口内数据的一系列更新");/*** debug 输出的位置***/System.out.println("window:(" + left + ", " + right + ")");/*********************/// 判断左侧窗口是否要收缩while (true) { // window need shrink —窗口需要收缩// d 是将要移出窗口的字符char d = s.charAt(left);// 左移窗口left++;// 进行窗口内数据的一系列更新System.out.println("进行窗口内数据的一系列更新");}}}
}
其中两处 sout 表示更新窗口数据的地方,直接往里面填具体逻辑就行了。而且,这两处操作分别是右移和左移窗口更新操作,它们的操作是完全对称的。稍后,我会用4道力扣原题来套这个框架。