劍指offer系列-面試題48. 最長不含重複字符的子字符串(python)

1. 題目

請從字符串中找出一個最長的不包含重複字符的子字符串,計算該最長子字符串的長度。
例子:

“abcabcbb” “abc” 長度爲3

“bbbbb” “b” 長度爲1

“dvdf” “vdf” 長度爲3

2. 解題思路

詳情見 面試題48. 最長不含重複字符的子字符串(動態規劃 / 雙指針 + 哈希表,清晰圖解)

圖解 滑動窗口(雙指針)及優化方法

2.1 暴力法

記錄子串的起點和終點,分別爲 i 和 j,當子字符串重複之後,從 i + 1重新計算最長不重複子字符串。

2.2 滑動窗口

0). 初始化頭尾指針 head,tail;
1). tail 指針右移,判斷 tail 指向的元素是否在 [head:tail] 的窗口內;
2). 如果窗口中沒有該元素,則將該元素加入窗口,同時更新窗口長度最大值,tail 指針繼續右移;
3). 如果窗口中存在該元素,則將 head 指針右移,直到窗口中不包含該元素。
4). 返回窗口長度的最大值。

2.3 優化的滑動窗口(雙指針+hash表)

與上面的不同之處在於,使用hash表記錄了字符的下標,當該字符重複時,直接去到該下標+1的位置,避免了重複比較。

2. 動態規劃

在這裏插入圖片描述

3. 代碼實現

3.1 暴力法

O(n2) + S(n)

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        """
        1. 暴力法
        """
        max_count = 0 # 最長不重複子字符串的長度
        record = set() # 記錄當前子串中以有哪些字符

        i, j = 0, 0 # 記錄子串的起點和終點
        while i <= j and j < len(s):
            if s[j] not in record: # 如果子串沒重複,長度+1
                record.add(s[j])
                j += 1
            else: # 如果子串重複了,重置record
                i = j = i+1
                record.clear() # 清空
            
            if len(record) > max_count: max_count = len(record)

        return max_count

3.2 滑動窗口

O(n2) + S(n)

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        head = 0
        tail = 0
        if len(s) < 2: return len(s) # 邊界條件
        res = 1
        
        while tail < len(s) - 1:
            tail += 1
            if s[tail] not in s[head: tail]:
                res = max(tail - head + 1, res)
            else:
                while s[tail] in s[head: tail]:
                    head += 1
        return res

作者:z1m
鏈接:https://leetcode-cn.com/problems/zui-chang-bu-han-zhong-fu-zi-fu-de-zi-zi-fu-chuan-lcof/solution/tu-jie-hua-dong-chuang-kou-shuang-zhi-zhen-shi-xia/
來源:力扣(LeetCode)
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

3.3 滑動窗口+hash表

O(n) + S(n)

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        n = len(s)
        hashmap = {}
        head, res = 0, 0
        for tail in range(n):
            if s[tail] in hashmap:
                head = max(hashmap[s[tail]], head)
            hashmap[s[tail]] = tail + 1
            res = max(res, tail - head + 1)
        return res

作者:z1m
鏈接:https://leetcode-cn.com/problems/zui-chang-bu-han-zhong-fu-zi-fu-de-zi-zi-fu-chuan-lcof/solution/tu-jie-hua-dong-chuang-kou-shuang-zhi-zhen-shi-xia/
來源:力扣(LeetCode)
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

3.4 動態規劃

O(n) + S(1)

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        dic = {}
        res = tmp = 0
        for j in range(len(s)):
            i = dic.get(s[j], -1) # 獲取索引 i
            dic[s[j]] = j # 更新哈希表
            tmp = tmp + 1 if tmp < j - i else j - i # dp[j - 1] -> dp[j]
            res = max(res, tmp) # max(dp[j - 1], dp[j])
        return res

作者:jyd
鏈接:https://leetcode-cn.com/problems/zui-chang-bu-han-zhong-fu-zi-fu-de-zi-zi-fu-chuan-lcof/solution/mian-shi-ti-48-zui-chang-bu-han-zhong-fu-zi-fu-d-9/
來源:力扣(LeetCode)
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

4. 總結

降低時間複雜度的關鍵在於,如何避免重複比較。

5. 參考文獻

[1] 劍指offer叢書
[2] 劍指Offer——名企面試官精講典型編程題

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章