3. Longest Substring Without Repeating Characters
Given a string, find the length of the longest substring without repeating characters.
Example 1:
Input: "abcabcbb"
Output: 3
Explanation: The answer is "abc", with the length of 3.
Example 2:
Input: "bbbbb"
Output: 1
Explanation: The answer is "b", with the length of 1.
Example 3:
Input: "pwwkew"
Output: 3
Explanation: 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.
分析:
题目要求的是一个字符串里最长的不包含重复字符的子串,这个子串的位置可以任意的,返回这个子串的长度。
-
常规解法:暴力比较
- 得到这个字符串的每一个子串
- 计算他们的长度,得到最大值
分析:
- 姑且不论这种方法是否够好,在for循环的条件里最好还是不要进行计算长度,先在循环外进行一次计算就好。
- 最大的问题还是时间复杂度太高,求子串的时间复杂度是O(n2),内部内嵌套一个时间复杂度为O(n)的判断该子串是否包含重复字符的循环,那么最终时间复杂度会是O(n3),在LeetCode无法通过。
Solution 1:
class Solution { public int lengthOfLongestSubstring(String s) { int ans = 0; String substr = null; for(int i = 0; i < s.length(); i++) { for(int j = i + 1; j < s.length() + 1; j++) { substr = s.substring(i, j);// 子串为i-j,不包括j if(unique(substr)) { ans = Math.max(ans, substr.length()); } } } return ans; } public static boolean unique(String str) { Set<Character> set = new HashSet<>(); for(int i = 0; i < str.length(); i++) { char c = str.charAt(i); if(set.contains(c)) { return false; } set.add(c); } return true; } }
-
改进方法:类似于滑动窗口
分别使用i,j表示窗口的左端和右端,每当
j++
窗口右端右移,加入一个新的字符时就判断是否有重复的字符,如果没有就更新ans的值,否则窗口的左端也右移i++
,窗口的左端也右移之后也是还要继续判断是不是还有重复的字符,如此窗口一直右移直到一端移除边界。分析:
时间复杂度为O(n)。
Solution 2:
public class Solution { public int lengthOfLongestSubstring(String s) { if(s == null || s.length() == 0) { return 0; } Set<Character> set = new HashSet<>(); int i = 0, j = 0, ans = 0; int n = s.length(); while(j < n) { if(set.contains(s.charAt(j))) { set.remove(s.charAt(i++)); } else { set.add(s.charAt(j++));// 如果窗口里还有j,就将j加入窗口 ans = Math.max(ans, set.size());// 并更新窗口的最大值 } } return ans; } }