Manacher’s Algorithm – Linear Time Longest Palindromic Substring

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 Time Longest Palindromic Substring)