📜  使用回文树的最长回文子串套装3

📅  最后修改于: 2021-04-24 14:58:57             🧑  作者: Mango

给定一个字符串,找到最长的子字符串,即回文。例如,如果给定的字符串为“ forgeeksskeegfor”,则输出应为“ geeksskeeg”。

先决条件:回文树|最长回文子串

回文树的结构:
回文树的实际结构接近有向图。它实际上是两个Tree的合并结构,它们共享一些公共节点(请参见下图以更好地理解)。树节点通过存储其索引来存储给定字符串的回文子字符串。
该树由两种类型的边组成:
1.插入边缘(加权边缘)
2.最大回文后缀(未加权)

插入边:
从节点u到v的权重为x的插入边意味着节点v是通过在u的字符串的开头和结尾处插入x来形成的。由于“ u”已经是回文,因此节点v处的结果字符串也将是回文。 x将是每个边缘的单个字符。因此,一个节点最多可以有26个插入边(考虑到小写字母字符串)。
最大回文后缀边缘:
顾名思义,对于一个节点,该边将指向其“最大回文后缀字符串”节点。我们不会将完整的字符串本身视为最大回文后缀,因为这没有任何意义(自循环)。为了简单起见,我们将其称为后缀edge(这是指除完整字符串之外的最大后缀)。很明显,每个节点只有1个后缀边缘,因为我们不会在树中存储重复的字符串。
我们将创建所有回文子串,然后返回我们得到的最后一个,因为这将是迄今为止最长的回文子串。
由于回文树按某个字符的到达顺序存储回文,因此最长的将始终位于树数组的最后一个索引处。
下面是上述方法的实现:

C++
// CPP code for Longest Palindromic substring
// using Palindromic Tree data structure
#include 
using namespace std;
  
#define MAXN  1000
  
struct Node
{
    // store start and end indexes of current
    // Node inclusively
    int start, end;
  
    // stores length of substring
    int length;
  
    // stores insertion Node for all characters a-z
    int insertionEdge[26];
  
    // stores the Maximum Palindromic Suffix Node for
    // the current Node
    int suffixEdge;
};
  
// two special dummy Nodes as explained above
Node root1, root2;
  
// stores Node information for constant time access
Node tree[MAXN];
  
// Keeps track the current Node while insertion
int currNode;
string s;
int ptr;
  
// Function to insert edge in tree
void insert(int currIndex)
{
    // Finding X, such that s[currIndex]
    // + X + s[currIndex] is palindrome.
    int temp = currNode;
  
    while (true)
    {
        int currLength = tree[temp].length;
        if (currIndex - currLength >= 1 &&
            (s[currIndex] == s[currIndex -
             currLength - 1]))
                        break;
  
        temp = tree[temp].suffixEdge;
    }
  
    // Check if s[currIndex] + X +
    // s[currIndex] is already Present in tree.
    if (tree[temp].insertionEdge[s[currIndex] -
        'a'] != 0)
    {
        currNode =
        tree[temp].insertionEdge[s[currIndex]
                   - 'a'];
  
        return;
    }
  
    // Else Create new node;
    ptr++;
  
    tree[temp].insertionEdge[s[currIndex]
               - 'a'] = ptr;
  
    tree[ptr].end = currIndex;
  
    tree[ptr].length = tree[temp].length + 2;
  
    tree[ptr].start = tree[ptr].end -
                      tree[ptr].length + 1;
  
    // Setting suffix edge for newly Created Node.
  
    currNode = ptr;
    temp = tree[temp].suffixEdge;
  
    // Longest Palindromic suffix for a
    // string of length 1 is a Null string.
    if (tree[currNode].length == 1) {
        tree[currNode].suffixEdge = 2;
        return;
    }
  
    // Else
    while (true) {
        int currLength = tree[temp].length;
  
        if (currIndex - currLength >= 1 &&
            (s[currIndex] ==
             s[currIndex - currLength - 1]))
                break;
  
        temp = tree[temp].suffixEdge;
    }
  
    tree[currNode].suffixEdge =
        tree[temp].insertionEdge[s[currIndex] - 'a'];
}
  
