劍指offer:最長不含重複字符的子字符串

題目:最長不含重複字符的子字符串
請從字符串中找出一個最長的不包含重複字符的子字符串,計算該最長子字符串的長度。假設字符串中只包含從’a’到’z’的字符。例如,在字符串中」arabcacfr」,最長非重複子字符串爲」acfr」,長度爲4。git

# -*- coding: utf-8 -*-
# @Time         : 2019-07-11 10:57
# @Author       : Jayce Wong
# @ProjectName  : job
# @FileName     : longestSubstringWithoutDuplication.py
# @Blog         : https://blog.51cto.com/jayce1111
# @Github       : https://github.com/SysuJayce

class Solution:
    """
    解法1:
    接住ascii碼來肯定每個字符最新出現的位置,從而肯定新子串的起點。

    解法2:
    利用動態規劃。
    當s[i]第一次出現: f(i) = f(i-1) + 1
    當s[i]再一次出現,若是出如今f(i-1)的子串中且與上一次出現的距離爲d,那麼f(i) = d
    當s[i]再一次出現,若是沒有出如今f(i-1)的子串中,那麼f(i) = f(i-1) + 1
    """
    def longestSubstringWithoutDuplication1(self, s):
        """
        遍歷全部字符,經過更新每一個字符出現的位置,並調整起點位置,計算獲得當前子串的長度。
        """
        if not s:
            return ""
        # 這裏咱們只考慮ascii碼錶中的前256個字符,若是輸入是超過這個範圍的則須要擴大list長度
        # 或者使用字典
        pos = [-1] * 256
        # 將start標記爲當前子串起點前1位。例如當前子串的下標是0-3,則start置爲-1,這樣在後面
        # 計算長度的時候就不用+1,由於start標記的是前一位
        start = -1
        lengths = [0] * len(s)
        for i, ch in enumerate(s):
            if pos[ord(ch)] > start:
                start = pos[ord(ch)]
            pos[ord(ch)] = i
            lengths[i] = i - start

        pos = 0
        length = lengths[0]
        # 對每個字符來講,若是上一次出現的下標比當前子串的起點要大,也就是說這個字符上一次出現
        # 的地方是在start以後,而這一次又出現了,說明在[start+1, i]這一段出現了2個相同字符。
        # 那麼咱們須要將start移動到當前字符上一次出現的位置才能確保當前字符的這一次出現是新子串
        # 中的第一次出現。
        # 對於每個出現的字符,記錄最新出現的下標。
        for i in range(1, len(lengths)):
            if lengths[i] >= length:
                length = lengths[i]
                pos = i

        return s[pos + 1 - length: pos + 1]

    def longestSubstringWithoutDuplication2(self, s):
        lengths = [1] * len(s)  # 記錄每一個位置的最長子串的長度
        for i in range(1, len(s)):
            # 若是當前字符出如今了上一個字符的最長子串中,那麼以當前字符爲結尾的最長子串長度爲
            # d,其中d爲當前字符距離上一次出現時的距離
            if s[i] in s[i - lengths[i-1]: i]:
                d = 1
                while s[i-d] != s[i]:
                    d += 1
                if d > lengths[i - 1]:
                    lengths[i] = lengths[i - 1] + 1
                else:
                    lengths[i] = d
            # 若是當前字符第一次出現,或者沒有出如今上一個字符的最長子串中,那麼以這個字符爲結尾
            # 的最長子串的長度爲上一個字符最長子串長度+1
            else:
                lengths[i] = lengths[i - 1] + 1

        # 查找最長子串是以哪一個位置爲結尾的,而後切片找出最長子串是哪一個
        pos = 0
        length = lengths[0]
        for i in range(1, len(lengths)):
            if lengths[i] >= length:
                length = lengths[i]
                pos = i

        return s[pos+1-length: pos+1]

def main():
    s = "arabcacfr"
    solution = Solution()
    print(solution.longestSubstringWithoutDuplication2(s))

if __name__ == '__main__':
    main()
相關文章
相關標籤/搜索