classSolution{publicintlengthOfLongestSubstring(String s){// 哈希集合,記錄每個字符是否出現(xiàn)過Set<Character> occ =newHashSet<Character>();int n = s.length();// 右指針,初始值為 -1,相當(dāng)于我們在字符串的左邊界的左側(cè),還沒有開始移動int rk =-1, ans =0;for(int i =0; i < n;++i){if(i !=0){// 左指針向右移動一格,移除一個字符
occ.remove(s.charAt(i -1));}while(rk +1< n &&!occ.contains(s.charAt(rk +1))){// 不斷地移動右指針
occ.add(s.charAt(rk +1));++rk;}// 第 i 到 rk 個字符是一個極長的無重復(fù)字符子串
ans =Math.max(ans, rk - i +1);}return ans;}}
執(zhí)行結(jié)果
執(zhí)行通過,執(zhí)行用時6ms,內(nèi)存消耗38.3 MB.
🌻Java方法二:遍歷
總體思路 遍歷字符串,每次以 i 值記錄,不回溯 i 值,用flag記錄遍歷過程找到的重復(fù)的字符的位置,。如果遇到重復(fù)字符,i-flag 即為子串長度,此時flag重新定位到子串中重復(fù)字符的位置,i 繼續(xù)往后遍歷,。這里length跟result記錄長度。我感覺代碼可以更簡潔一點的,但是好像寫懵了?
圖解
classSolution{publicintlengthOfLongestSubstring(String s){//a b c a b c d a d e//0 1 2 3 4 5 6 7 8 9int maxSize =0;//記錄ASCII 碼字符出現(xiàn)的位置,以字符作為下標int[] dict =newint[128];//為了方便理解,這里把數(shù)組內(nèi)容全部設(shè)為 -1,之后在記錄的時候就可以從 0 開始,方便理解Arrays.fill(dict,-1);//用于記錄重復(fù) ASCII 碼字符出現(xiàn)的位置的值int repeatValue =-1;// 當(dāng)前下標int i =0;int ASCII;while(i < s.length()){
ASCII = s.charAt(i);//如果當(dāng)前位置的值 > repeatValue,證明當(dāng)前位置已經(jīng)賦過一次值了,證明字符重復(fù)if(dict[ASCII]> repeatValue)//更新 repeatValue 為之前賦值的下標
repeatValue = dict[ASCII];//將當(dāng)前下標賦值到數(shù)組相應(yīng)位置
dict[ASCII]= i;//i - repeatValue(去除重復(fù)部分)// 比如 abcabcdade 中的三個 a 的計算 abca - a(3 - 0)=bca abcabcda - abca(7 - 3)=bcda
maxSize =Math.max(maxSize, i - repeatValue);//s.length() - repeatValue - 1 判斷剩下的數(shù)有沒有必要繼續(xù)循環(huán)//比如 abcabcdade 最后的 a(當(dāng) i = 7 repeatValue = 3) ,abcabcdade - abca(10-3-1) = bcdade 剩下最多有六位//比如 abcabcdade 最后的 d(當(dāng) i = 8 repeatValue = 6) ,abcabcdade - abcabcd(10-6-1) = ade 剩下最多也是三位if(maxSize >= s.length()- repeatValue -1){return maxSize;}
i++;}return maxSize;}}