📜  虫子|套装2(使用特里)

📅  最后修改于: 2021-04-28 14:12:34             🧑  作者: Mango

给定字典,这是一种在字典和M x N板中进行查询的方法,其中每个单元格都有一个字符。查找可以由一系列相邻字符组成的所有可能单词。请注意,我们可以移至8个相邻字符的任何一个,但是一个单词不应具有同一单元格的多个实例。

例子:

输入: dictionary [] = {“ GEEKS”,“ FOR”,“ QUIZ”,“ GO”}; boggle [] [] = {{‘G’,’I’,’Z’},{‘U’,’E’,’K’},{‘Q’,’S’,’E’}};输出:出现词典的以下单词GEEKS QUIZ说明: 输入: dictionary [] = {“ GEEKS”,“ ABCFIHGDE”}; boggle [] [] = {{‘A’,’B’,’C’},{‘D’,’E’,’F’},{‘G’,’H’,’I’}};输出:字典中以下单词出现ABCFIHGDE说明:

我们在下面的文章中讨论了基于Graph DFS的解决方案。
Boggle(在一个字符板上查找所有可能的单词)|套装1

在这里,我们讨论基于Trie的解决方案,它比基于DFS的解决方案更好。
给定字典dictionary [] = {“ GEEKS”,“ FOR”,“ QUIZ”,“ GO”}
1.创建一个空的trie并将给定字典的所有单词插入trie

After insertion, Trie looks like(leaf nodes are in RED)
                       root
                    /       
                    G   F     Q
                 /  |   |     |
                O   E   O     U
                    |   |     |
                    E    R     I
                    |         |  
                    K         Z 
                    |   
                    S   

2.之后,我们仅在boggle [] []中选择那些是Trie根的子代的字符
在上面让我们选择’G’boggle [0] [0],’Q’boggle [2] [0](它们都存在于boggle矩阵中)
3.在trie中搜索一个以我们在第2步中选择的字符开头的单词

1) Create bool visited boolean matrix (Visited[M][N] = false )
2) Call SearchWord() for every cell (i, j) which has one of the
   first characters of dictionary words. In above example,
   we have 'G' and 'Q' as first characters.

SearchWord(Trie *root, i, j, visited[][N])
if root->leaf == true 
   print word 

if we have seen this element first time then make it visited.
   visited[i][j] = true
   do
      traverse all child of current root 
      k goes (0 to 26 ) [there are only 26 Alphabet] 
      add current char and search for next character 

      find next character which is adjacent to boggle[i][j]
      they are 8 adjacent cells of boggle[i][j] (i+1, j+1), 
      (i+1, j) (i-1, j) and so on.
   
   make it unvisited visited[i][j] = false 

下面是上述想法的实现:

C++
// C++ program for Boggle game
#include 
using namespace std;
  
// Converts key current character into index
// use only 'A' through 'Z'
#define char_int(c) ((int)c - (int)'A')
  
// Alphabet size
#define SIZE (26)
  
#define M 3
#define N 3
  
// trie Node
struct TrieNode {
    TrieNode* Child[SIZE];
  
    // isLeaf is true if the node represents
    // end of a word
    bool leaf;
};
  
// Returns new trie node (initialized to NULLs)
TrieNode* getNode()
{
    TrieNode* newNode = new TrieNode;
    newNode->leaf = false;
    for (int i = 0; i < SIZE; i++)
        newNode->Child[i] = NULL;
    return newNode;
}
  
// If not present, inserts a key into the trie
// If the key is a prefix of trie node, just
// marks leaf node
void insert(TrieNode* root, char* Key)
{
    int n = strlen(Key);
    TrieNode* pChild = root;
  
    for (int i = 0; i < n; i++) {
        int index = char_int(Key[i]);
  
        if (pChild->Child[index] == NULL)
            pChild->Child[index] = getNode();
  
        pChild = pChild->Child[index];
    }
  
    // make last node as leaf node
    pChild->leaf = true;
}
  
// function to check that current location
// (i and j) is in matrix range
bool isSafe(int i, int j, bool visited[M][N])
{
    return (i >= 0 && i < M && j >= 0 && j < N && !visited[i][j]);
}
  
