这道题我一开始使用了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[] aaa = new int[128];
for (int i = 0; i < aaa.length; i++) {
aaa[i]=-1;
}
int max = 0;
int left = 0;
int right = 0;
char[] chars = s.toCharArray();
int length = s.length();
while (right<length){
//进行比较如果left指向的位置晚于这个字符上一次出现的位置,就说明此时窗口有两个这个字符了,
//直接进行跳转,到上一次字符的后一个。
left = Math.max(left,aaa[chars[right]]+1);
//max重新赋值
max = Math.max(right-left+1,max);
aaa[chars[right]] = right;
//窗口右移
right++;
}
return max;
}
}