题目描述
解法
对于平时不刷题的朋友们来说,此题属于如果之前没见过,凭借面试中短短十几二十分钟想真的自己做出来,基本不可能的那种题目。
对于这种题目,我只有一个办法,搞懂思路,反复编码,直到形成肌肉记忆。
不要太高估自己,就算记得思路,面试的时候你想 bug free 一次过,都是有难度的。
下面,我来总结一下此题应该记住的关键点:
1.滑动窗口,一般来说,要一个字符串的连续子串满足啥条件的题目,都可以用该解法。基本思路是,用一头一尾俩指针框定一个范围,然后右指针不停右移,直到不满足条件为止,这时候左指针再跟着右移,直到又重新满足条件。
判断是否满足条件,利用的是一个窗口,也就是一个集合,它是左右指针之间的所有元素的集合;
2.在本题中,窗口保存的是左右指针的闭区间;
3.循环结束条件,是右指针到达字符串尾部,而且结束后要再判定一次窗口的长度;
3.移动右指针的时候 ,将当前右指针指向的字符加入窗口;
4.当右指针指向的字符在窗口中出现过时,开始移动左指针,直到左指针越过该字符在最近一次出现的位置,同时,要把左指针越过的字符统统从窗口移除。这个重复的字符就不用移除了,因为右指针越过它,本来是要把它加入窗口的,我们左指针不移除,右指针就不用再加入了,省了两个操作。
代码
class Solution {
public int lengthOfLongestSubstring(String s) {
// 参数校验
if(s == null){
return 0;
}
int len = s.length();
if(len <= 1){
return len;
}
// 初始化左右指针,其实模拟的是左右指针都指向第一个字符,
// 这时候右指针右移了一位
int l = 0;
int r = 1;
// 维护一个窗口,我们只判定窗口内的字符串是否不含重复字符
// 窗口里的内容是左右指针的闭区间
Set<Character> window = new HashSet<>();
// 先把第一个字符放进去,对第二个字符的处理,就在 while 循环中了
window.add(s.charAt(0));
int ans = 1; // 返回结果最小是1,很容易理解,单个字符就是长度为1的无重复字符的子串
// 右指针指向字符串最后一个字符时进行最后一次循环
while(r < len){
char temp = s.charAt(r);
if(!window.contains(temp)){
// 如果窗口中没有右指针指向的字符,将其加入窗口
window.add(temp);
} else {
// 如果碰到重复字符,那么立刻更新结果,看看当前窗口长度是不是比现有结果更大
ans = Math.max(ans, window.size());
// 将左指针移动到第一次出现重复字符的位置的后一位
while(s.charAt(l) != temp){
// 不在左右指针之间的字符,要清除出窗口
window.remove(s.charAt(l++));
}
// 将左指针指向重复字符的后一位,这里没将其移出窗口
// 因为我们也没有将右指针指向的下一个该字符放进窗口
// 所以这里不移出,就当移出又放进去了,没啥区别
l++;
}
r++;
}
// 万一右指针到头了,但是最后却没遇到重复字符,上面的 else 分支最后就没走到
// 因此单独判定一下
ans = Math.max(ans, window.size());
return ans;
}
}
现在,关于无重复字符的最长子串这道题,你已经知道得和我一样多了~
本专栏定期更新力扣算法讲解,希望以最容易记忆的方式帮你搞定面试算法题。