[LeetCode] 3. Longest Substring Without Repeating Characters 題解

問題描述

輸入一個字符串,找到其中最長的不重複子串python

例1:數組

輸入:"abcabcbb"
輸出:3
解釋:最長非重複子串爲"abc"
複製代碼

例2:bash

輸入:"bbbbb"
輸出:1
解釋:最長非重複子串爲"b"
複製代碼

例3:spa

輸入:"pwwkew"
輸出:3
解釋:最長非重複子串爲"wke"
複製代碼

問題難度

Mediumcode

解題思路

本題採用「滑動窗口法」能夠達到較理想的時間複雜度 O(n),滑動窗口指的是當前非重複子串所在的窗口,此滑動窗口有兩種操做方法leetcode

  1. 檢查下一個字符是否會重複,如未重複,則將窗口向右擴大
  2. 發現重複字符,則將窗口右邊界保持不變,左邊界右移,以此縮小窗口

上面的操做比較容易理解,惟一須要注意的是第 2 點中,當發現重複字符時,窗口左邊界向右移動幾個單位,咱們能夠看一個示意圖:字符串

+---------+ 
| a b c d | e d x y z 
+---------+
 
+-----------+ 
| a b c d e | d x y z // 未發現重複,向右擴大窗口
+-----------+

        +-----+ 
a b c d | e d | x y z // 發現重複,縮小窗口
        +-----+
複製代碼

假設輸入字符串爲 "abcdedxyz",一直到咱們遍歷到字符 e 時,均未發現重複的字符串,至此對窗口進行的操做都是向右擴大,當檢查到下一個字符 d 時,因爲前面字符串中已經出現過該字符,因此窗口左邊界須要進行右移,移動的位置、即新子串窗口的起始點,正好是兩個重複字符中、第一個重複字符的右邊,如圖所示爲字符 e 所在的位置。get

至此,咱們能夠開始寫程序了:string

def lengthOfLongestSubstring(self, s):
        """ :type s: str :rtype: int """
        maxlen = 0
        current_substring = [None]*128
        current_substring_len = 0
        begin_index = 0
        for i in s:
            stoi = ord(i)
            if current_substring[stoi] is None or current_substring[stoi] < begin_index:
                current_substring[stoi] = begin_index + current_substring_len
                current_substring_len += 1
            else:
                if maxlen < current_substring_len:
                    maxlen = current_substring_len 
                
                sub_len = current_substring[stoi] - begin_index + 1
                begin_index = current_substring[stoi] + 1
                current_substring_len -= sub_len

                current_substring[stoi] = current_substring_len + begin_index
                current_substring_len += 1

        if maxlen < current_substring_len:
            maxlen = current_substring_len
        return maxlen
複製代碼

以上代碼中,current_substring 是一個緩衝區,用來存放當前子字符串,緩衝區聲明爲 128 個是爲了讓數組的下標空間能容納 128 個 ASCII 字符,即這裏用數組的下標來表示字符,這樣作的好處是能夠很快的知道某個字符是否出現重複,數組的內容咱們填的是該字符對應的下標,例如字符串 "abcde" 填到 current_substring 中爲:it

index:   0..97  98  99  100 101 ..
                   +---+---+---+---+---+---+---+
current_substring: |...| 0 | 1 | 2 | 3 | 4 |...|
                   +---+---+---+---+---+---+---+
複製代碼

咱們用變量 begin_index 來記錄當前窗口在字符串中的起始位置,而 current_substring_len 用來記錄當前窗口的長度。for 循環是對字符串的遍歷。

首先將字符轉化爲其對應的整數 stoi,檢查 stoi 中的內容是否爲空,或其存儲的位置是否在窗口的左邊,如是則表示該字符在 begin_index 以後未出現過,非重複子串能夠繼續累加。

不然表示出現重複,出現重複時,須要將窗口的左邊界右移,或者說對新的滑動窗口進行初始化,實際上只需更新 begin_indexcurrent_substring_len 兩個值。

最後,咱們須要在每一次窗口改變時,或在結束遍歷時,判斷當前子字符串的長度是不是最長的,並將最長串存儲在 maxlen 中,做爲結果返回。

原題連接

相關文章
相關標籤/搜索