📜  使用Trie的最长公共前缀

📅  最后修改于: 2021-04-17 08:36:00             🧑  作者: Mango

给定一组字符串,找到最长的公共前缀。

Input  : {“geeksforgeeks”, “geeks”, “geek”, “geezer”}
Output : "gee"

Input  : {"apple", "ape", "april"}
Output : "ap"

以前的方法:一个字一个字匹配,逐匹配,分而治之,二进制搜索。

在本文中,讨论了一种使用Trie日期结构的方法。
脚步:

  • 将所有单词一一插入到特里。插入后,我们在Trie上进行散步。
  • 在这一步中,请更深入,直到找到一个节点的子节点超过1个(发生分支)或0个子节点(其中一个字符串用尽)。

    这是因为出现在最长公共前缀中的字符(三叉戟中的节点)必须是其父节点的单个子节点,即-在任何这些节点中都不应分支。

将字符串视为–“ geeksforgeeks”,“ geeks”,“ geek”,“ geezer”的算法图解

最长公共前缀使用Trie

C++
// A Program to find the longest common
// prefix of the given words
  
#include
using namespace std;
  
// Alphabet size (# of symbols)
#define ALPHABET_SIZE (26)
  
// Converts key current character into index
// use only 'a' through 'z' and lower case
#define CHAR_TO_INDEX(c) ((int)c - (int)'a')
  
// Trie node
struct TrieNode
{
    struct TrieNode *children[ALPHABET_SIZE];
  
    // isLeaf is true if the node represents
    // end of a word
    bool isLeaf;
};
  
// Returns new trie node (initialized to NULLs)
struct TrieNode *getNode(void)
{
    struct TrieNode *pNode = new TrieNode;
  
    if (pNode)
    {
        int i;
  
        pNode->isLeaf = false;
  
        for (i = 0; i < ALPHABET_SIZE; i++)
            pNode->children[i] = NULL;
    }
  
    return pNode;
}
  
// If not present, inserts the key into the trie
// If the key is a prefix of trie node, just marks leaf node
void insert(struct TrieNode *root, string key)
{
    int length = key.length();
    int index;
  
    struct TrieNode *pCrawl = root;
  
    for (int level = 0; level < length; level++)
    {
        index = CHAR_TO_INDEX(key[level]);
        if (!pCrawl->children[index])
            pCrawl->children[index] = getNode();
  
        pCrawl = pCrawl->children[index];
    }
  
    // mark last node as leaf
    pCrawl->isLeaf = true;
}
  
// Counts and returns the number of children of the
// current node
int countChildren(struct TrieNode *node, int *index)
{
    int count = 0;
    for (int i=0; ichildren[i] != NULL)
        {
            count++;
            *index = i;
        }
    }
    return (count);
}
  
// Perform a walk on the trie and return the
// longest common prefix string
string walkTrie(struct TrieNode *root)
{
    struct TrieNode *pCrawl = root;
    int index;
    string prefix;
  
    while (countChildren(pCrawl, &index) == 1 &&
            pCrawl->isLeaf == false)
    {
        pCrawl = pCrawl->children[index];
        prefix.push_back('a'+index);
    }
    return (prefix);
}
  
// A Function to construct trie
void constructTrie(string arr[], int n, struct TrieNode *root)
{
    for (int i = 0; i < n; i++)
        insert (root, arr[i]);
    return;
}
  
// A Function that returns the longest common prefix
// from the array of strings
string commonPrefix(string arr[], int n)
{
    struct TrieNode *root = getNode();
    constructTrie(arr, n, root);
  
    // Perform a walk on the trie
    return walkTrie(root);
}
  
// Driver program to test above function
int main()
{
    string arr[] = {"geeksforgeeks", "geeks",
                    "geek", "geezer"};
    int n = sizeof (arr) / sizeof (arr[0]);
  
    string ans = commonPrefix(arr, n);
  
    if (ans.length())
        cout << "The longest common prefix is "
             << ans;
    else
        cout << "There is no common prefix";
    return (0);
}


Java
// Java Program to find the longest common
// prefix of the given words
public class Longest_common_prefix {
      
    // Alphabet size (# of symbols)
    static final int ALPHABET_SIZE = 26;
       
    // Trie node
    static class TrieNode
    {
        TrieNode[] children = new TrieNode[ALPHABET_SIZE];
       
        // isLeaf is true if the node represents
        // end of a word
        boolean isLeaf;
          
        // constructor
        public TrieNode() {
            isLeaf = false;
            for (int i = 0; i < ALPHABET_SIZE; i++)
                children[i] = null;
        }
    };
       
    static TrieNode root;
    static int indexs;
       
    // If not present, inserts the key into the trie
    // If the key is a prefix of trie node, just marks
    // leaf node
    static void insert(String key)
    {
        int length = key.length();
        int index;
       
        TrieNode pCrawl = root;
       
        for (int level = 0; level < length; level++)
        {
            index = key.charAt(level) - 'a';
            if (pCrawl.children[index] == null)
                pCrawl.children[index] = new TrieNode();
       
            pCrawl = pCrawl.children[index];
        }
       
        // mark last node as leaf
        pCrawl.isLeaf = true;
    }
       
