太难了,高级的滑动窗口问题,直接看题解直接背
这题最标准、最正确、面试最喜欢的写法,就是:
-
need:记录 t 需要什么字符 -
window:记录当前窗口有什么字符 -
left/right:滑动窗口 -
valid:满足要求的字符种类数
这是 LeetCode 官方题解级别写法。
完整标准模板如下:
java
class Solution {
public String minWindow(String s, String t) {
if (s == null || t == null || s.length() < t.length()) {
return "";
}
int[] need = new int[128];
for (char c : t.toCharArray()) {
need[c]++;
}
//定义滑动窗口
int left = 0, right = 0;
int minLen = Integer.MAX_VALUE;
//结束满足条件
int needCount = t.length();
//最小字串起始位置, 结合minLen得到最终字符串
int start = 0;
//右指针不断向右
while (right < s.length()) {
//找到右边窗口进来的字母
char sCharAtRight = s.charAt(right);
//如果找到需要的字母
if (need[sCharAtRight] > 0) {
needCount--;
}
//所需字符减一,可以为负数,表示多余该字符
need[sCharAtRight]--;
right++;
//所有字符都已经找到,触发结算机制
while (needCount == 0) {
int temp = right - left;
if (minLen > temp) {
minLen = temp;
start = left;
}
char sCharAtLeft = s.charAt(left);
//所需字符加一
need[sCharAtLeft]++;
if (need[sCharAtLeft] > 0) {
needCount++;
}
left++;
}
}
return minLen ==Integer.MAX_VALUE ? "" : s.substring(start, start + minLen);
}
}
这题真正的精髓只有一句:
右边扩张找可行解,左边收缩找最优解
也就是:
right 负责:
让窗口合法
left 负责:
让窗口最小
建议你重点记住这个模板:
while (right < s.length()) {
// 1. 扩大窗口
char c = s.charAt(right);
right++;
// 2. 更新窗口数据
// 3. 判断窗口是否合法
while (窗口合法) {
// 更新答案
// 4. 缩小窗口
char d = s.charAt(left);
left++;
// 5. 更新窗口数据
}
}
这个是:
滑动窗口万能模板
后面很多题都是它变形:
-
剑指 Offer 48 最长不含重复字符的子字符串
-
剑指 Offer 14 字符串中的变位词
-
LeetCode 438 找到字符串中所有字母异位词
-
LeetCode 567 字符串的排列
本质都一样。