滑动窗口,顾名思义就是一个在数组或者字符串中连续的一个子数组,或者沿着轨道开动”列车“,而定长滑动窗口,就是长度固定的列车,在数组中可以前后移动(移除/添加)

我们以LeetCode的一道例题来看。(感谢灵茶山艾府的Leetcode题单!本系列文章只是用自己的话把算法解释给自己看(?)希望自己日后Review的时候能看懂23333。)

给你字符串 s 和整数 k

请返回字符串 s 中长度为 k 的单个子字符串中可能包含的最大元音字母数。

英文中的 元音字母 为(a, e, i, o, u)。

示例 1:

输入:s = "abciiidef", k = 3
输出:3
解释:子字符串 "iii" 包含 3 个元音字母。

示例 2:

输入:s = "aeiou", k = 2
输出:2
解释:任意长度为 2 的子字符串都包含 2 个元音字母。

示例 3:

输入:s = "leetcode", k = 3
输出:2
解释:"lee"、"eet" 和 "ode" 都包含 2 个元音字母。

示例 4:

输入:s = "rhythms", k = 4
输出:0
解释:字符串 s 中不含任何元音字母。

示例 5:

输入:s = "tryhard", k = 4
输出:1

提示:

  • 1 <= s.length <= 10^5
  • s 由小写英文字母组成
  • 1 <= k <= s.length

从题目中我们可以看出,长度为k的子字符串就是一个定长的滑动窗口!我们要找出这个滑动窗口内最多会同时出现几个元音字母。

我们可以先构造一个初始的滑动窗口,右端点(i)长度从1开始增长,如果添加的元素为元音则元音+1,同时用Math.max(a,b)函数去记录元音字母同时的最大值,当长度达到k时,即形成了定长窗口,列车再往前开,这个时候就要操作左端点(i-k+1),把尾巴给移除掉了,此时要判断移除的是否为元音,如果是,则元音要-1。

欸,为什么是i-k+1呢,我们来看下面几种情况:

[1,4) -> [1,2,3] -> 4-1 = 3

[1,4] -> [1,2,3,4] -> 4-1+1=4

(1,4) -> [2,3] -> 4-1-1=2

很明显,滑动窗口的意图是左右都闭合的情况,所以就是[left,i],在已知窗口长度为k的情况下,求得左端点i-k+1

这个模板按照 入->更新->出 的顺序,所以每一次循环结束的时候,滑动窗口都是等待前方新元素加入的临界状态。

class Solution {
    public int maxVowels(String s, int k) {
        char[] S = s.toCharArray(); 
        int ans = 0;
        int vowel = 0;
        for(int i = 0 ; i < S.length;i++){
            if(ans == k){
                return ans;
            }
            if(S[i] == 'a' || S[i] == 'e' || S[i] =='i' || S[i] == 'o' || S[i] == 'u'){
                vowel++;
            }
            int left = i-k+1;
            if(left<0){
                continue;
            }
            ans = Math.max(ans,vowel);
            char out = S[left];
            if (out == 'a' || out == 'e' || out == 'i' || out == 'o' || out == 'u') {
                vowel--;
            }
        }
        return ans;
    }
}

9.26练习更新:

子数组最大平均数 I,和例题发现有不一样!求的是平均数最大值,但是数中有负数,所以不能直接int result=0;,而是用int result=Integer.MIN_VALUE来确保result起始的时候是边界值!