// A recursive function to print all words present on boggle
void searchWord(TrieNode* root, char boggle[M][N], int i,
                int j, bool visited[][N], string str)
{
    // if we found word in trie / dictionary
    if (root->leaf == true)
        cout << str << endl;
  
    // If both I and j in  range and we visited
    // that element of matrix first time
    if (isSafe(i, j, visited)) {
        // make it visited
        visited[i][j] = true;
  
        // traverse all childs of current root
        for (int K = 0; K < SIZE; K++) {
            if (root->Child[K] != NULL) {
                // current character
                char ch = (char)K + (char)'A';
  
                // Recursively search reaming character of word
                // in trie for all 8 adjacent cells of boggle[i][j]
                if (isSafe(i + 1, j + 1, visited)
                    && boggle[i + 1][j + 1] == ch)
                    searchWord(root->Child[K], boggle,
                               i + 1, j + 1, visited, str + ch);
                if (isSafe(i, j + 1, visited)
                    && boggle[i][j + 1] == ch)
                    searchWord(root->Child[K], boggle,
                               i, j + 1, visited, str + ch);
                if (isSafe(i - 1, j + 1, visited)
                    && boggle[i - 1][j + 1] == ch)
                    searchWord(root->Child[K], boggle,
                               i - 1, j + 1, visited, str + ch);
                if (isSafe(i + 1, j, visited)
                    && boggle[i + 1][j] == ch)
                    searchWord(root->Child[K], boggle,
                               i + 1, j, visited, str + ch);
                if (isSafe(i + 1, j - 1, visited)
                    && boggle[i + 1][j - 1] == ch)
                    searchWord(root->Child[K], boggle,
                               i + 1, j - 1, visited, str + ch);
                if (isSafe(i, j - 1, visited)
                    && boggle[i][j - 1] == ch)
                    searchWord(root->Child[K], boggle,
                               i, j - 1, visited, str + ch);
                if (isSafe(i - 1, j - 1, visited)
                    && boggle[i - 1][j - 1] == ch)
                    searchWord(root->Child[K], boggle,
                               i - 1, j - 1, visited, str + ch);
                if (isSafe(i - 1, j, visited)
                    && boggle[i - 1][j] == ch)
                    searchWord(root->Child[K], boggle,
                               i - 1, j, visited, str + ch);
            }
        }
  
        // make current element unvisited
        visited[i][j] = false;
    }
}
  
// Prints all words present in dictionary.
void findWords(char boggle[M][N], TrieNode* root)
{
    // Mark all characters as not visited
    bool visited[M][N];
    memset(visited, false, sizeof(visited));
  
    TrieNode* pChild = root;
  
    string str = "";
  
    // traverse all matrix elements
    for (int i = 0; i < M; i++) {
        for (int j = 0; j < N; j++) {
            // we start searching for word in dictionary
            // if we found a character which is child
            // of Trie root
            if (pChild->Child[char_int(boggle[i][j])]) {
                str = str + boggle[i][j];
                searchWord(pChild->Child[char_int(boggle[i][j])],
                           boggle, i, j, visited, str);
                str = "";
            }
        }
    }
}
  
// Driver program to test above function
int main()
{
    // Let the given dictionary be following
    char* dictionary[] = { "GEEKS", "FOR", "QUIZ", "GEE" };
  
    // root Node of trie
    TrieNode* root = getNode();
  
    // insert all words of dictionary into trie
    int n = sizeof(dictionary) / sizeof(dictionary[0]);
    for (int i = 0; i < n; i++)
        insert(root, dictionary[i]);
  
    char boggle[M][N] = { { 'G', 'I', 'Z' },
                          { 'U', 'E', 'K' },
                          { 'Q', 'S', 'E' } };
  
    findWords(boggle, root);
  
    return 0;
}


Java
// Java program for Boggle game
public class Boggle {
  
    // Alphabet size
    static final int SIZE = 26;
  
    static final int M = 3;
    static final int N = 3;
  
    // trie Node
    static class TrieNode {
        TrieNode[] Child = new TrieNode[SIZE];
  
        // isLeaf is true if the node represents
        // end of a word
        boolean leaf;
  
        // constructor
        public TrieNode()
        {
            leaf = false;
            for (int i = 0; i < SIZE; i++)
                Child[i] = null;
        }
    }
  
    // If not present, inserts a key into the trie
    // If the key is a prefix of trie node, just
    // marks leaf node
    static void insert(TrieNode root, String Key)
    {
        int n = Key.length();
        TrieNode pChild = root;
  
        for (int i = 0; i < n; i++) {
            int index = Key.charAt(i) - 'A';
  
            if (pChild.Child[index] == null)
                pChild.Child[index] = new TrieNode();
  
            pChild = pChild.Child[index];
        }
  
        // make last node as leaf node
        pChild.leaf = true;
    }
  
    // function to check that current location
    // (i and j) is in matrix range
    static boolean isSafe(int i, int j, boolean visited[][])
    {
        return (i >= 0 && i < M && j >= 0
                && j < N && !visited[i][j]);
    }
  