// Driver code
int main()
{
    // Imaginary root's suffix edge points to
    // itself, since for an imaginary string
    // of length = -1 has an imaginary suffix
    // string. Imaginary root.
    root1.length = -1;
    root1.suffixEdge = 1;
  
    // NULL root's suffix edge points to
    // Imaginary root, since for a string
    // of length = 0 has an imaginary suffix string.
    root2.length = 0;
    root2.suffixEdge = 1;
  
    tree[1] = root1;
    tree[2] = root2;
  
    ptr = 2;
    currNode = 1;
    s = "forgeeksskeegfor";
    for (int i = 0; i < s.size(); i++)
            insert(i);
  
    // last will be the index of our last substring
    int last = ptr;
  
    for (int i = tree[last].start;
         i <= tree[last].end; i++)
                cout << s[i];
  
    return 0;
}


Java
// JAVA code for Longest Palindromic subString 
// using Palindromic Tree data structure 
class GFG 
{
  
    static final int MAXN = 1000;
  
    static class Node
    {
        // store start and end indexes of current
        // Node inclusively
        int start, end;
  
        // stores length of subString
        int length;
  
        // stores insertion Node for all characters a-z
        int[] insertionEdge = new int[26];
  
        // stores the Maximum Palindromic Suffix Node for
        // the current Node
        int suffixEdge;
    };
  
    // two special dummy Nodes as explained above
    static Node root1, root2;
  
    // stores Node information for constant time access
    static Node[] tree = new Node[MAXN];
  
    // Keeps track the current Node while insertion
    static int currNode;
    static char[] s;
    static int ptr;
  
    // Function to insert edge in tree
    static void insert(int currIndex)
    {
        // Finding X, such that s[currIndex]
        // + X + s[currIndex] is palindrome.
        int temp = currNode;
  
        while (true) {
            int currLength = tree[temp].length;
            if (currIndex - currLength >= 1 && 
                (s[currIndex] == s[currIndex - currLength - 1]))
                break;
  
            temp = tree[temp].suffixEdge;
        }
  
        // Check if s[currIndex] + X +
        // s[currIndex] is already Present in tree.
        if (tree[temp].insertionEdge[s[currIndex] - 'a'] != 0)
        {
            currNode = tree[temp].insertionEdge[s[currIndex] - 'a'];
  
            return;
        }
  
        // Else Create new node;
        ptr++;
  
        tree[temp].insertionEdge[s[currIndex] - 'a'] = ptr;
  
        tree[ptr].end = currIndex;
  
        tree[ptr].length = tree[temp].length + 2;
  
        tree[ptr].start = tree[ptr].end - tree[ptr].length + 1;
  
        // Setting suffix edge for newly Created Node.
  
        currNode = ptr;
        temp = tree[temp].suffixEdge;
  
        // Longest Palindromic suffix for a
        // String of length 1 is a Null String.
        if (tree[currNode].length == 1)
        {
            tree[currNode].suffixEdge = 2;
            return;
        }
  
        // Else
        while (true)
        {
            int currLength = tree[temp].length;
  
            if (currIndex - currLength >= 1 && 
                (s[currIndex] == s[currIndex - currLength - 1]))
                break;
  
            temp = tree[temp].suffixEdge;
        }
  
        tree[currNode].suffixEdge = 
        tree[temp].insertionEdge[s[currIndex] - 'a'];
    }
  
