Given a string, find the length of the longest substring without repeating characters.
給定一個(gè)字符串,超出不重復(fù)的最長(zhǎng)的子字符串。
Examples:
Given "abcabcbb", the answer is "abc", which the length is 3.
Given "bbbbb", the answer is "b", with the length of 1.
Given "pwwkew", the answer is "wke", with the length of 3.
Note that the answer must be a substring, "pwke" is a subsequence and not a substring.
解1(暴力解):
遍歷字符串,列出所有的子字符串的集合,然后判斷子字符串是否有重復(fù)的元素。boolean allUnique(String s, int start, int end)
來(lái)判斷start和end之間是否有重復(fù)的字符串。
代碼如下(java):
public class Solution { public int lengthOfLongestSubstring(String s) { int n = s.length(); int ans = 0; for (int i = 0; i < n; i++) for (int j = i + 1; j <= n; j++) if (allUnique(s, i, j)) ans = Math.max(ans, j - i); return ans; } public boolean allUnique(String s, int start, int end) { Set<Character> set = new HashSet<>(); for (int i = start; i < end; i++) { Character ch = s.charAt(i); if (set.contains(ch)) return false; set.add(ch); } return true; } }
這種方式的時(shí)間復(fù)雜度為O(n^3),
空間復(fù)雜度為O(k),k最大為不重復(fù)的子字符串的長(zhǎng)度。。這種方法顯然不是最優(yōu)解,提交時(shí)會(huì)顯示時(shí)間超時(shí)。
解2(推拉窗):
創(chuàng)建一個(gè)hashset,用兩個(gè)變量i,j分別表示子字符串的首尾位置。從字符串的首字符添加字符,如果在添加一個(gè)字符的時(shí)候,判斷hashset中是否已經(jīng)存在,如果不存在,添加該字符到set,進(jìn)行下一個(gè)字符的判斷,更新返回的長(zhǎng)度值;否則,刪除i位置的字符,子字符串的首位置向后移一位,如此循環(huán)先去。
代碼(java):
public class Solution { public int lengthOfLongestSubstring(String s) { int n = s.length(); Set<Character> set = new HashSet<>(); int ans = 0, i = 0, j = 0; while (i < n && j < n) { // try to extend the range [i, j] if (!set.contains(s.charAt(j))){ set.add(s.charAt(j++)); ans = Math.max(ans, j - i); } else { set.remove(s.charAt(i++)); } } return ans; } }
該算法的時(shí)間復(fù)雜度為O(2n)=O(n).
空間復(fù)雜度為O(k),k最大為不重復(fù)的子字符串的長(zhǎng)度。
解3(推拉窗改進(jìn)):
上面遍歷的兩次字符串,我們可以將下標(biāo)和字符存成字符串,那么我們就不必一步一步的遞增i了。代碼如下(java)。
public class Solution { public int lengthOfLongestSubstring(String s) { int n = s.length(), ans = 0; Map<Character, Integer> map = new HashMap<>(); // current index of character // try to extend the range [i, j] for (int j = 0, i = 0; j < n; j++) { if (map.containsKey(s.charAt(j))) { i = Math.max(map.get(s.charAt(j)), i); } ans = Math.max(ans, j - i + 1); map.put(s.charAt(j), j + 1); } return ans; } }
空間復(fù)雜度不變,時(shí)間復(fù)雜度為O(n),只遍歷字符串一次。