    // A recursive function to print
    // all words present on boggle
    static void searchWord(TrieNode root, char boggle[][], int i,
                           int j, boolean visited[][], String str)
    {
        // if we found word in trie / dictionary
        if (root.leaf == true)
            System.out.println(str);
  
        // If both I and j in  range and we visited
        // that element of matrix first time
        if (isSafe(i, j, visited)) {
            // make it visited
            visited[i][j] = true;
  
            // traverse all child of current root
            for (int K = 0; K < SIZE; K++) {
                if (root.Child[K] != null) {
                    // current character
                    char ch = (char)(K + 'A');
  
                    // Recursively search reaming character of word
                    // in trie for all 8 adjacent cells of
                    // boggle[i][j]
                    if (isSafe(i + 1, j + 1, visited)
                        && boggle[i + 1][j + 1] == ch)
                        searchWord(root.Child[K], boggle,
                                   i + 1, j + 1,
                                   visited, str + ch);
                    if (isSafe(i, j + 1, visited)
                        && boggle[i][j + 1] == ch)
                        searchWord(root.Child[K], boggle,
                                   i, j + 1,
                                   visited, str + ch);
                    if (isSafe(i - 1, j + 1, visited)
                        && boggle[i - 1][j + 1] == ch)
                        searchWord(root.Child[K], boggle,
                                   i - 1, j + 1,
                                   visited, str + ch);
                    if (isSafe(i + 1, j, visited)
                        && boggle[i + 1][j] == ch)
                        searchWord(root.Child[K], boggle,
                                   i + 1, j,
                                   visited, str + ch);
                    if (isSafe(i + 1, j - 1, visited)
                        && boggle[i + 1][j - 1] == ch)
                        searchWord(root.Child[K], boggle,
                                   i + 1, j - 1,
                                   visited, str + ch);
                    if (isSafe(i, j - 1, visited)
                        && boggle[i][j - 1] == ch)
                        searchWord(root.Child[K], boggle,
                                   i, j - 1,
                                   visited, str + ch);
                    if (isSafe(i - 1, j - 1, visited)
                        && boggle[i - 1][j - 1] == ch)
                        searchWord(root.Child[K], boggle,
                                   i - 1, j - 1,
                                   visited, str + ch);
                    if (isSafe(i - 1, j, visited)
                        && boggle[i - 1][j] == ch)
                        searchWord(root.Child[K], boggle,
                                   i - 1, j,
                                   visited, str + ch);
                }
            }
  
            // make current element unvisited
            visited[i][j] = false;
        }
    }
  
    // Prints all words present in dictionary.
    static void findWords(char boggle[][], TrieNode root)
    {
        // Mark all characters as not visited
        boolean[][] visited = new boolean[M][N];
        TrieNode pChild = root;
  
        String str = "";
  
        // traverse all matrix elements
        for (int i = 0; i < M; i++) {
            for (int j = 0; j < N; j++) {
                // we start searching for word in dictionary
                // if we found a character which is child
                // of Trie root
                if (pChild.Child[(boggle[i][j]) - 'A'] != null) {
                    str = str + boggle[i][j];
                    searchWord(pChild.Child[(boggle[i][j]) - 'A'],
                               boggle, i, j, visited, str);
                    str = "";
                }
            }
        }
    }
  
    // Driver program to test above function
    public static void main(String args[])
    {
        // Let the given dictionary be following
        String dictionary[] = { "GEEKS", "FOR", "QUIZ", "GEE" };
  
        // root Node of trie
        TrieNode root = new TrieNode();
  
        // insert all words of dictionary into trie
        int n = dictionary.length;
        for (int i = 0; i < n; i++)
            insert(root, dictionary[i]);
  
        char boggle[][] = { { 'G', 'I', 'Z' },
                            { 'U', 'E', 'K' },
                            { 'Q', 'S', 'E' } };
  
        findWords(boggle, root);
    }
}
// This code is contributed by Sumit Ghosh


C#
// C# program for Boggle game
using System;
  
public class Boggle {
  
    // Alphabet size
    static readonly int SIZE = 26;
  
    static readonly int M = 3;
    static readonly int N = 3;
  
    // trie Node
    public class TrieNode {
        public TrieNode[] Child = new TrieNode[SIZE];
  
        // isLeaf is true if the node represents
        // end of a word
        public bool leaf;
  
        // constructor
        public TrieNode()
        {
            leaf = false;
            for (int i = 0; i < SIZE; i++)
                Child[i] = null;
        }
    }
  
    // If not present, inserts a key into the trie
    // If the key is a prefix of trie node, just
    // marks leaf node
    static void insert(TrieNode root, String Key)
    {
        int n = Key.Length;
        TrieNode pChild = root;
  
        for (int i = 0; i < n; i++) {
            int index = Key[i] - 'A';
  
            if (pChild.Child[index] == null)
                pChild.Child[index] = new TrieNode();
  
            pChild = pChild.Child[index];
        }
  
        // make last node as leaf node
        pChild.leaf = true;
    }
  
