题目
分析
要找出一条不含重复字符的子串,首先要想到用Set集合来进行求解;
首先想到的是暴力遍历s的所有字符,以每个字符作为开始,依次往下寻找最长不包含重复字符的子串。以`abcabcbb`为例,首先是以a字符串开始遍历,找到一个不包含重复字符的子串(abc)abcbb,然后再从b开始,找出下一个不包含重复字符的子串a(bca)bcbb,然后一下ab(cab)cbb,以此类推找到所有的不包含重复字符子串。
上面可以求解出所有的不包含重复字符的子串,然后找出最大的子串长度就可以得出答案了,但是我们发现还有优化的地方。
如果用滑动窗口来维护一个不包含重复字符的子串,这样可以避免去找很多不必要的子串,比如`abcdc`,我们找出以第一个字符开始的不包含重复字符的子串为(abcd)c,遍历下一个就遇到了重复字符c,往后的a(bcd)c和ab(cd)c其实我们可以省略掉,因为这两个子串都会遇到相同的重复字符c,那么只要我们将重复字符c以及之前的字符都移除到窗口之外就可以了,这样我们第一次遇到重复字符c之后,下一个不包含重复字符的子串就是abc(dc)。
滑动窗口可以用队列来实现,也可以用双指针来维护,具体请看下面的代码实现。
代码实现
解法一:暴力求解
class Solution {
public int lengthOfLongestSubstring(String s) {
// 判空条件
if(s == null || s.length() == 0) return 0;
Set<Character> set = new HashSet<>();
char[] arr = s.toCharArray();
int ans = 0;
// 遍历以每一个字符作为开始
for(int i = 0; i < arr.length; i++){
// 遍历找出以此字符开始的最长无重复子串的长度
for(int j = i; j < arr.length; j++){
if(!set.contains(arr[j])){
// set集合不存在重复字符就将该字符加入set
set.add(arr[j]);
}else{
// set集合存在重复字符,记录当前最长的子串,并清空set
ans = Math.max(ans, set.size());
set.clear();
break;
}
}
}
// 最后一轮的统计结果
ans = Math.max(ans, set.size());
return ans;
}
}
解法二:滑动窗口:队列实现
class Solution {
public int lengthOfLongestSubstring(String s) {
// 判空条件
if(s == null || s.length() == 0) return 0;
Set<Character> set = new HashSet<>();
char[] arr = s.toCharArray();
int ans = 0;
// 用队列来做滑动窗口
Queue<Character> queue = new LinkedList<>();
for(int i = 0; i < arr.length; i++){
if(!set.contains(arr[i])){
// set中不存在的字符加入到滑动窗口
queue.offer(arr[i]);
// 同时加入到set中
set.add(arr[i]);
// 有新字符加入,更新结果
ans = Math.max(queue.size(), ans);
}else{
// set中若已存在相同的字符,将队列中的相同字符以及之前字符移除队列
char c = queue.poll();
while(c != arr[i]){
// 若没遇到重复那个字符,需要把删除的字符也移除set集合
set.remove(c);
c = queue.poll();
}
queue.offer(c);
}
}
return ans;
}
}
解法三:滑动窗口:双指针实现
class Solution {
public int lengthOfLongestSubstring(String s) {
// 判空条件
if(s == null || s.length() == 0) return 0;
Set<Character> set = new HashSet<>();
char[] arr = s.toCharArray();
int ans = 0;
// 用双指针来标记滑动窗口的范围
int i = 0, j = 0;
while(i < arr.length && j < arr.length){
if(!set.contains(arr[j])){
set.add(arr[j]);
ans = Math.max(ans, j - i + 1);
}else{
while(arr[i] != arr[j]){
set.remove(arr[i++]);
}
i++;
}
j++;
}
return ans;
}
}