原理
滑动窗口 = 单调性 + “同向双指针”
(单调性规避了很多没有必要的枚举)
模板:
1、left = 0,right = 0;
2、根据题目要求进窗口
3、判断
出窗口
更新结果
【出窗口和更新结果两个步骤需分析题目确定,顺序不固定】
典型算法题
1、209. 长度最小的子数组 - 力扣(LeetCode)
class Solution {
public static int minSubArrayLen(int target, int[] nums) {
int left = 0;
int right = 0;
int sum = 0;
//这里min不能是-1,因为后面要求最小值,-1会干扰结果
int min = Integer.MAX_VALUE;
while (right < nums.length && left < nums.length) {
sum += nums[right];
while (sum >= target) {
// 满足结果,更新最小值
int len = right - left + 1;
min = Math.min(len, min);
sum = sum - nums[left++];
//left++;
}
right++;
}
return min == Integer.MAX_VALUE ? 0 : min;
}
}
循环可以使用for循环,也可以使用while循环,依据个人爱好定
2、3. 无重复字符的最长子串 - 力扣(LeetCode)
class Solution {
public int lengthOfLongestSubstring(String ss) {
//使用滑动窗口+哈希表
//如果哈希表能用数组代替尽量用数组代替,因为数组更快
//将字符串转变成字符数组
char[] s = ss.toCharArray();
int[] hash = new int[128];
int len = 0;
//有效字符:哈希表中字符的个数为1
for(int left = 0,right = 0;right < ss.length();right++){
//进窗口,让hash进入窗口,右边界
hash[s[right]]++;
//判断,窗口内出现重复字符
while(hash[s[right]] > 1){
//滑动窗口中已经有了该有效字符
//出窗口,从哈希表中删除该字符,左边界
//hash[s[right]]--;
hash[s[left++]]--;
}
//更新结果
len =Math.max(len,right-left+1);
}
return len;
}
}
3、438. 找到字符串中所有字母异位词 - 力扣(LeetCode)
class Solution {
public List<Integer> findAnagrams(String ss, String pp) {
//使用滑动窗口,right往前面走搜寻到有效字符,当有效字符超过三个就记录一下当前字符串的起始位置,
//left++,无效
List<Integer> ret = new ArrayList<>();
char[] s = ss.toCharArray();
char[] p = pp.toCharArray();
//统计p字符串中每个字符出现的个数
int[] hashP =new int[26];
for(char ch:p){
hashP[ch -'a']++;
}
//统计窗口中每个字符出现的个数
int[] hash2 = new int[26];
int lenP = pp.length();
for(int left = 0,right = 0,count = 0; right < s.length;right++){
char in = s[right];
//进窗口
hash2[in - 'a']++;
if(hash2[in -'a'] <= hashP[in - 'a']){
count++;//统计有效字符的个数
}
//判断
if(right -left +1 > lenP){
//出窗口
char out = s[left++];
//如果出的是有效字符,需要count--
if(hash2[out -'a']-- <= hashP[out - 'a']){
count--;
}
}
//更新结果
if(count == lenP)
ret.add(left);
}
return ret;
}
}
除此之外,还有力扣1004、1658、904、30、76都可以用滑动窗口解决,只要分析出它们具有单调性并且可以使用双指针就可以按照上面的模板进行代码的编写