滑动窗口

这一题是leetcode的NO.3题,曾经被面到过,很经典的一道题

  • 注意:子串与子序列的区别

    • 子串:不可跳跃,如 pwwkewwke是子串

    • 子序列:可以跳跃,如pwwkewpkw是子序列

方法1:粗糙版滑动窗口

  • Set来维护重复字符与否的问题

    • 出现新的字符,很好,right指针向右扩展,并将当前字符加入Set中,更新最长无重复子串长度

    • 出现旧的字符,将左边界left指针向右收缩,移除当前的left指针指向的字符

    public int lengthOfLongestSubstring1st(String s) {
        int res = 0, left = 0, right = 0;
        int n = s.length();
        Set<Character> set = new HashSet<>();
        while (right < n && left < n) {
            if (!set.contains(s.charAt(right))) {
                set.add(s.charAt(right++));
                res = Math.max(res, right - left);
            } else {
                set.remove(s.charAt(left++));
            }
        }
        return res;
    }

方法2:优化版滑动窗口

  • 用一个hashmap来建立字符和其出现位置之间的映射。

  • 维护一个滑动窗口,窗口内的都是没有重复的字符,去尽可能的扩大窗口的大小,窗口不停的向右滑动。

  • (1)如果当前遍历到的字符从未出现过,那么直接扩大右边界;

  • (2)如果当前遍历到的字符出现过,则缩小窗口(左边索引向右移动),然后继续观察当前遍历到的字符;

  • (3)重复(1)(2),直到左边索引无法再移动;

  • (4)维护一个结果res,每次用出现过的窗口大小来更新结果res,最后返回res获取结果。

    • 用一个mapper记录出现过并且没有被删除的字符

    • 用一个滑动窗口记录当前index开始的最大的不重复的字符序列

    • res去记录目前位置最大的长度,每次滑动窗口更新就去决定是否需要更新res

方法3:再优化版滑动窗口

  • 常用的表如下所示:

  • 准备一个helper数组,每次记录right指针的绝对位置,

  • 更新res,更新left(拿到其最大位置)

方法1:双端队列

方法2:双端队列

方法3:辅助数组+贪心

国际站看的的一个思路,很赞

如上图:

1.将源数组按k的大小分,最后一组不够k的话,维持现状

2.1.遍历数组,组装left_max,即从左开始,每个k组从左开始,取最大值

2.2.遍历数组,组装right_max,即从右开始,每个k组从右开始,取最大值

3.借助左右辅助数组拼装结果数组,Math.max(right_max[i], left_max[i + k - 1])

实现

上述贪心的证明:

思路来源国际站,很赞的一个证明

假设$a_0$,$a_1$,$a_2$ ... $a_n$的窗口宽度是$w$,目标是为了获取一个$d[]=int[n-w+1]$

将上面的数组从左边开始分,每个元素的形式:$i*w+j$,其中$i$是从左边开始数,窗口的$index$,$j$是在这个窗口下的偏移量,其中$0<=i<=n/w$, $0<=j<=w$

构建如下的结果:

$d[iw+j]=max(a[iw+j+x])$这里的$x$满足:$0<=x<=w$,因此,$i*w+j$实际上代表的是要计算的最大值

假设有如下的数组:

$left[iw+j]=left_max(a[iw+k])$​ 其中$0<=k<j$​

$right[iw+j]=right_max(a[iw+k])$ 其中$j<=k<=(i+1)*w-1$

数组$left[]$是从左到右的每个窗口最大值

数组$right[]$是从右到左的每个窗口的最大值

有如下的推导: $d[iw+j]=max(right[iw+j], left[(i+1)w+j-1])$ $d[iw+j]=max(right[iw+j], left[(iw+w+j-1])$ => $d[m] = max(right[m], left[m+w-1])$

结果数组$d[]$​的最后一个元素是:$d[n-w]=max(right[n-w], left[n-1])$​

159.最多有两个不同字符的最长子串

方法1:Map统计数量+滑动窗口

方法2:Map标记位置+滑动窗口

方法3:滑动窗口+指针

340.最多有K个不同字符的最长子串

方法1:Map统计数量+滑动窗口

方法2:Map标记位置+滑动窗口

方法1:递归

  • 拿掉边界的处理

方法1:滑动窗口

另外一种思路:

方法2:滑动窗口+统计

思路来自@lee215大佬,该解法可以参考424题

Follow up:返回所有符合条件的索引

Last updated