    // Counts and returns the number of children of the
    // current node
    static int countChildren(TrieNode node)
    {
        int count = 0;
        for (int i=0; i


Python3
# Python 3 program to find the longest common prefix
ALPHABET_SIZE = 26
indexs = 0
class TrieNode:
    # constructor
    def __init__(self):
        self.isLeaf = False
        self.children = [None]*ALPHABET_SIZE
  
# Function to facilitate insertion in Trie
# If not present, insert the node in the Trie
def insert(key, root):
    pCrawl = root
    for level in range(len(key)):
        index = ord(key[level]) - ord('a')
        if pCrawl.children[index] == None:
            pCrawl.children[index] = TrieNode()
        pCrawl = pCrawl.children[index]
    pCrawl.isLeaf = True
  
# Function to construct Trie
def constructTrie(arr, n, root):
    for i in range(n):
        insert(arr[i], root)
  
# Counts and returns number of children of the node
def countChildren(node):
    count = 0
    for i in range(ALPHABET_SIZE):
        if node.children[i] != None:
            count +=1
            # Keeping track of diversion in the trie
            global indexs
            indexs = i
    return count
      
# Perform walk on trie and return longest common prefix 
def walkTrie(root):
    pCrawl = root
    prefix = ""
    while(countChildren(pCrawl) == 1 and pCrawl.isLeaf == False):
        pCrawl = pCrawl.children[indexs]
        prefix += chr(97 + indexs)
    return prefix or -1
  
# Function that returns longest common prefix 
def commonPrefix(arr, n, root):
    constructTrie(arr, n, root)
    return walkTrie(root)
  
# Driver code to test the code
n = 4
arr = ["geeksforgeeks", "geeks", "geek", "geezer"]
root = TrieNode()
print(commonPrefix(arr,n, root))
  
# This code is Contributed by Akshay Jain (DA-IICT)


C#
// C# Program to find the longest common
// prefix of the given words
using System;
      
public class Longest_common_prefix 
{
      
    // Alphabet size (# of symbols)
    static readonly int ALPHABET_SIZE = 26;
      
    // Trie node
    public class TrieNode
    {
        public TrieNode[] children = new TrieNode[ALPHABET_SIZE];
      
        // isLeaf is true if the node represents
        // end of a word
        public bool isLeaf;
          
        // constructor
        public TrieNode() 
        {
            isLeaf = false;
            for (int i = 0; i < ALPHABET_SIZE; i++)
                children[i] = null;
        }
    };
      
    static TrieNode root;
    static int indexs;
      
    // If not present, inserts the key into the trie
    // If the key is a prefix of trie node, just marks
    // leaf node
    static void insert(String key)
    {
        int length = key.Length;
        int index;
      
        TrieNode pCrawl = root;
      
        for (int level = 0; level < length; level++)
        {
            index = key[level] - 'a';
            if (pCrawl.children[index] == null)
                pCrawl.children[index] = new TrieNode();
      
            pCrawl = pCrawl.children[index];
        }
      
        // mark last node as leaf
        pCrawl.isLeaf = true;
    }
      
    // Counts and returns the number of children of the
    // current node
    static int countChildren(TrieNode node)
    {
        int count = 0;
        for (int i = 0; i < ALPHABET_SIZE; i++)
        {
            if (node.children[i] != null)
            {
                count++;
                indexs = i;
            }
        }
        return (count);
    }
      
    // Perform a walk on the trie and return the
    // longest common prefix string
    static String walkTrie()
    {
        TrieNode pCrawl = root;
        indexs = 0;
        String prefix = "";
      
        while (countChildren(pCrawl) == 1 &&
                pCrawl.isLeaf == false)
        {
            pCrawl = pCrawl.children[indexs];
            prefix += (char)('a' + indexs);
        }
        return prefix;
    }
      
    // A Function to construct trie
    static void constructTrie(String []arr, int n)
    {
        for (int i = 0; i < n; i++)
            insert (arr[i]);
        return;
    }
      
    // A Function that returns the longest common prefix
    // from the array of strings
    static String commonPrefix(String []arr, int n)
    {
        root = new TrieNode();
        constructTrie(arr, n);
      
        // Perform a walk on the trie
        return walkTrie();
    }
      
    // Driver program to test above function
    public static void Main(String []args)
    {
        String []arr = {"geeksforgeeks", "geeks",
                        "geek", "geezer"};
        int n = arr.Length;
      
        String ans = commonPrefix(arr, n);
      
        if (ans.Length != 0)
            Console.WriteLine("The longest common prefix is "+ans);
        else
            Console.WriteLine("There is no common prefix");
    }
}
  
// This code contributed by Rajput-Ji


输出 :

The longest common prefix is gee

时间复杂度:将所有单词插入特里树需要O(MN)时间,而在特里树上走动则需要O(M)时间,其中-

N = Number of strings
M = Length of the largest string

辅助空间:要存储所有字符串,我们需要为Trie分配O(26 * M * N)〜O(MN)空间。