LeetCode 3. Longest Substring Without Repeating Characters 无重复字符的最长子串
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
1 2 3
| 输入: "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
|
示例 2:
1 2 3
| 输入: "bbbbb" 输出: 1 解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
|
示例 3:
1 2 3 4
| 输入: "pwwkew" 输出: 3 解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。 请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
|
题干很容易看懂,直接用暴力法查找所有子串中最长的无重复字符子串这种方法就不写了,时间复杂度是\(O(n^3)\),肯定是会超时的。暴力法中对所有子串进行检测会做很多重复的操作,如果我们能记录下\(i\)到\(j-1\)中没有重复的字符, 那么只要\(s[j]\)不在\(i\)到\(j-1\)中,那么\(i\)到\(j\)的子串中就没有重复的字符。这里我们就使用滑动窗口来记录\(i\)到\(j-1\)中的字符。
Java题解1:
按照上述思路可以得到正确的答案,但是耗时太长。使用HashSet记录字符,可以把查找的效率提高到\(O(1)\)。整个算法的时间复杂度为\(O(n)\)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
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) { 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; }
|
Java题解2:
优化题解
优化点:
使用HashMap来记录某个字符串最后出现的位置,这样删除的时候就不需要一个个删除,\(left\)可以直接跳到与\(s[i]\)重复的那个字符串的位置。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
public int lengthOfLongestSubstring2(String s) { int max = 0; int left = -1; HashMap<Character, Integer> hashMap = new HashMap<>(); for (int i = 0; i < s.length(); i++) { char charitem = s.charAt(i); if (hashMap.containsKey(charitem)) { left = Math.max(left, hashMap.get(charitem)); } max = Math.max(i - left, max); hashMap.put(charitem, i); } return max; }
|