一、题目描述
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
示例 2:
输入: “bbbbb”
输出: 1
解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。
示例 3:
输入: “bbbbb”
输出: 1
解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。
二、解法
可以有两种思路:
1、暴力法:使用一个嵌套循环挨个匹配,时间复杂度是 O(n * n),空间复杂度是 O(n)
2、滑动窗口法:当出现一个重复的时候,那么就不能使用前面已经记录的那个重复的字符了,要把它移动到它的后一位[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SldKCMXl-1584791396069)(C:\Users\dell\AppData\Roaming\Typora\typora-user-images\image-20200319230634286.png)]
如果是字符 c 出现了重复,我们把指针移到 a 的下一位,那么这个子串一定还会有重复,一直到第一个 c 的下一位才可能消除重复。
提醒自己:滑动窗口不一定要一次就把指针移动到指定的位置,可以一下一下挪动!!!
2.1 暴力法
class Solution {
public int lengthOfLongestSubstring(String s) {
int[] char_num; //保存字符出现的次数
int max = 0, temp = 0;
for(int i = 0; i < s.length(); i++) {
temp = 0;
char_num = new int[128]; //ASCLL 的字符集有 128 种
for(int j = i; j < s.length(); j++) {
int index = s.charAt(j);
if(char_num[index] == 0){
char_num[index]++;
temp++;
max = (temp > max) ? temp : max;
} else break;
}
}
return max;
}
}
//官方已经说明暴力解法会超时,但他们是使用 hashset 来求解的,我用数组并没有超时
2.2滑动窗口
Ⅰ、使用 set
class Solution {
public int lengthOfLongestSubstring(String s) {
int max = 0, temp = 0, i = 0, j = 0;
int length = s.length();
Set<Character> set = new HashSet<>(); //滑动窗口的 set 解法
//用窗口来进行优化
while(i < length && j < length) {
//窗口是一个 [start, end],则 j 是 end,i 是start
if(!set.contains(s.charAt(j))) {
set.add(s.charAt(j));
j++;
max = (j - i > max) ? j - i : max;
} else { //移动 start,是一步一步移动的!
set.remove(s.charAt(i));
i++;
}
}
return max;
}
}
Ⅱ、使用数组(桶)
class Solution {
public int lengthOfLongestSubstring(String s) {
int[] char_num = new int[128];
int length = s.length();
int i =0, j = 0, max = 0;
while(i < length && j < length) {
if(char_num[s.charAt(j)] == 0) { //j 指针指向的字符在数组中如果表示为 0
char_num[s.charAt(j)]++;
j++;
max = (j - i > max) ? j - i : max;
} else {
char_num[s.charAt(i)] = 0; //把 i 指针指向的字符在数组中清除掉
i++;
}
}
return max;
}
}