    // Driver code
    public static void main(String[] args) 
    {
        // Imaginary root's suffix edge points to
        // itself, since for an imaginary String
        // of length = -1 has an imaginary suffix
        // String. Imaginary root.
        root1 = new Node();
        root1.length = -1;
        root1.suffixEdge = 1;
  
        // null root's suffix edge points to
        // Imaginary root, since for a String
        // of length = 0 has an imaginary suffix String.
        root2 = new Node();
        root2.length = 0;
        root2.suffixEdge = 1;
        for (int i = 0; i < MAXN; i++)
            tree[i] = new Node();
        tree[1] = root1;
        tree[2] = root2;
  
        ptr = 2;
        currNode = 1;
        s = "forgeeksskeegfor".toCharArray();
        for (int i = 0; i < s.length; i++)
            insert(i);
  
        // last will be the index of our last subString
        int last = ptr;
  
        for (int i = tree[last].start; i <= tree[last].end; i++)
            System.out.print(s[i]);
  
    }
}
  
// This code is contributed by Rajput-Ji


Python3
# Python3 code for Longest Palindromic 
# substring using Palindromic Tree 
# data structure 
  
class Node: 
      
    def __init__(self, length = None, 
                       suffixEdge = None):
          
        # store start and end indexes 
        # of current Node inclusively 
        self.start = None
        self.end = None
          
        # Stores length of substring 
        self.length = length 
  
        # stores insertion Node for all
        # characters a-z 
        self.insertionEdge = [0] * 26
  
        # stores the Maximum Palindromic 
        # Suffix Node for the current Node 
        self.suffixEdge = suffixEdge 
  
# Function to insert edge in tree 
def insert(currIndex): 
      
    global currNode, ptr
      
    # Finding X, such that s[currIndex] 
    # + X + s[currIndex] is palindrome. 
    temp = currNode 
  
    while True: 
      
        currLength = tree[temp].length 
        if (currIndex - currLength >= 1 and
           (s[currIndex] == s[currIndex -
            currLength - 1])): 
            break
  
        temp = tree[temp].suffixEdge 
  
    # Check if s[currIndex] + X + 
    # s[currIndex] is already Present in tree. 
    if tree[temp].insertionEdge[ord(s[currIndex]) - 
                                ord('a')] != 0: 
      
        currNode = tree[temp].insertionEdge[ord(s[currIndex]) - 
                                            ord('a')] 
        return
      
    # Else Create new node 
    ptr += 1
  
    tree[temp].insertionEdge[ord(s[currIndex]) - 
                             ord('a')] = ptr 
  
    tree[ptr].end = currIndex 
  
    tree[ptr].length = tree[temp].length + 2
  
    tree[ptr].start = (tree[ptr].end - 
                       tree[ptr].length + 1)
  
    # Setting suffix edge for newly Created Node. 
    currNode = ptr 
    temp = tree[temp].suffixEdge 
  
    # Longest Palindromic suffix for a 
    # string of length 1 is a Null string. 
    if tree[currNode].length == 1: 
        tree[currNode].suffixEdge = 2
        return
  
    # Else 
    while True: 
        currLength = tree[temp].length 
  
        if (currIndex - currLength >= 1 and
            s[currIndex] == s[currIndex - 
                              currLength - 1]): 
            break
  
        temp = tree[temp].suffixEdge 
  
    tree[currNode].suffixEdge = \
    tree[temp].insertionEdge[ord(s[currIndex]) - ord('a')] 
  
# Driver code 
if __name__ == "__main__":
      
    MAXN = 1000
      
    # Imaginary root's suffix edge points to 
    # itself, since for an imaginary string 
    # of length = -1 has an imaginary suffix 
    # string. Imaginary root.
    root1 = Node(-1, 1) 
  
    # NULL root's suffix edge points to 
    # Imaginary root, since for a string of 
    # length = 0 has an imaginary suffix string. 
    root2 = Node(0, 1)
      
    # Stores Node information for 
    # constant time access 
    tree = [Node() for i in range(MAXN)] 
      
    # Keeps track the Current Node 
    # while insertion 
    currNode, ptr = 1, 2
      
    tree[1] = root1 
    tree[2] = root2 
  
    s = "forgeeksskeegfor"
    for i in range(0, len(s)): 
        insert(i) 
  
    # last will be the index of our
    # last substring 
    last = ptr 
    for i in range(tree[last].start,
                   tree[last].end + 1): 
        print(s[i], end = "") 
  
