3.无重复字符的最长子串(Longest Substring Without Repeating Characters)M

英文题目

  • Given a string s, find the length of the longest substring without repeating characters.

  • Example 1:

  • Input: s = "abcabcbb"
    Output: 3
    Explanation: The answer is "abc", with the length of 3.
    
  • Example 2:

  • Input: s = "bbbbb"
    Output: 1
    Explanation: The answer is "b", with the length of 1.
    
  • Example 3:

  • Input: s = "pwwkew"
    Output: 3
    Explanation: The answer is "wke", with the length of 3.
    
  • Notice that the answer must be a substring, "pwke" is a subsequence and not a substring.

  • Example 4:

  • Input: s = ""
    Output: 0
    
  • Constraints:

  • 0 <= s.length <= 5 * 10^4

  • s consists of English letters, digits, symbols and spaces.

中文题目

  • 给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。

  • 示例 1:

  • 输入: "abcabcbb"
    输出: 3 
    解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
    
  • 示例 2:

  • 输入: "bbbbb"
    输出: 1
    解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
    
  • 示例 3:

  • 输入: "pwwkew"
    输出: 3
    解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
    请注意,你的答案必须是子串的长度,"pwke" 是一个子序列,不是子串。
    

滑动窗口

  • 参考:滑动窗口open in new window

  • 初始化集合lookup

  • 遍历每个字符

    • 不断地判断当前字符是否存在lookup集合中,若存在则去除窗口左边字符,直到当前字符不在集合中
    • 把该字符添加到集合中
    • 使用集合的元素数量更新最大集合长度
  • 时间复杂度O(n)

    # python: 时间 64 ms, 击败 76.6%; 内存 16 MB, 击败 48.28%
    class Solution:
        def lengthOfLongestSubstring(self, s: str) -> int:
            if not s:
                return 0
            lookup = set()
            left, maxLen = 0, 0
            # right即为窗口右边界
            for right in range(len(s)):
                while s[right] in lookup:
                    lookup.remove(s[left])
                    left += 1
                lookup.add(s[right])
                maxLen = max(maxLen, len(lookup))
            return maxLen
    
    // C++: 时间 40 ms, 击败 15.41%; 内存 13.1 MB, 击败 10.59%
    class Solution {
    public:
        int lengthOfLongestSubstring(string s) {
            if (s.size() == 0) {
                return 0;
            }
            set<char> lookup;
            // 注意要定义成 unsigned long,否则编译不过
            unsigned long maxLen = 0; 
            int left = 0;
            for (int right = 0; right < s.size(); ++right) {
                while (lookup.find(s[right]) != lookup.end()) {
                    lookup.erase(s[left]);
                    ++left;
                }
                lookup.insert(s[right]);
                max_len = std::max(maxLen, lookup.size());
            }
            return max_len;
        }
    };
    
    // java: 时间 6 ms, 击败 47.49%; 内存 42.6 MB, 击败 25.29%
    class Solution {
        public int lengthOfLongestSubstring(String s) {
            if (s.length() == 0) {
                return 0;
            }
            Set<Character> lookup = new HashSet<>();
            int left = 0, maxLen = 0;
            for (int right = 0; right < s.length(); ++right) {
                while (lookup.contains(s.charAt(right))) {
                    lookup.remove(s.charAt(left));
                    ++left;
                }
                lookup.add(s.charAt(right));
                maxLen = Math.max(maxLen, lookup.size());
            }
            return maxLen;
        }
    }
    
    // Go:时间 12 ms, 击败 40.73%; 内存 2.4 MB, 击败 78.98%
    func lengthOfLongestSubstring(s string) int {
        if len(s) == 0 {
            return 0
        }
        lookup := map[byte]bool{}
        left, maxLen := 0, 0
        for right := range s {
            for ; left < right; left++ { // 注意go里的循环
                if _, ok := lookup[s[right]]; !ok {
                    break
                }
                delete(lookup, s[left])
            }
            lookup[s[right]] = true
            maxLen = maxInt(len(lookup), maxLen)
        }
        return maxLen
    }
    
    func maxInt(a, b int) int {
        if a >= b {
            return a
        }
        return b
    }
    
    // javascript: 时间 80 ms, 击败 73.96%; 内存 45.7 MB, 击败 48.40%
    /**
     * @param {string} s
     * @return {number}
     */
    var lengthOfLongestSubstring = function(s) {
        if (s.length == 0) {
            return 0;
        }
        const lookup = new Set();
        let left = 0, maxLen = 0;
        for (let right = 0; right < s.length; ++right) {
            while (lookup.has(s.charAt(right))) {
                lookup.delete(s.charAt(left));
                ++left;
            }
            lookup.add(s.charAt(right));
            maxLen = Math.max(maxLen, lookup.size);
        }
        return maxLen;
    };
    
Last Updated:
Contributors: Shiqi Lu, Traum Lou