滑动窗口技巧作为双指针技巧之一, 通常用于解决子字符串的匹配问题
解决这类问题的通用框架如下:
/*
通用框架:
创建两个HashMap, 一个用来存储满足条件所需的key的个数(need), 另一个用来做window
遍历存need里面
创建窗口的左右指针和计数器(记录窗口中key的个数是否满足条件)
开始右指针移动,扩大窗口并增加key(窗口内一系列更新)
在while里判断左指针是否要收缩,然后进行窗口内更新(减少map)
*/
按照这个框架来解决第一个问题:
class Solution {
public String minWindow(String s, String t) {
// 用一个哈希表needs计算需要的字符及出现次数,另一个window作为滑动窗口记录
int start = 0;
int minLength = Integer.MAX_VALUE;
Map<Character, Integer> needs = new HashMap<>();
Map<Character, Integer> window = new HashMap<>();
// 填needs
for(int i = 0; i < t.length(); i++){
needs.put(t.charAt(i), needs.getOrDefault(t.charAt(i), 0) + 1);
}
int left = 0;
int right = 0;
int match = 0; // 记录window中有多少个字符符合要求
while(right < s.length()){
char c1 = s.charAt(right);
//如果needs有对应的键,就把这个放进window
if(needs.containsKey(c1)){
window.put(c1, window.getOrDefault(c1, 0) + 1);
if(needs.get(c1).equals(window.get(c1))){
match++;
}
}
right++;
//window中的字符符合要求,调整left,更新结果
while(match == needs.size()){
if(right - left < minLength){
start = left;
minLength = right - left;
}
char c2 = s.charAt(left);
left++;
if(needs.containsKey(c2)){
if(window.get(c2).equals(needs.get(c2)))
match--;
window.put(c2, window.getOrDefault(c2, 0) - 1);
}
}
}
return minLength == Integer.MAX_VALUE? "":s.substring(start, start+minLength);
}
}
与之相类似的题目还有
代码如下
class Solution {
public List<Integer> findAnagrams(String s, String p) {
// 创建hashmap记录need和window
Map<Character, Integer> need = new HashMap<>();
Map<Character, Integer> window = new HashMap<>();
//记录索引
List<Integer> res = new ArrayList<>();
// valid 记录满足条件的字符个数
int valid = 0;
int right = 0;
int left = 0;
//将p放到need里面
for(int i = 0; i < p.length(); i++){
need.put(p.charAt(i), need.getOrDefault(p.charAt(i), 0) + 1);
}
//扩大窗口,记录char并移动right
while(right < s.length()){
char c1 = s.charAt(right);
right++;
//如果存在need中的char,添加到window
if(need.containsKey(c1)){
window.put(c1, window.getOrDefault(c1, 0) + 1);
if(need.get(c1).equals(window.get(c1))){
valid++;
}
}
//判断left是否++
while(right - left >= p.length()){
if(valid == need.size()){
res.add(left);
}
char c2 = s.charAt(left);
left++;
if(need.containsKey(c2))
if(need.get(c2).equals(window.get(c2)))
valid--;
window.put(c2, window.getOrDefault(c2, 0) - 1);
}
}
return res;
}
}
其他类似的题目可以参考东哥的,不过实现方式都是C++
https://github.com/labuladong/fucking-algorithm/blob/master/算法思维系列/滑动窗口技巧进阶.md