这道题我一开始使用了Set加类似滑动窗口的方法,最后解得出来,但效率不尽人意,最后经过几次修改,最终用到是滑动窗口+指针+数组的方式讲效果达到最优,超过近99%的代码。
1、第一版
class Solution {
public int lengthOfLongestSubstring(String s) {
//先判断特殊情况
if (s.equals("")){
return 0;
}
//x[i]记录的是以下标为i字符为最后一个字符时不重复字符字串的长度
Integer [] x = new Integer[s.length()];
char[] chars = s.toCharArray();
for (int i = 0; i < s.length(); i++) {
int num = 0;
//记录以下标为i字符为最后一个字符的字串。
HashSet <Character> aa = new HashSet<>();
for (int j = i; j >=0; j--) {
aa.add(chars[j]);
//当子串里有字符被去重了,就说明不能再往下了。
if (aa.toArray().length!=++num){
num--;
break;
}
}
x[i]=num;
}
int max = Integer.MIN_VALUE;
for (int i = 0; i < x.length; i++) {
if (max<x[i]){
max = x[i];
}
}
return max;
}
}
2、第二版
使用了普通的滑动窗口的思路。
class Solution {
public int lengthOfLongestSubstring(String s) {
//维护者left和right指针中存在的字符
HashSet<Character> hashSet = new HashSet<>();
int left = 0;
int right = 0;
int max = 0;//最长长度
while(right<s.length()){
//如果此时right指向的字符已经在left和right指针中间了
//就将left向右移,直至此时right指向的字符不存在于hashSet当中了
if (hashSet.contains(s.charAt(right))){
hashSet.remove(s.charAt(left++));
//如果不存在于hashSet当中就继续right又移,并将其添加到集合当中
//更新max;
}else {
hashSet.add(s.charAt(right++));
max = Math.max(max,right-left);
}
}
return max;
}
}
3、第三版
此时不需要维护那个set字串了,直接维护一个数组,记录这上一次这个字符出现的下标,如果出现重复字符,直接将left跳转到这个上一次出现字符的后一个,直接一步到位,不需要其一步步向右移动了。
class Solution {
public int lengthOfLongestSubstring(String s) {
//维护一个数组,记录这上一次这个字符出现的下标
int[] last = new int[128];
for(int i = 0; i < 128; i++) {
last[i] = -1;
}
int n = s.length();
int max = 0;
int left = 0;
for(int i = 0; i < n; i++) {
int index = s.charAt(i);
//直接跳转到上次的出现的下标
left = Math.max(left, last[index] + 1);
max = Math.max(max, i - left + 1);
//更新最新出现的字符的下标
last[index] = i;
}
return max;
}
}