[Leetcode] Longest Substring Without Repeating Characters

原题:

https://leetcode.com/problems/longest-substring-without-repeating-characters/description/

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

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.

分析:

首要要判断non-repeating characters,考虑要用字典或集合。
遍历全部子字符串需要O(N2),每个字符串判断non-repeating chars需要O(n),所以最坏需要时间O(n3)和空间O(n)。但由于构建子字符串和使用字典判断字符独特性可以同时进行,所以brute force应该只需要O(n2)。
考虑先实现brute force然后进行优化。

解题:

第一版:Brute Force

class Solution(object):
    def lengthOfLongestSubstring(self, s):
        """
        :type s: str
        :rtype: int
        """
        res = 0
        for i in range(len(s)):
            letters = set()
            j = i
            while j < len(s) and s[j] not in letters:
                letters.add(s[j])
                j += 1
            res = max(res, len(letters))
        return res

Time Limit Exceeded
时间是O(n2),但仍不出所料的超时了。

第二版:从brute force剪枝,已经构建出的子字符串字典不用重复构建。使用ordered dict来实现一个滑动窗口,右侧enqueue,左侧dequeue。当需要enqueue的字符已经存在时,dequeue已存在的字符和它左边的所有字符。

class Solution(object):
    def lengthOfLongestSubstring(self, s):
        """
        :type s: str
        :rtype: int
        """
        res = 0
        letters = collections.OrderedDict()
        for letter in s:
            inserted = False
            while not inserted:
                if letter not in letters:
                    letters[letter] = 1
                    inserted = True
                    res = max(res, len(letters))
                else:
                    letters.popitem(last = False)
        return res

Runtime: 389 ms
Accepted,但是速度仍然不够理想。
使用ordered dict,在pop左侧字符的时候是O(n)的时间。虽然比brute force有优化,但总时间依然是O(n2)。

第三版:在计算子字符串长度的时候,我们并不需要考虑每一个字符,只需要知道它的开始和结束的index就可以了。因此,我们实际需要的是一个字典,里面保存每一个已经遍历过的字符的index(重复字符取最大值)。并且在每次遇到重复字符的时候,用字典里保存的index来计算新的开始index。这样每次遍历结束时,我们可以保证开始和当前index之间的子字符串是没有重复字符的。

class Solution(object):
    def lengthOfLongestSubstring(self, s):
        """
        :type s: str
        :rtype: int
        """
        res = start = 0
        discovered = {}
        for idx, val in enumerate(s):
            if val in discovered:
                start = max(start, discovered[val] + 1)
            discovered[val] = idx
            res = max(res, idx - start + 1)
        return res

Runtime: 82 ms
时间:O(n)
空间:O(n)

你可能感兴趣的:([Leetcode] Longest Substring Without Repeating Characters)