3. 無重復字符的最長子串(Python)

題目

給定一個字符串饭玲,請你找出其中不含有重復字符的最長子串的長度。

示例

示例 1:

輸入: "abcabcbb"
輸出: 3
解釋: 因為無重復字符的最長子串是 "abc"叁执,所以其長度為 3茄厘。

示例 2:

輸入: "bbbbb"
輸出: 1
解釋: 因為無重復字符的最長子串是 "b",所以其長度為 1谈宛。

示例 3:

輸入: "pwwkew"
輸出: 3
解釋: 因為無重復字符的最長子串是 "wke"次哈,所以其長度為 3。
請注意吆录,你的答案必須是 子串 的長度窑滞,"pwke" 是一個子序列,不是子串恢筝。

解答

方案1

我們首先考慮用暴力求解法哀卫,探究字符串的每一個子串是否不含重復字符,并記錄不含重復字符的最長子串撬槽。
這里此改,我們設置i,j為子串兩端字符在原字符中的下標索引侄柔,用lambda表達式定義一個簡易函數no_repetitive_chars共啃,用于判斷輸入的字符串是否沒有重復字符,如果沒有返回True暂题。用cur_len記錄當前非重復字符串的長度勋磕,用max_len記錄當前為止最大非重復子串長度。所有子串的可能有(N+1)*N/2個敢靡,需要一一判斷挂滓。

class Solution:
    def lengthOfLongestSubstring(self, s):
        no_repetitive_chars = lambda s: len(list(cur_chars)) == len(set(list(cur_chars)))
        max_len = 0
        for i in range(len(s)):
            for j in range(i+1, len(s)+1):
                cur_chars = s[i:j]                      # 取當前子串
                if no_repetitive_chars(cur_chars):
                    cur_len = len(cur_chars)            # 當前子串長度
                    max_len = max(cur_len, max_len)     # 當前最長子串長度
        return max_len

不出意料,代碼超時啸胧,我們需要更換思路赶站。

方案2

如何做到只遍歷一次?為了獲得更好的時間性能纺念,我們采用算法優(yōu)化中常用的以空間換時間策略贝椿,設輸入字符串為s,從頭到尾遍歷字符串:
1.創(chuàng)建臨時字符串變量cur_str陷谱,這個字符串中烙博,沒有重復字符瑟蜈,并且最后一個字符是當前遍歷到的字符;
2.定義下標字典(哈希表)index_dict渣窜,字典的鍵是cur_str中的每一個字符铺根,值為字符對應的s中的下標;
3.從頭到尾遍歷字符串乔宿,查看當前字符串cur_char是否在cur_str中位迂,如果出現(xiàn)過,從字典中取出該字符的位置prev_index详瑞,為了保證cur_str中元素不重復掂林,需要把cur_str中第一個字符的開始位置start_index(相對于s)移動到prev_index+1,相當于從prev_index+0.5位置截斷cur_str并取后半部分坝橡;
4.同時更新下標字典index_dict泻帮,刪除在start_index之前的所有字符記錄,確保index_dict中的所有元素只包含cur_str中的所有字符计寇。
需要留意的是锣杂,start_index,prev_index饲常,cur_index等下標變量都是相對于輸入字符s的位置蹲堂。

class Solution(object):
    def lengthOfLongestSubstring(self, s):

        def remove_previous_chars(index_dict, index):
            previous_chars = []
            for char in index_dict.keys():
                if index_dict[char] < index:
                    previous_chars.append(char)
            for char in previous_chars:
                index_dict.pop(char)
        # 相當于{key: value for key, value in index_dict.items() if value >= index}
        # 但是執(zhí)行會出錯不知為何

        if s is None or len(s) == 0:                            # 特殊情況,特殊對待
            return 0

        max_len = start_index = 0
        index_dict = {}                                         # 下標字典贝淤,key為字符柒竞,value為下標

        for cur_index in range(len(s)):
            cur_char = s[cur_index]                             # 當前字符
            if cur_char in index_dict:
                start_index = index_dict[cur_char] + 1          # 更新當前字符串的起始位置
                remove_previous_chars(index_dict, start_index)  # 更新下標字典
            # cur_str = s[cur_index: start_index+1]             # 當前字符串
            # cur_len = len(cur_str)                            # 當前字符串長度
            cur_len = cur_index - start_index + 1               # 當前字符的長度
            index_dict[cur_char] = cur_index                    # 加入當前字符及其下標
            max_len = max(max_len, cur_len)                     # 當前最大長度
        return max_len

