滑动窗口解题总结
滑动窗口解题总结
一、算法简介
滑动窗口是一种高级双指针技巧的算法框架,代码模板可以按照如下表示
int left = 0,right = 0; //1.初始化双指针,建立一个索引闭区间,也就是窗口
//2.定义求解目标的初始值
while(right < s.length()){
window.add(s[right]); //3.通过增加right指针不断地扩大窗口 (找到可行解)
//并同时更新求解的目标值
right++;
while(valid){ //4.判断当前窗口是否满足要求
window.remove(s[left]); //5.停止增加right指针,转而增加left指针,直至窗口中的数据不符合要求
// 并同时更新求解的目标值
left++; //6.继续循环
}
}
其中的window的数据类型一般为哈希表,当然在存储英文字母时也可以使用数组;代码的关键点如何判断
滑动窗口是有效的
二、典型例题
1.Leetcode 3
给定一个字符串,找出其中不含有重复字符的最长子串的长度
class Solution {
private Map<Character,Integer> window = new HashMap<>(); //定义存储元素出现次数的哈希表
public int lengthOfLongestSubstring(String s) {
if(s.length() == 0) return 0;
int left = 0,right = 0; //初始化左右指针
int maxLen = 0; //初始化最大长度
while(right < s.length()){
if(!window.containsKey(s.charAt(right))){ //判断当前元素是否已经存在
window.put(s.charAt(right),1); //不存在就存入哈希表
maxLen = Math.max(maxLen,right - left + 1); //更新最大长度
right++; //向右扩大窗口
}else{
while(window.containsKey(s.charAt(right))){ //如果已经包含那就从左边删除元素直至不包含
window.remove(s.charAt(left));
left++; //从左边缩小窗口
}
}
}
return maxLen;
}
}
题目的框架都是相似的,不同的是如何判断当前窗口的有效性
2.Leetcode 438
给定一个字符串 s 和一个非空字符串 p,找到 s 中所有是 p 的字母异位词的子串,子串起始索引
class Solution {
private List<Integer> res = new ArrayList<>(); //存储结果的列表
private Map<Character,Integer> need = new HashMap<>(); //子串哈希表
private Map<Character,Integer> window = new HashMap<>(); //滑动窗口哈希表
public List<Integer> findAnagrams(String s, String p) {
if(s.length() == 0) return res;
int left = 0,right = 0; //初始化左右指针
int match = 0; //记录字符串匹配个数
for(char c : p.toCharArray()){ //构造子串哈希表
need.put(c,need.getOrDefault(c,0) + 1);
}
while(right < s.length()){
char c1 = s.charAt(right);
if(need.containsKey(c1)){
window.put(c1,window.getOrDefault(c1,0) + 1);
if(window.get(c1).equals(need.get(c1))) match++; //更新匹配的字符数目
//整型对象的比较不能用“==”
}
right++;
while(match == need.size()){ //判断当前窗口是否满足要求
if(right - left == p.length()){ //发现字母异位词
res.add(left); //添加到返回结果中
}
char c2 = s.charAt(left);
if(need.containsKey(c2)){ //从左边删除的元素在子串中出现
window.put(c2,window.get(c2)-1); //在窗口哈希表中删除
if(window.get(c2) < need.get(c2)) match--; //减少匹配的字符数
}
left++; //缩小滑动窗口
}
}
return res;
}
}
框架是一致的,不同的就是对窗口值有效性的判断