leetcode 解題 3. 無重複字元的最長子串-python3@ 官方,暴力解法和視窗滑動解法

娃哈哈店長發表於2019-12-26
  • 給定一個字串,請你找出其中不含有重複字元的 最長子串 的長度。
  • 示例 1:
    輸入: "abcabcbb"
    輸出: 3
    解釋: 因為無重複字元的最長子串是 "abc",所以其長度為 3。

可在 twoSum中切換解題方式

暴力解法

我們可以遍歷給定字串 s 的所有可能的子字串並判斷子字串是否有無重複。
如果沒有重複,那麼我們將會更新無重複字元子串的最大長度的答案。

  • 時間複雜度:O(n^3)
    要驗證索引範圍在 [i, j) 內的字元是否都是唯一的,我們需要檢查該範圍中的所有字元
    對於所有 j∈[i+1,n] 所耗費的時間總和為:i+1∑n O(j−i)
    對於給定的 i∈[0,n-1]
    因此時間複雜度為O(n^3)

  • 空間複雜度O(n)

def check_str(self,s: str) -> bool:
        for i in range(len(s)):
            if s[i] in s[i+1:]:
                return False
        return True
def force(self, s: str) -> int:
        m=0
        if s != "":
            m=1
        for i in range(len(s)):
            for j in range(i+1,len(s)):
                if s[i] != s[j]:
                    if self.check_str(s[i:j+1]):
                        m = max(m,len(s[i:j+1]))
        return m

視窗滑動法

在暴力法中,我們會反覆檢查一個子字串是否含有有重複的字元,但這是沒有必要的。

如果從索引 i 到 j - 1之間的子字串 s[i:j]已經被檢查為沒有重複字元。我們只需要檢查 s[j] 對應的字元是否已經存在於子字串s[i:j]中。

要檢查一個字元是否已經在子字串中,我們可以檢查整個子字串,這將產生一個複雜度為 O(n^2)的演算法,但我們可以做得更好。

透過使用 HashSet 作為滑動視窗,我們可以用 O(1)的時間來完成對字元是否在當前的子字串中的檢查。

滑動視窗是陣列/字串問題中常用的抽象概念。

  • 視窗通常是在陣列/字串中由開始和結束索引定義的一系列元素的集合,即s[i,j).add()而滑動視窗是可以將兩個邊界向某一方向“滑動”的視窗。
    例如,我們將 [i, j)向右滑動 1 個元素,則它將變為 [i+1, j+1)(左閉,右開)。
  • 回到我們的問題,我們使用 HashSet 將字元儲存在當前視窗 [i, j)(最初 j = i)中。
  • 然後我們向右側滑動索引 j,如果它不在 HashSet 中,我們會繼續滑動 j。直到 s[j] 已經存在於 HashSet 中。
  • 此時,我們找到的沒有重複字元的最長子字串將會以索引 i 開頭。如果我們對所有的 i 這樣做,就可以得到答案。
  • 時間複雜度:O(2n) = O(n)O,在最糟糕的情況下,每個字元將被 i 和 j 訪問兩次。
  • 空間複雜度:O(min(m, n)),與之前的方法相同。滑動視窗法需要 O(k) 的空間,其中 k 表示 Set 的大小。而 Set 的大小取決於字串 n 的大小以及字符集 / 字母 m 的大小。
def sliding_window(self, s: str) -> int:
        # 視窗的定義
        dic = {}
        # 定義視窗左邊和最大無重複子字串長度為0
        i ,res = 0, 0
        # 向右從0依次滑動視窗右邊j
        for j in range(len(s)):
            # 當視窗中的字串有重複
            if s[j] in dic:
                #將視窗左邊i向後移動
                i = max(dic[s[j]], i)
                # i +=1
            # 獲取新的最大無重複子字串長度
            res = max(res, j-i+1)
            # 將j滑過的字元存入dic
            dic[s[j]] = j+1
        return res

python3最新執行速度最佳化題解,還是利用視窗移動方式
速度和佔用記憶體最優: 還是利用移動視窗 但是取消了字典或者set的定義,用python3 的切片來代替

def lengthOfLongestSubstring(self, s:str) -> int:
        length,j = 0,-1
        for i,x in enumerate(s):
            if x in s[j+1:i]:
                length = max(length,i-j-1)
                j = s[j+1:i].index(x)+j+1
        return max(length,len(s)-1-j)

原始碼儲存在github上,歡迎來提bug哦!-點選訪問
如果覺得不錯請給我一個star謝謝了Stray_Camel(^U^)ノ~YO

本作品採用《CC 協議》,轉載必須註明作者和本文連結
文章!!首發於我的部落格Stray_Camel(^U^)ノ~YO

相關文章