个人博客:The Blog Of WaiterXiaoYY 欢迎来互相交流学习。
Sliding Window
Sliding Window 也就是”滑动窗口“,通常用来求解一个字符串的字串。
滑动窗口一般配合哈希表来使用,
哈希表用来记录字符出现的次数,然后根据我们的需求的来处理这个字符。
为什么叫滑动窗口?
因为做题的方法感觉是一个一定长度的格子窗口,
比如像这样:
每个格子对应一个字符,然后设置判断条件,整个窗口一起移动,寻找我们所需要的东西。
但往往窗口的长度并不是固定的,我们在题目中慢慢体会。
无重复字符的最长字串
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
题目不难理解,一个字符串s,在s中找出一个子字符串,在字符串中没有重复的字符,返回符合情况的最长子字符串的长度。
看到求子字符串,就应该想到滑动窗口。
那这道题,怎么利用滑动窗口来做呢?
以事例一为例说明:
我们需要两个指针,left 和 right ,表示窗口的左边界和右边界,
因为我们是去寻找最长的字串,所以我们的窗口应该从最小开始,慢慢变大,在窗口里面的就是我们要找的子串,
注意,也就是说,一旦纳入我们的窗口,就是符合条件的字串,如果字符重复就不能纳入进来,
我们需要利用哈希表来记录窗口里面字符出现的次数,
一开始,窗口的长度为0,左边界右边界都指向第一个数,
窗口内的字符是a,这时候哈希表 window 存入a出现的次数,
此时,我们纳入了第二个字符a,那这个窗口是不符合要求的,所以前面那个窗口就是我们要找的最大的窗口,
这时候我们需要记录前一个窗口大小,也就是子字符串的长度,
res = right - left,此时 res = 3,
但是此时的结果还不是最终的结果,窗口的右边界right,还没有达到字符串s的最右边,
说明字符串s还没有被遍历完,那就可能还有更长的情况,
但现在我们遇到一个问题,此时窗口的右边界不能移动了,因为重复的字符纳入到我们的窗口里面,我们的这个窗口不符合题目要求了,如果再移动右边界没有任何意义,
这时候我们应该移动左边界了,
左边界的应该移动到重复的那个字符串右边的第一个字符,这样我们的窗口才有继续扩大下去的条件,
此时,右边界才有移动下去的条件,那只需要再重复我们上面的操作就行,每次都记录下res,然后取最大的res返回即可。
如果明白了上面,我们就可以先来写写我们的伪代码:
String s;// 我们的字符串
此时left 和 right 都在最开始的地方
while(right < s.length()) {
将右边界对应的字符存入到哈希表
右边界增加 1
如果此时遇到重复字符
则进入移动左边界的循环
while(window.get(i) > 1) {
取出左边界的字符
将左边界的字符从window中删去
将左边界++
直到将窗口内所有字符的个数都是 1
}
记录此时的窗口长度
更新res
return res;
}
如果明白了这些,我们的代码就可以很容易写出来,
有一点还需要注意的是,窗口长度是 right - left,而不是 right - left +1,
因为在每次记录字符的数量的同时,窗口右边界都指向了此时下一位,在我们将重复字符纳入窗口的那一刻,我们就记录下了字串的长度了。
代码
class Solution {
public int lengthOfLongestSubstring(String s) {
//建立哈希表window记录窗口中字符的数量
HashMap<Character, Integer> window = new HashMap<>();
//窗口的左右边界
int left = 0;
int right = 0;
//记录我们的结果
int res = 0;
//右边界还没有到字符串s的右边界,说明res的结果还不是最终结果
while(right < s.length()) {
//取出右边界的字符,将其记录在window中
char c1 = s.charAt(right);
window.put(c1, window.getOrDefault(c1,0) + 1);
//记录字符的同时右边界也增加l
right++;
//遇到重复的字符,则开始移动左边界
while(window.get(c1) > 1) {
char c2 = s.charAt(left);
int temp = window.get(c2);
temp--;
window.put(c2,temp);
left++;
}
//取出窗口的最大值java
res = Math.max(res, right - left);
}
return res;
}
}