这道题我一开始使用了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;}
}