    // function to check that current location
    // (i and j) is in matrix range
    static bool isSafe(int i, int j, bool[, ] visited)
    {
        return (i >= 0 && i < M && j >= 0 && j < N && !visited[i, j]);
    }
  
    // A recursive function to print all words present on boggle
    static void searchWord(TrieNode root, char[, ] boggle, int i,
                           int j, bool[, ] visited, String str)
    {
        // if we found word in trie / dictionary
        if (root.leaf == true)
            Console.WriteLine(str);
  
        // If both I and j in range and we visited
        // that element of matrix first time
        if (isSafe(i, j, visited)) {
            // make it visited
            visited[i, j] = true;
  
            // traverse all child of current root
            for (int K = 0; K < SIZE; K++) {
                if (root.Child[K] != null) {
                    // current character
                    char ch = (char)(K + 'A');
  
                    // Recursively search reaming character of word
                    // in trie for all 8 adjacent cells of
                    // boggle[i, j]
                    if (isSafe(i + 1, j + 1, visited) && boggle[i + 1, j + 1] == ch)
                        searchWord(root.Child[K], boggle, i + 1, j + 1,
                                   visited, str + ch);
                    if (isSafe(i, j + 1, visited) && boggle[i, j + 1] == ch)
                        searchWord(root.Child[K], boggle, i, j + 1,
                                   visited, str + ch);
                    if (isSafe(i - 1, j + 1, visited) && boggle[i - 1, j + 1] == ch)
                        searchWord(root.Child[K], boggle, i - 1, j + 1,
                                   visited, str + ch);
                    if (isSafe(i + 1, j, visited) && boggle[i + 1, j] == ch)
                        searchWord(root.Child[K], boggle, i + 1, j,
                                   visited, str + ch);
                    if (isSafe(i + 1, j - 1, visited) && boggle[i + 1, j - 1] == ch)
                        searchWord(root.Child[K], boggle, i + 1, j - 1,
                                   visited, str + ch);
                    if (isSafe(i, j - 1, visited) && boggle[i, j - 1] == ch)
                        searchWord(root.Child[K], boggle, i, j - 1,
                                   visited, str + ch);
                    if (isSafe(i - 1, j - 1, visited) && boggle[i - 1, j - 1] == ch)
                        searchWord(root.Child[K], boggle, i - 1, j - 1,
                                   visited, str + ch);
                    if (isSafe(i - 1, j, visited) && boggle[i - 1, j] == ch)
                        searchWord(root.Child[K], boggle, i - 1, j,
                                   visited, str + ch);
                }
            }
  
            // make current element unvisited
            visited[i, j] = false;
        }
    }
  
    // Prints all words present in dictionary.
    static void findWords(char[, ] boggle, TrieNode root)
    {
        // Mark all characters as not visited
        bool[, ] visited = new bool[M, N];
        TrieNode pChild = root;
  
        String str = "";
  
        // traverse all matrix elements
        for (int i = 0; i < M; i++) {
            for (int j = 0; j < N; j++) {
                // we start searching for word in dictionary
                // if we found a character which is child
                // of Trie root
                if (pChild.Child[(boggle[i, j]) - 'A'] != null) {
                    str = str + boggle[i, j];
                    searchWord(pChild.Child[(boggle[i, j]) - 'A'],
                               boggle, i, j, visited, str);
                    str = "";
                }
            }
        }
    }
  
    // Driver program to test above function
    public static void Main(String[] args)
    {
        // Let the given dictionary be following
        String[] dictionary = { "GEEKS", "FOR", "QUIZ", "GEE" };
  
        // root Node of trie
        TrieNode root = new TrieNode();
  
        // insert all words of dictionary into trie
        int n = dictionary.Length;
        for (int i = 0; i < n; i++)
            insert(root, dictionary[i]);
  
        char[, ] boggle = { { 'G', 'I', 'Z' },
                            { 'U', 'E', 'K' },
                            { 'Q', 'S', 'E' } };
        findWords(boggle, root);
    }
}
  
// This code has been contributed by 29AjayKumar


输出:

GEE, GEEKS, QUIZ

复杂度分析:

  • 时间复杂度: O(4 ^(N ^ 2))。
    即使应用了trie,时间复杂度也保持不变。对于每个单元,有4个方向,并且有N ^ 2个单元。因此,时间复杂度为O(4 ^(N ^ 2))。
  • 辅助空间: O(N ^ 2)。
    递归的最大长度可以为N ^ 2,其中N是矩阵的边。因此,空间复杂度为O(N ^ 2)。