代碼通過時間限制,耗時280ms播聪。

方案3

如何能夠不用反復刪除字典中的元素朽基?這里我們的字典index_dict性質改變,不只用來記錄cur_str中的所有字符离陶,而是遍歷到當前位置cur_index后之前所有s中出現(xiàn)過的字符及其距離cur_index最近的下標稼虎。這樣就要求我們不能隨意更新cur_str的開始位置start_index,這時招刨,我們更新start_index不僅需要當前字符在index_dict中出現(xiàn)過霎俩,位置為prev_index,而且需要保證出現(xiàn)的位置在cur_str中沉眶,這就要求上次出現(xiàn)位置prev_index<當前字符串的開始位置cur_index打却,省去了刪除字典元素的步驟。

class Solution(object):
    def lengthOfLongestSubstring(self, s):

        if s is None or len(s) == 0:
            return 0

        max_len = start_index = 0
        index_dict = {}

        for cur_index in range(len(s)):
            cur_str = s[cur_index]
            if cur_str in index_dict and index_dict[cur_str] >= start_index:
                start_index = index_dict[cur_str] + 1
            cur_len = cur_index - start_index + 1
            index_dict[cur_str] = cur_index
            max_len = max(max_len, cur_len)
        return max_len

代碼通過時間88ms谎倔,這也是網上廣泛采用的方法柳击。

如有任何疑問,歡迎評論區(qū)留言片习。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末捌肴,一起剝皮案震驚了整個濱河市蹬叭,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌状知,老刑警劉巖秽五,帶你破解...
    沈念sama閱讀 216,324評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異试幽,居然都是意外死亡筝蚕,警方通過查閱死者的電腦和手機卦碾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評論 3 392
  • 文/潘曉璐 我一進店門铺坞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人洲胖,你說我怎么就攤上這事济榨。” “怎么了绿映?”我有些...
    開封第一講書人閱讀 162,328評論 0 353
  • 文/不壞的土叔 我叫張陵擒滑,是天一觀的道長。 經常有香客問我叉弦,道長丐一,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,147評論 1 292
  • 正文 為了忘掉前任淹冰,我火速辦了婚禮库车,結果婚禮上,老公的妹妹穿的比我還像新娘樱拴。我一直安慰自己柠衍,他們只是感情好,可當我...
    茶點故事閱讀 67,160評論 6 388
  • 文/花漫 我一把揭開白布晶乔。 她就那樣靜靜地躺著珍坊,像睡著了一般。 火紅的嫁衣襯著肌膚如雪正罢。 梳的紋絲不亂的頭發(fā)上阵漏,一...
    開封第一講書人閱讀 51,115評論 1 296
  • 那天,我揣著相機與錄音翻具,去河邊找鬼履怯。 笑死,一個胖子當著我的面吹牛呛占,可吹牛的內容都是我干的虑乖。 我是一名探鬼主播,決...
    沈念sama閱讀 40,025評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼晾虑,長吁一口氣:“原來是場噩夢啊……” “哼疹味!你這毒婦竟也來了仅叫?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,867評論 0 274
  • 序言:老撾萬榮一對情侶失蹤糙捺,失蹤者是張志新(化名)和其女友劉穎诫咱,沒想到半個月后,有當地人在樹林里發(fā)現(xiàn)了一具尸體洪灯,經...
    沈念sama閱讀 45,307評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡坎缭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,528評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了签钩。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片掏呼。...
    茶點故事閱讀 39,688評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖铅檩,靈堂內的尸體忽然破棺而出憎夷,到底是詐尸還是另有隱情,我是刑警寧澤昧旨,帶...
    沈念sama閱讀 35,409評論 5 343
  • 正文 年R本政府宣布拾给,位于F島的核電站,受9級特大地震影響兔沃,放射性物質發(fā)生泄漏蒋得。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,001評論 3 325
  • 文/蒙蒙 一乒疏、第九天 我趴在偏房一處隱蔽的房頂上張望额衙。 院中可真熱鬧,春花似錦缰雇、人聲如沸入偷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽疏之。三九已至,卻和暖如春暇咆,著一層夾襖步出監(jiān)牢的瞬間锋爪,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評論 1 268
  • 我被黑心中介騙來泰國打工爸业, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留其骄,地道東北人。 一個月前我還...
    沈念sama閱讀 47,685評論 2 368
  • 正文 我出身青樓扯旷,卻偏偏與公主長得像拯爽,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子钧忽,可洞房花燭夜當晚...
    茶點故事閱讀 44,573評論 2 353