Manacher “马拉车”算法

1.回文 :正着念和反着念都是一样的,就是可以对称。

2.暴力解不是很好,因为有奇数和偶数长度的串。奇数长度可以方便地扩展回文,但是偶数不便扩展。

3.使用技巧:在字符串的每个字符的两边都穿插特殊标记符号(任何符号都可以:因为虚轴不会和实轴比对)。这就使所有的字符串都变成了奇数长度。

4.例如:11311  --->  #1#1#3#1#1#  -->1 3 5 3 1 11 1 3 5 3 1   最长回文就是最大值➗2。即11311的最大回文数是11/2=5。

5.前提概念:

回文直径:以某个字符为中心,扩展出来的回文长度。

回文半径:回文直径的一半

回文半径数组:从0开始,从左往右开始求回文半径,将每个位置的回文半径存入回文半径数组。

回文右边界:从左往右扩,右边界是当前字符为中心扩展回文右边最远的位置。

回文右边界中心:第一次到达右边最远位置的中心

可能性1:i位置不在回文右边界里面。例如:#1#2#1#    求解第一个#时回文右边界是-1,不在回文右边界里面,更新回文右边界到“#”位置;扩展第一个“1”时,回文右边界在“#”位置,所有右边界更新为“1”位置。

可能性2:i位置在回文右边界内;带求解的i在回文右边界中心c的对称i*的范围在c的回文范围内。i的回文半径就是i*的回文半径。

可能性3:i位置在回文右边界内;带求解的i在回文右边界中心c的对称i*的范围不在c的回文范围内。i的回文半径就是i到R的距离(最远右边界)。

可能性4:i位置在回文右边界内;带求解的i在回文右边界中心c的对称i*的回文半径和以c为回文半径压线(重合)。i到R这部分必定是回文,但是往右边的下一位是不是,就得继续判断,不确定。

可能性:根据上面分析的4种情况,可以综合出以下内容。

CASE1:i在R外 ----->暴力扩展

CASE2:i在R内

                A)i*回文在L,R内 ---->直接得解:i的回文半径就是i*的回文半径

                B)i*回文在L,R外 ---->直接得解:i是(R-i)

                C)i*回文左边界与L重合,则需要确定R的右边继续查找是否符合。

算法复杂度:O(N)

 上面可能性的示例:

注释:{ }:L,R

[ ]:i或者i*的范围

加黑字母:c

加黑斜体字母:i或者i*

下划线为i的回文直径

CASE2(A):  t {F [aba] kt[aba] F} s

CASE2(B):  [ab {cEcba] tttabcEc} F

CASE2(C):  {[abcEcba]FFF[abcEcba]}?  -->继续判断“?”是否等于“F”

 代码展示:

def manacher_string(str):
    string = "#"
    for i in str:
        string = string + i + "#"
    return string

# a = manacher_string("dfdfsd")
# print(a)


def manacher(str):
    arr = []  # 回文半径数组
    str = manacher_string(str)
    C = -1  # C是回文中心
    R = -1  # R是回文右边界
    max = 0  # 更新最大回文数
    for i in range(len(str)):
        # 如果R>i,意味着符合CASE2中的A:i*在边界内-->arr[i] = arr[2*c-i],
        #                           B:i*在边界外-->arr[i] = R-i
        #                           C:i*与边界重合-->arr[2*c-i] == R-i
        # 当i >= R时,需要暴力扩。

        arr.append(min(arr[2*C-i], R-i))if R > i else arr.append(1)
        while i + arr[i] < len(str) and i - arr[i] > -1:  # i - arr[i] 左极限是第一个元素的情况 0-1=-1
            if str[i+arr[i]] == str[i-arr[i]]:
                arr[i] = arr[i] + 1
            else:
                break
        if i + arr[i] > R:  # 更新最大右边界和中心
            R = i + arr[i]
            C = i
        max = arr[i] if arr[i] > max else max
    return max - 1

a = manacher("abxxba")
print(a)

猜你喜欢

转载自blog.csdn.net/m0_38109046/article/details/88029844