美文网首页我爱编程
Manacher’s Algorithm – Linear Ti

Manacher’s Algorithm – Linear Ti

作者: 萧沪椿Helson | 来源:发表于2018-05-24 13:26 被阅读0次

    Manacher’s Algorithm 是一种高效查询最长回文串的算法,我在 lintcode 题目中用于统计输入的字符串拥有多少个回文子串。

    原文共 4 篇,part1 & part2 主要介绍原理,part3 & part4 为具体实现。
    推荐中文参考:https://www.felix021.com/blog/read.php?2040

    我把求解的条件整理如下。

    3 Answers and 4 Different Cases

    currentLeftPosition = 2 * centerPosition – currentRightPosition

    • ANS 1: L[currentRightPosition] = L[currentLeftPosition]

      • CASE 1: L[currentLeftPosition] < centerRightPosition – currentRightPosition

        • i-left palindrome is NOT prefix of the center palindrome
        • i-left palindrome is completely contained in the center palindrome
      • CASE 2: L[currentLeftPosition] == centerRightPosition – currentRightPosition

        • i-left palindrome is prefix of the center palindrome

        • center palindrome is suffix of the entire input string

          (centerRightPosition = 2*N where N is input string length N)

    • ANS 2: L[currentRightPosition] >= L[currentLeftPosition]

      • CASE 3: L[currentLeftPosition] == centerRightPosition – currentRightPosition

        • i-left palindrome is prefix of center palindrome

          (i-left palindrome is completely contained in center palindrome)

        • center palindrome is NOT suffix of input string

          (centerRightPosition < 2 * N where N is input string length N)

    • ANS 3: L[currentRightPosition] >= centerRightPosition – currentRightPosition

      • CASE 4: L[currentLeftPosition] > centerRightPosition – currentRightPosition
        • i-left palindrome is NOT completely contained in center palindrome

    What Would Be Next CenterPosition?

    We change centerPosition to currentRightPosition if palindrome centered at currentRightPosition expands beyond centerRightPosition.

    Solution

    请求一个数组 L ,长度为 2N + 1 ,N 个空间给输入字符串,N + 1 个空间用于隔断 N 个字符。

    L[i] 保存当前字符/隔断对应的回文串长度,如果当前字符/隔断没有回文串,字符的 L[i] 为 1 (字符本身也属于回文串),隔断的 L[i] 为 0 。

    初始化 L [1] 为 1 ,利用已计算出的长度,减少甚至不去计算后面对称的子串长度

    def findLongestPalindromicString(self, str):
        N = len(str)
        if N == 0:
            return
        
        N = 2 * N + 1  # Position (insert separator)
        L = [0] * N
        # the first seperator has no palindrome length
        # the first character has one length in the start
        L[1] = 1
        C = 1  # centerPosition
        R = 2  # centerRightPosition
        # i is currentRightPosition
        for i in range(2, N):
            iMirror = 2 * C - i
            diff = R - i
            if L[iMirror] <= diff:
                L[i] = L[iMirror]
            else:
                L[i] = diff
    
            try:
                # character will do compare, seperator just add ONE directly
                while ((i + L[i]) < N and (i - L[i]) > 0) and \
                        (((i + L[i] + 1) % 2 == 0) or
                            (str[(i + L[i] + 1) // 2] == str[(i - L[i] - 1) // 2])):
                    L[i] += 1
            except:
                pass
    
            if i + L[i] > R:
                C, R = i, i + L[i]
    
        return sum([(l + 1) // 2 for l in L])
    

    Other Solutions

        def countPalindromicSubstrings(self, str):
            # write your code here
            length = len(str)
            count = 0
            for l in range(2 * length - 1):
                left = right = l // 2
                if l % 2 != 0:
                    right += 1
                while left >= 0 and right < length and str[left] == str[right]:
                    count += 1
                    left -= 1
                    right += 1
    
            return count
    
        def dp(self, str):
            l = len(str)
            t = [[False for col in range(l)] for row in range(l)]
            for i in range(l):
                t[i][i] = True
                if i + 1 < l and str[i] == str[i + 1]:
                    t[i][i + 1] = True
    
            sub_l = 3
            while sub_l <= l:
                i = 0
                while i < (l - sub_l + 1):
                    j = i + sub_l - 1
                    if t[i + 1][j - 1] and str[i] == str[j]:
                        t[i][j] = True
                    i += 1
                sub_l += 1
    
            count = 0
            for i in range(l):
                for j in range(i, l):
                    if t[i][j] == True:
                        count += 1
            return count
    

    相关文章

      网友评论

        本文标题:Manacher’s Algorithm – Linear Ti

        本文链接:https://www.haomeiwen.com/subject/bbfsjftx.html