# This code is contributed by Rituraj Jain


C#
// C# code for longest Palindromic subString 
// using Palindromic Tree data structure 
using System;
  
class GFG 
{
  
    static readonly int MAXN = 1000;
  
    class Node
    {
        // store start and end indexes of current
        // Node inclusively
        public int start, end;
  
        // stores length of subString
        public int Length;
  
        // stores insertion Node for all characters a-z
        public int[] insertionEdge = new int[26];
  
        // stores the Maximum Palindromic Suffix Node for
        // the current Node
        public int suffixEdge;
    };
  
    // two special dummy Nodes as explained above
    static Node root1, root2;
  
    // stores Node information for constant time access
    static Node[] tree = new Node[MAXN];
  
    // Keeps track the current Node while insertion
    static int currNode;
    static char[] s;
    static int ptr;
  
    // Function to insert edge in tree
    static void insert(int currIndex)
    {
        // Finding X, such that s[currIndex]
        // + X + s[currIndex] is palindrome.
        int temp = currNode;
  
        while (true)
        {
            int currLength = tree[temp].Length;
            if (currIndex - currLength >= 1 && 
                (s[currIndex] == s[currIndex - currLength - 1]))
                break;
  
            temp = tree[temp].suffixEdge;
        }
  
        // Check if s[currIndex] + X +
        // s[currIndex] is already Present in tree.
        if (tree[temp].insertionEdge[s[currIndex] - 'a'] != 0)
        {
            currNode = tree[temp].insertionEdge[s[currIndex] - 'a'];
  
            return;
        }
  
        // Else Create new node;
        ptr++;
  
        tree[temp].insertionEdge[s[currIndex] - 'a'] = ptr;
  
        tree[ptr].end = currIndex;
  
        tree[ptr].Length = tree[temp].Length + 2;
  
        tree[ptr].start = tree[ptr].end - tree[ptr].Length + 1;
  
        // Setting suffix edge for newly Created Node.
        currNode = ptr;
        temp = tree[temp].suffixEdge;
  
        // longest Palindromic suffix for a
        // String of length 1 is a Null String.
        if (tree[currNode].Length == 1)
        {
            tree[currNode].suffixEdge = 2;
            return;
        }
  
        // Else
        while (true)
        {
            int currLength = tree[temp].Length;
  
            if (currIndex - currLength >= 1 && 
                (s[currIndex] == s[currIndex - currLength - 1]))
                break;
  
            temp = tree[temp].suffixEdge;
        }
  
        tree[currNode].suffixEdge = 
        tree[temp].insertionEdge[s[currIndex] - 'a'];
    }
  
    // Driver code
    public static void Main(String[] args) 
    {
        // Imaginary root's suffix edge points to
        // itself, since for an imaginary String
        // of length = -1 has an imaginary suffix
        // String. Imaginary root.
        root1 = new Node();
        root1.Length = -1;
        root1.suffixEdge = 1;
  
        // null root's suffix edge points to
        // Imaginary root, since for a String
        // of length = 0 has an imaginary suffix String.
        root2 = new Node();
        root2.Length = 0;
        root2.suffixEdge = 1;
        for (int i = 0; i < MAXN; i++)
            tree[i] = new Node();
        tree[1] = root1;
        tree[2] = root2;
  
        ptr = 2;
        currNode = 1;
        s = "forgeeksskeegfor".ToCharArray();
        for (int i = 0; i < s.Length; i++)
            insert(i);
  
        // last will be the index of our last subString
        int last = ptr;
  
        for (int i = tree[last].start; i <= tree[last].end; i++)
            Console.Write(s[i]);
  
    }
}
  
// This code is contributed by Rajput-Ji


输出:
geeksskeeg