📌  相关文章
📜  由前缀的级联和后缀字符串形成的最长回文字符串(1)

📅  最后修改于: 2023-12-03 15:27:14.036000             🧑  作者: Mango

由前缀的级联和后缀字符串形成的最长回文字符串

在计算机科学中,回文字符串是一个正着读和倒着读都一样的字符串,例如"level"或"racecar"。最长回文字符串指在一个给定字符串中,最长的回文字符串。

本文将介绍一种基于前缀的级联和后缀字符串的算法,可以用来找到最长回文字符串。

1. 前缀的级联

在字符串的前缀中,有些前缀和其他前缀是可以级联的。例如,对于字符串"abacaba",前缀"a"与前缀"aba"级联,因为它们都以"a"为开头。

在本算法中,我们将找到所有可级联的前缀,并将它们组成一个名为"palindrome tree"的数据结构。

以下是通过前缀的级联,构建出来的"palindrome tree"的示意图:

                                  a   
                              /   |   \
                             a   bcb   a 
                                /     \
                               b       c

在上述示意图中,每个节点代表一个回文字符串。在这个例子中,我们可以看到有三个回文字符串,分别为"a","aba"和"aca"。我们还可以看到,"aba"和"aca"级联,因为它们的公共前缀为"a"。

2. 后缀字符串

我们可以通过后缀字符串来进一步优化我们的算法。后缀字符串是原字符串的反转字符串。例如,对于字符串"abacaba",后缀字符串为"abacaba"的反转字符串"abacaba"。

我们将在"palindrome tree"中添加"suffix link"属性来保存每个节点的后缀节点。"suffix link"指向一个满足以下条件的节点:

  • 它是当前节点回文字符串的后缀字符串所能到的最长回文字符串的节点
    • 如果不存在,则指向根节点

以下是添加了"suffix link"属性后,"palindrome tree"的示意图:

                                ┌── a ──┐
                                │ /   |   \
                                aa bcb aa 
                              / (b ) | (c)
                             a      b   c
                          (ab)    (aba)(aca)
                               ┌── a ──┐ 
                               │     |   \
                               ab    bcb  ac  
                             /  \  (b ) (c)    
                            a   a  ba   cb      
                          (aba) (aca)

在上述示意图中,我们可以看到,每个节点都有一个后缀链接。例如,节点"b"的后缀链接指向节点"aa",因为"b"节点的回文后缀"b",可以通过"bcb"所在的节点"a"的后缀链接指向节点"aa",而节点"aa"是最长的回文后缀。

3. 从"palindrome tree"中找到最长回文字符串

有了"palindrome tree"和后缀链接,我们可以用以下步骤找到最长回文字符串:

  1. 从根节点开始,按照输入字符串的顺序遍历每个字符
  2. 如果没有以当前字符结尾的回文字符串,就创建一个新的节点,并添加到"palindrome tree"中。将该节点作为当前节点。
  3. 如果存在以当前字符结尾的回文字符串,就沿着后缀链接向下移动到最长回文后缀所在的节点。将该节点作为当前节点。
  4. 为当前节点添加以当前字符结尾的回文字符串,并记录该字符串的长度。
  5. 如果当前节点的回文字符串长度大于已知最长回文字符串的长度,则更新已知最长回文字符串。

以下是一个Python实现:

def longest_palindrome(s):
    # 创建一个palindrome tree并初始化根节点
    tree = [[-1, -1, {}], [-1, 0, {}]]
    n = len(s)
    ans_l = ans_r = 0
    for i in range(n):
        cur = 1
        j = i
        while True:
            if j == -1 or s[j] in tree[cur][2]:
                break
            cur = tree[cur][0]
        if j != -1:
            cur = tree[cur][2][s[j]]
        else:
            cur = 1
        while True:
            if j-1 < 0 or j-1 in tree[cur][2] and s[j-1] == s[i]:
                break
            cur = tree[cur][1]
        if j-1 in tree[cur][2] and s[j-1] == s[i]:
            tree.append([-1, -1, {}])
            tree[-1][0] = tree[tree[cur][2][s[j-1]]][0]
            tree[cur][2][s[j-1]] = len(tree)-1
            cur = len(tree)-1
        tree[cur][2][s[i]] = len(tree)
        tree.append([-1, j-1, {}])
        tree[cur][1] = len(tree)-1
        cur = tree[cur][0]
        tree[-1][0] = cur
        while True:
            if s[i] in tree[cur][2]:
                if tree[cur][2][s[i]] != len(tree)-1:
                    tree[-1][0] = tree[cur][2][s[i]]
                break
            cur = tree[cur][0]
        cur = tree[-1][0]
        l = tree[cur][1]
        r = i
        while True:
            if l < 0 or r == n:
                break
            if s[l] != s[r]:
                break
            l -= 1
            r += 1
        if (r-l-1) > (ans_r-ans_l+1):
            ans_l = l+1
            ans_r = r-1
    return s[ans_l:ans_r+1]
4. 总结

基于前缀的级联和后缀字符串的算法,可以用来找到最长回文字符串。它使用了"palindrome tree"数据结构来表示回文字符串。

以上是本算法的详细介绍,希望可以帮助到需要的读者。