[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)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容