Given a M x N boggle board, find list of all possible words that can be formed by a sequence of adjacent characters on the the board.

We are allowed to search a word in all eight possible directions i.e. North, West, South, East, North-East, North-West, South-East, South-West, but a word should not have multiple instances of the same cell.



For example, consider below traditional 4 x 4 boggle board and a dictionary of valid words.

Dictionary: { START, NOTE, SAND, STONED }





Output: The valid words are: { NOTE, SAND, STONED }





We can use DFS to solve this problem. The idea is to start from each character in the matrix and explore all eight paths possible and recursively check if they leads to a solution or not. To make sure that a word doesn’t have multiple instances of the same cell, we keep track of cells involved in current path in a matrix and before exploring any cell, we ignore the cell if it is already covered in current path.

To find all possible possible movements from a cell, we can use an array to store the relative position of movement from any cell. For example, if the current cell is (x, y) , we can move to (x + row[k], y + col[k]) for 0 <= k <=7 using below array.



int row[] = { -1, -1, -1, 0, 0, 1, 1, 1 };

int col[] = { -1, 0, 1, -1, 1, -1, 0, 1 };



So, from position (x, y) , we can move to:



(x – 1, y – 1)

(x – 1, y)

(x – 1, y + 1)

(x, y – 1)

(x, y + 1)

(x + 1, y – 1)

(x + 1, y)

(x + 1, y + 1)





The algorithm can be implemented as follows in C++, Java and Python:

C++ #include <iostream> #include <vector> #include <algorithm> #include <unordered_set> #include <string> using namespace std; // M x N matrix #define M 3 #define N 4 // Below arrays details all 8 possible movements from a cell // (top, right, bottom, left and 4 diagonal moves) int row[] = { -1, -1, -1, 0, 1, 0, 1, 1 }; int col[] = { -1, 1, 0, -1, -1, 1, 0, 1 }; // Function to check if it is safe to go to cell (x, y) from current cell. // The function returns false if (x, y) is not valid matrix coordinates // or cell (x, y) is already processed bool isSafe(int x, int y, bool processed[][N]) { return (x >= 0 && x < M) && (y >= 0 && y < N) && !processed[x][y]; } // A recursive function to generate all possible words in a boggle void searchBoggle(char board[][N], unordered_set<string> &words, bool processed[][N], int i, int j, string path) { // mark current node as processed processed[i][j] = true; // update the path with the current character and insert it into the set path = path + board[i][j]; words.insert(path); // check for all 8 possible movements from the current cell for (int k = 0; k < 8; k++) { // skip if cell is invalid or it is already processed if (isSafe(i + row[k], j + col[k], processed)) { searchBoggle(board, words, processed, i + row[k], j + col[k], path); } } // mark current node as unprocessed processed[i][j] = false; } // Function to search for given set of words in a boggle void searchBoggle(char board[][N], vector<string> &input) { // construct a boolean matrix to store whether a cell is processed or not bool processed[M][N] { }; // construct a set to store all possible words constructed from the matrix unordered_set<string> words; // generate all possible words in a boggle for (int i = 0; i < M; i++) { for (int j = 0; j < N; j++) { // consider each character as a starting point and run DFS searchBoggle(board, words, processed, i, j, ""); } } // for each word in the input list, check whether it is present in the set for (string word: input) { if (words.find(word) != words.end()) { cout << word << endl; } } } int main() { char board[M][N] = { {'M', 'S', 'E', 'F'}, {'R', 'A', 'T', 'D'}, {'L', 'O', 'N', 'E'} }; vector<string> words { "START", "NOTE", "SAND", "STONED" }; searchBoggle(board, words); return 0; } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 #include <iostream> #include <vector> #include <algorithm> #include <unordered_set> #include <string> using namespace std ; // M x N matrix #define M 3 #define N 4 // Below arrays details all 8 possible movements from a cell // (top, right, bottom, left and 4 diagonal moves) int row [ ] = { - 1 , - 1 , - 1 , 0 , 1 , 0 , 1 , 1 } ; int col [ ] = { - 1 , 1 , 0 , - 1 , - 1 , 1 , 0 , 1 } ; // Function to check if it is safe to go to cell (x, y) from current cell. // The function returns false if (x, y) is not valid matrix coordinates // or cell (x, y) is already processed bool isSafe ( int x , int y , bool processed [ ] [ N ] ) { return ( x >= 0 && x < M ) && ( y >= 0 && y < N ) && ! processed [ x ] [ y ] ; } // A recursive function to generate all possible words in a boggle void searchBoggle ( char board [ ] [ N ] , unordered_set < string > &words , bool processed [ ] [ N ] , int i , int j , string path ) { // mark current node as processed processed [ i ] [ j ] = true ; // update the path with the current character and insert it into the set path = path + board [ i ] [ j ] ; words . insert ( path ) ; // check for all 8 possible movements from the current cell for ( int k = 0 ; k < 8 ; k ++ ) { // skip if cell is invalid or it is already processed if ( isSafe ( i + row [ k ] , j + col [ k ] , processed ) ) { searchBoggle ( board , words , processed , i + row [ k ] , j + col [ k ] , path ) ; } } // mark current node as unprocessed processed [ i ] [ j ] = false ; } // Function to search for given set of words in a boggle void searchBoggle ( char board [ ] [ N ] , vector < string > &input ) { // construct a boolean matrix to store whether a cell is processed or not bool processed [ M ] [ N ] { } ; // construct a set to store all possible words constructed from the matrix unordered_set < string > words ; // generate all possible words in a boggle for ( int i = 0 ; i < M ; i ++ ) { for ( int j = 0 ; j < N ; j ++ ) { // consider each character as a starting point and run DFS searchBoggle ( board , words , processed , i , j , "" ) ; } } // for each word in the input list, check whether it is present in the set for ( string word : input ) { if ( words . find ( word ) != words . end ( ) ) { cout << word << endl ; } } } int main ( ) { char board [ M ] [ N ] = { { 'M' , 'S' , 'E' , 'F' } , { 'R' , 'A' , 'T' , 'D' } , { 'L' , 'O' , 'N' , 'E' } } ; vector < string > words { "START" , "NOTE" , "SAND" , "STONED" } ; searchBoggle ( board , words ) ; return 0 ; } Download Run Code Output:



NOTE

SAND

STONED

Java import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; class Main { // M x N matrix private static int M, N; // Below arrays details all 8 possible movements from a cell // (top, right, bottom, left and 4 diagonal moves) public static int[] row = { -1, -1, -1, 0, 1, 0, 1, 1 }; public static int[] col = { -1, 1, 0, -1, -1, 1, 0, 1 }; // Function to check if it is safe to go to cell (x, y) from current cell. // The function returns false if (x, y) is not valid matrix coordinates // or cell (x, y) is already processed public static boolean isSafe(int x, int y, boolean[][] processed) { return (x >= 0 && x < M) && (y >= 0 && y < N) && !processed[x][y]; } // A recursive function to generate all possible words in a boggle public static void searchBoggle(char[][] board, Set<String> words, boolean[][] processed, int i, int j, String path) { // mark current node as processed processed[i][j] = true; // update the path with the current character and insert it into the set path = path + board[i][j]; words.add(path); // check for all 8 possible movements from the current cell for (int k = 0; k < 8; k++) { // skip if cell is invalid or it is already processed if (isSafe(i + row[k], j + col[k], processed)) { searchBoggle(board, words, processed, i + row[k], j + col[k], path); } } // mark current node as unprocessed processed[i][j] = false; } // Function to search for given set of words in a boggle public static void searchBoggle(char[][] board, List<String> input) { // construct a boolean matrix to store whether a cell is processed or not boolean[][] processed = new boolean[M][N]; // construct a set to store all possible words constructed from the matrix Set<String> words = new HashSet<>(); // generate all possible words in a boggle for (int i = 0; i < M; i++) { for (int j = 0; j < N; j++) { // consider each character as a starting point and run DFS searchBoggle(board, words, processed, i, j, ""); } } // for each word in the input list, check whether it is present in the set for (String word: input) { if (words.contains(word)) { System.out.println(word); } } } public static void main(String[] args) { char[][] board = { {'M', 'S', 'E'}, {'R', 'A', 'T'}, {'L', 'O', 'N'} }; M = board.length; N = board[0].length; List<String> words = Arrays.asList("STAR", "NOTE", "SAND", "STONE"); searchBoggle(board, words); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 import java . util . Arrays ; import java . util . HashSet ; import java . util . List ; import java . util . Set ; class Main { // M x N matrix private static int M , N ; // Below arrays details all 8 possible movements from a cell // (top, right, bottom, left and 4 diagonal moves) public static int [ ] row = { - 1 , - 1 , - 1 , 0 , 1 , 0 , 1 , 1 } ; public static int [ ] col = { - 1 , 1 , 0 , - 1 , - 1 , 1 , 0 , 1 } ; // Function to check if it is safe to go to cell (x, y) from current cell. // The function returns false if (x, y) is not valid matrix coordinates // or cell (x, y) is already processed public static boolean isSafe ( int x , int y , boolean [ ] [ ] processed ) { return ( x >= 0 && x < M ) && ( y >= 0 && y < N ) && ! processed [ x ] [ y ] ; } // A recursive function to generate all possible words in a boggle public static void searchBoggle ( char [ ] [ ] board , Set <String> words , boolean [ ] [ ] processed , int i , int j , String path ) { // mark current node as processed processed [ i ] [ j ] = true ; // update the path with the current character and insert it into the set path = path + board [ i ] [ j ] ; words . add ( path ) ; // check for all 8 possible movements from the current cell for ( int k = 0 ; k < 8 ; k ++ ) { // skip if cell is invalid or it is already processed if ( isSafe ( i + row [ k ] , j + col [ k ] , processed ) ) { searchBoggle ( board , words , processed , i + row [ k ] , j + col [ k ] , path ) ; } } // mark current node as unprocessed processed [ i ] [ j ] = false ; } // Function to search for given set of words in a boggle public static void searchBoggle ( char [ ] [ ] board , List <String> input ) { // construct a boolean matrix to store whether a cell is processed or not boolean [ ] [ ] processed = new boolean [ M ] [ N ] ; // construct a set to store all possible words constructed from the matrix Set <String> words = new HashSet <> ( ) ; // generate all possible words in a boggle for ( int i = 0 ; i < M ; i ++ ) { for ( int j = 0 ; j < N ; j ++ ) { // consider each character as a starting point and run DFS searchBoggle ( board , words , processed , i , j , "" ) ; } } // for each word in the input list, check whether it is present in the set for ( String word : input ) { if ( words . contains ( word ) ) { System . out . println ( word ) ; } } } public static void main ( String [ ] args ) { char [ ] [ ] board = { { 'M' , 'S' , 'E' } , { 'R' , 'A' , 'T' } , { 'L' , 'O' , 'N' } } ; M = board . length ; N = board [ 0 ] . length ; List <String> words = Arrays . asList ( "STAR" , "NOTE" , "SAND" , "STONE" ) ; searchBoggle ( board , words ) ; } } Download Run Code Output:



STAR

NOTE

Python # Below lists details all 8 possible movements from a cell # (top, right, bottom, left and 4 diagonal moves) row = [-1, -1, -1, 0, 1, 0, 1, 1] col = [-1, 1, 0, -1, -1, 1, 0, 1] # Function to check if it is safe to go to cell (x, y) from current cell. # The function returns false if (x, y) is not valid matrix coordinates # or cell (x, y) is already processed def isSafe(x, y, processed): return (0 <= x < M) and (0 <= y < N) and not processed[x][y] # A recursive function to generate all possible words in a boggle def searchBoggle(board, words, processed, i, j, path=""): # mark current node as processed processed[i][j] = True # update the path with the current character and insert it into the set path = path + board[i][j] words.add(path) # check for all 8 possible movements from the current cell for k in range(8): # skip if cell is invalid or it is already processed if isSafe(i + row[k], j + col[k], processed): searchBoggle(board, words, processed, i + row[k], j + col[k], path) # mark current node as unprocessed processed[i][j] = False # Function to search for given set of words in a boggle def searchInBoggle(board, input): # construct a matrix to store whether a cell is processed or not processed = [[False for x in range(N)] for y in range(M)] # construct a set to store all possible words constructed from the matrix words = set() # generate all possible words in a boggle for i in range(M): for j in range(N): # consider each character as a starting point and run DFS searchBoggle(board, words, processed, i, j) # for each word in the input list, check whether it is present in the set print([word for word in input if word in words]) if __name__ == '__main__': board = [ ['M', 'S', 'E'], ['R', 'A', 'T'], ['L', 'O', 'N'] ] (M, N) = (len(board), len(board[0])) words = ["STAR", "NOTE", "SAND", "STONE"] searchInBoggle(board, words) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 # Below lists details all 8 possible movements from a cell # (top, right, bottom, left and 4 diagonal moves) row = [ - 1 , - 1 , - 1 , 0 , 1 , 0 , 1 , 1 ] col = [ - 1 , 1 , 0 , - 1 , - 1 , 1 , 0 , 1 ] # Function to check if it is safe to go to cell (x, y) from current cell. # The function returns false if (x, y) is not valid matrix coordinates # or cell (x, y) is already processed def isSafe ( x , y , processed ) : return ( 0 <= x < M ) and ( 0 <= y < N ) and not processed [ x ] [ y ] # A recursive function to generate all possible words in a boggle def searchBoggle ( board , words , processed , i , j , path = "" ) : # mark current node as processed processed [ i ] [ j ] = True # update the path with the current character and insert it into the set path = path + board [ i ] [ j ] words . add ( path ) # check for all 8 possible movements from the current cell for k in range ( 8 ) : # skip if cell is invalid or it is already processed if isSafe ( i + row [ k ] , j + col [ k ] , processed ) : searchBoggle ( board , words , processed , i + row [ k ] , j + col [ k ] , path ) # mark current node as unprocessed processed [ i ] [ j ] = False # Function to search for given set of words in a boggle def searchInBoggle ( board , input ) : # construct a matrix to store whether a cell is processed or not processed = [ [ False for x in range ( N ) ] for y in range ( M ) ] # construct a set to store all possible words constructed from the matrix words = set ( ) # generate all possible words in a boggle for i in range ( M ) : for j in range ( N ) : # consider each character as a starting point and run DFS searchBoggle ( board , words , processed , i , j ) # for each word in the input list, check whether it is present in the set print ( [ word for word in input if word in words ] ) if __name__ == '__main__' : board = [ [ 'M' , 'S' , 'E' ] , [ 'R' , 'A' , 'T' ] , [ 'L' , 'O' , 'N' ] ] ( M , N ) = ( len ( board ) , len ( board [ 0 ] ) ) words = [ "STAR" , "NOTE" , "SAND" , "STONE" ] searchInBoggle ( board , words ) Download Run Code Output:



[‘STAR’, ‘NOTE’]







The time complexity of above solution is exponential. We can improve the time complexity by using a trie data structure. The idea is to build a trie out of the given words and then perform pre-order traversal (DFS) on it as shown below:

C++ #include <iostream> #include <unordered_map> #include <unordered_set> #include <string> #include <vector> using namespace std; // M x N matrix #define M 4 #define N 4 // A Trie node struct Trie { // true when node is a leaf node bool isLeaf; unordered_map<char, Trie*> character; // Constructor Trie() { isLeaf = false; } }; // Iterative function to insert a string into a Trie void insert(Trie* const &root, string const &str) { // start from the root node Trie* curr = root; for (char ch: str) { // create a new node if path doesn't exists if (curr->character.find(ch) == curr->character.end()) { curr->character[ch] = new Trie(); } // go to the next node curr = curr->character[ch]; } curr->isLeaf = true; } // Below arrays details all 8 possible movements from a cell // (top, right, bottom, left and 4 diagonal moves) int row[] = { -1, -1, -1, 0, 1, 0, 1, 1 }; int col[] = { -1, 1, 0, -1, -1, 1, 0, 1 }; // The function returns false if (x, y) is not valid matrix coordinates // or cell (x, y) is already processed or doesn't lead to the solution bool isSafe(int x, int y, bool processed[][N], char board[][N], char ch) { return (x >= 0 && x < M) && (y >= 0 && y < N) && !processed[x][y] && (board[x][y] == ch); } // A recursive function to search valid words present in a boggle using trie void searchBoggle(Trie *root, char board[][N], int i, int j, bool processed[][N], string path, unordered_set<string> &result) { // if leaf node is encountered if (root->isLeaf) { // update result with the current word result.insert(path); } // mark current cell as processed processed[i][j] = true; // traverse all children of the current Trie node for (auto it : root->character) { // check for all 8 possible movements from current cell for (int k = 0; k < 8; k++) { // skip if cell is invalid or it is already processed // or doesn't lead to any path in the Trie if (isSafe(i + row[k], j + col[k], processed, board, it.first)) { searchBoggle(it.second, board, i + row[k], j + col[k], processed, path + it.first, result); } } } // mark current cell as unprocessed processed[i][j] = false; } // Function to search for given set of words in a boggle void searchBoggle(char board[][N], vector<string> words) { // insert all words into a trie Trie* root = new Trie(); for (string word: words) { insert(root, word); } // construct a set for storing the result unordered_set<string> result; // construct a boolean matrix to store whether a cell is processed or not bool processed[M][N] {}; std::string s; // consider each character in the matrix for (int i = 0 ; i < M; i++) { for (int j = 0 ; j < N ; j++) { // current character char ch = board[i][j]; // proceed only if current character is child of the Trie root node if (root->character[ch]) { s = ch; searchBoggle(root->character[ch], board, i, j, processed, s, result); } } } // print each word in the result set for (string word: result) { cout << word << endl; } } int main() { char board[M][N] = { {'M', 'S', 'E', 'F'}, {'R', 'A', 'T', 'D'}, {'L', 'O', 'N', 'E'}, {'K', 'A', 'F', 'B'} }; vector<string> words { "START", "NOTE", "SAND", "STONED" }; searchBoggle(board, words); return 0; } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 #include <iostream> #include <unordered_map> #include <unordered_set> #include <string> #include <vector> using namespace std ; // M x N matrix #define M 4 #define N 4 // A Trie node struct Trie { // true when node is a leaf node bool isLeaf ; unordered_map < char , Trie * > character ; // Constructor Trie ( ) { isLeaf = false ; } } ; // Iterative function to insert a string into a Trie void insert ( Trie * const &root , string const &str ) { // start from the root node Trie * curr = root ; for ( char ch : str ) { // create a new node if path doesn't exists if ( curr -> character . find ( ch ) == curr -> character . end ( ) ) { curr -> character [ ch ] = new Trie ( ) ; } // go to the next node curr = curr -> character [ ch ] ; } curr -> isLeaf = true ; } // Below arrays details all 8 possible movements from a cell // (top, right, bottom, left and 4 diagonal moves) int row [ ] = { - 1 , - 1 , - 1 , 0 , 1 , 0 , 1 , 1 } ; int col [ ] = { - 1 , 1 , 0 , - 1 , - 1 , 1 , 0 , 1 } ; // The function returns false if (x, y) is not valid matrix coordinates // or cell (x, y) is already processed or doesn't lead to the solution bool isSafe ( int x , int y , bool processed [ ] [ N ] , char board [ ] [ N ] , char ch ) { return ( x >= 0 && x < M ) && ( y >= 0 && y < N ) && ! processed [ x ] [ y ] && ( board [ x ] [ y ] == ch ) ; } // A recursive function to search valid words present in a boggle using trie void searchBoggle ( Trie * root , char board [ ] [ N ] , int i , int j , bool processed [ ] [ N ] , string path , unordered_set < string > &result ) { // if leaf node is encountered if ( root -> isLeaf ) { // update result with the current word result . insert ( path ) ; } // mark current cell as processed processed [ i ] [ j ] = true ; // traverse all children of the current Trie node for ( auto it : root -> character ) { // check for all 8 possible movements from current cell for ( int k = 0 ; k < 8 ; k ++ ) { // skip if cell is invalid or it is already processed // or doesn't lead to any path in the Trie if ( isSafe ( i + row [ k ] , j + col [ k ] , processed , board , it . first ) ) { searchBoggle ( it . second , board , i + row [ k ] , j + col [ k ] , processed , path + it . first , result ) ; } } } // mark current cell as unprocessed processed [ i ] [ j ] = false ; } // Function to search for given set of words in a boggle void searchBoggle ( char board [ ] [ N ] , vector < string > words ) { // insert all words into a trie Trie * root = new Trie ( ) ; for ( string word : words ) { insert ( root , word ) ; } // construct a set for storing the result unordered_set < string > result ; // construct a boolean matrix to store whether a cell is processed or not bool processed [ M ] [ N ] { } ; std :: string s ; // consider each character in the matrix for ( int i = 0 ; i < M ; i ++ ) { for ( int j = 0 ; j < N ; j ++ ) { // current character char ch = board [ i ] [ j ] ; // proceed only if current character is child of the Trie root node if ( root -> character [ ch ] ) { s = ch ; searchBoggle ( root -> character [ ch ] , board , i , j , processed , s , result ) ; } } } // print each word in the result set for ( string word : result ) { cout << word << endl ; } } int main ( ) { char board [ M ] [ N ] = { { 'M' , 'S' , 'E' , 'F' } , { 'R' , 'A' , 'T' , 'D' } , { 'L' , 'O' , 'N' , 'E' } , { 'K' , 'A' , 'F' , 'B' } } ; vector < string > words { "START" , "NOTE" , "SAND" , "STONED" } ; searchBoggle ( board , words ) ; return 0 ; } Download Run Code Output:



STONED

NOTE

SAND

Java import java.util.*; // A Trie node class Trie { // true when node is a leaf node boolean isLeaf; Map<Character, Trie> character = new HashMap<>(); // Constructor Trie() { isLeaf = false; } } class Main { // M x N matrix private static int M, N; // Iterative function to insert a String into a Trie private static void insert(Trie root, String str) { // start from the root node Trie curr = root; for (char ch: str.toCharArray()) { // create a new node if path doesn't exists curr.character.putIfAbsent(ch, new Trie()); // go to the next node curr = curr.character.get(ch); } curr.isLeaf = true; } // Below arrays details all 8 possible movements from a cell // (top, right, bottom, left and 4 diagonal moves) private static int[] row = { -1, -1, -1, 0, 1, 0, 1, 1 }; private static int[] col = { -1, 1, 0, -1, -1, 1, 0, 1 }; // The function returns false if (x, y) is not valid matrix coordinates // or cell (x, y) is already processed or doesn't lead to the solution public static boolean isSafe(int x, int y, boolean[][] processed, char[][] board, char ch) { return (x >= 0 && x < M) && (y >= 0 && y < N) && !processed[x][y] && (board[x][y] == ch); } // A recursive function to search valid words present in a boggle using trie public static void searchBoggle(Trie root, char[][] board, int i, int j, boolean[][] processed, String path, Set<String> result) { // if leaf node is encountered if (root.isLeaf) { // update result with the current word result.add(path); } // mark current cell as processed processed[i][j] = true; // traverse all children of the current Trie node for (var entry : root.character.entrySet()) { // check for all 8 possible movements from current cell for (int k = 0; k < 8; k++) { // skip if cell is invalid or entry is already processed // or doesn't lead to any path in the Trie if (isSafe(i + row[k], j + col[k], processed, board, entry.getKey())) { searchBoggle(entry.getValue(), board, i + row[k], j + col[k], processed, path + entry.getKey(), result); } } } // mark current cell as unprocessed processed[i][j] = false; } // Function to search for given set of words in a boggle public static void searchBoggle(char[][] board, List<String> words) { // insert all words into a trie Trie root = new Trie(); for (String word: words) { insert(root, word); } // construct a set for storing the result Set<String> result = new HashSet<>(); // construct a boolean matrix to store whether a cell is processed or not boolean[][] processed = new boolean[M][N]; // consider each character in the matrix for (int i = 0 ; i < M; i++) { for (int j = 0 ; j < N ; j++) { // current character char ch = board[i][j]; // proceed only if current character is child of the Trie root node if (root.character.containsKey(ch)) { searchBoggle(root.character.get(ch), board, i, j, processed, Character.toString(ch), result); } } } // print each word in the result set System.out.println(result); } public static void main(String[] args) { char[][] board = { {'M', 'S', 'E', 'F'}, {'R', 'A', 'T', 'D'}, {'L', 'O', 'N', 'E'}, {'K', 'A', 'F', 'B'} }; M = board.length; N = board[0].length; List<String> words = Arrays.asList("START", "NOTE", "SAND", "STONED"); searchBoggle(board, words); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 import java . util . * ; // A Trie node class Trie { // true when node is a leaf node boolean isLeaf ; Map < Character , Trie > character = new HashMap <> ( ) ; // Constructor Trie ( ) { isLeaf = false ; } } class Main { // M x N matrix private static int M , N ; // Iterative function to insert a String into a Trie private static void insert ( Trie root , String str ) { // start from the root node Trie curr = root ; for ( char ch : str . toCharArray ( ) ) { // create a new node if path doesn't exists curr . character . putIfAbsent ( ch , new Trie ( ) ) ; // go to the next node curr = curr . character . get ( ch ) ; } curr . isLeaf = true ; } // Below arrays details all 8 possible movements from a cell // (top, right, bottom, left and 4 diagonal moves) private static int [ ] row = { - 1 , - 1 , - 1 , 0 , 1 , 0 , 1 , 1 } ; private static int [ ] col = { - 1 , 1 , 0 , - 1 , - 1 , 1 , 0 , 1 } ; // The function returns false if (x, y) is not valid matrix coordinates // or cell (x, y) is already processed or doesn't lead to the solution public static boolean isSafe ( int x , int y , boolean [ ] [ ] processed , char [ ] [ ] board , char ch ) { return ( x >= 0 && x < M ) && ( y >= 0 && y < N ) && ! processed [ x ] [ y ] && ( board [ x ] [ y ] == ch ) ; } // A recursive function to search valid words present in a boggle using trie public static void searchBoggle ( Trie root , char [ ] [ ] board , int i , int j , boolean [ ] [ ] processed , String path , Set <String> result ) { // if leaf node is encountered if ( root . isLeaf ) { // update result with the current word result . add ( path ) ; } // mark current cell as processed processed [ i ] [ j ] = true ; // traverse all children of the current Trie node for ( var entry : root . character . entrySet ( ) ) { // check for all 8 possible movements from current cell for ( int k = 0 ; k < 8 ; k ++ ) { // skip if cell is invalid or entry is already processed // or doesn't lead to any path in the Trie if ( isSafe ( i + row [ k ] , j + col [ k ] , processed , board , entry . getKey ( ) ) ) { searchBoggle ( entry . getValue ( ) , board , i + row [ k ] , j + col [ k ] , processed , path + entry . getKey ( ) , result ) ; } } } // mark current cell as unprocessed processed [ i ] [ j ] = false ; } // Function to search for given set of words in a boggle public static void searchBoggle ( char [ ] [ ] board , List <String> words ) { // insert all words into a trie Trie root = new Trie ( ) ; for ( String word : words ) { insert ( root , word ) ; } // construct a set for storing the result Set <String> result = new HashSet <> ( ) ; // construct a boolean matrix to store whether a cell is processed or not boolean [ ] [ ] processed = new boolean [ M ] [ N ] ; // consider each character in the matrix for ( int i = 0 ; i < M ; i ++ ) { for ( int j = 0 ; j < N ; j ++ ) { // current character char ch = board [ i ] [ j ] ; // proceed only if current character is child of the Trie root node if ( root . character . containsKey ( ch ) ) { searchBoggle ( root . character . get ( ch ) , board , i , j , processed , Character . toString ( ch ) , result ) ; } } } // print each word in the result set System . out . println ( result ) ; } public static void main ( String [ ] args ) { char [ ] [ ] board = { { 'M' , 'S' , 'E' , 'F' } , { 'R' , 'A' , 'T' , 'D' } , { 'L' , 'O' , 'N' , 'E' } , { 'K' , 'A' , 'F' , 'B' } } ; M = board . length ; N = board [ 0 ] . length ; List <String> words = Arrays . asList ( "START" , "NOTE" , "SAND" , "STONED" ) ; searchBoggle ( board , words ) ; } } Download Run Code Output:



[SAND, NOTE, STONED]

Python # A Trie node class Trie: # Constructor def __init__(self): self.character = {} self.isLeaf = False # true when node is a leaf node # Iterative function to insert a String into a Trie def insert(root, str): # start from the root node curr = root for ch in str: # go to the next node (create if path doesn't exists) curr = curr.character.setdefault(ch, Trie()) curr.isLeaf = True # Below lists details all 8 possible movements from a cell # (top, right, bottom, left and 4 diagonal moves) row = [-1, -1, -1, 0, 1, 0, 1, 1] col = [-1, 1, 0, -1, -1, 1, 0, 1] # The function returns false if (x, y) is not valid matrix coordinates # or cell (x, y) is already processed or doesn't lead to the solution def isSafe(x, y, processed, board, ch): return (0 <= x < M) and (0 <= y < N) and \ not processed[x][y] and (board[x][y] == ch) # A recursive function to search valid words present in a boggle using trie def searchBoggle(root, board, i, j, processed, path, result): # if leaf node is encountered if root.isLeaf: # update result with the current word result.add(path) # mark current cell as processed processed[i][j] = True # traverse all children of the current Trie node for key, value in root.character.items(): # check for all 8 possible movements from current cell for k in range(8): # skip if cell is invalid or it is already processed # or doesn't lead to any path in the Trie if isSafe(i + row[k], j + col[k], processed, board, key): searchBoggle(value, board, i + row[k], j + col[k], processed, path + key, result) # mark current cell as unprocessed processed[i][j] = False # Function to search for given set of words in a boggle def searchInBoggle(board, words): # insert all words into a trie root = Trie() for word in words: insert(root, word) # construct a set for storing the result result = set() # construct a matrix to store whether a cell is processed or not processed = [[False for x in range(N)] for y in range(M)] # consider each character in the matrix for i in range(M): for j in range(N): ch = board[i][j] # current character # proceed only if current character is child of the Trie root node if ch in root.character: searchBoggle(root.character[ch], board, i, j, processed, ch, result) # print each word in the result set print(result) if __name__ == '__main__': board = [ ['M', 'S', 'E', 'F'], ['R', 'A', 'T', 'D'], ['L', 'O', 'N', 'E'], ['K', 'A', 'F', 'B'] ] (M, N) = (len(board), len(board[0])) words = ["START", "NOTE", "SAND", "STONED"] searchInBoggle(board, words) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 # A Trie node class Trie : # Constructor def __init__ ( self ) : self . character = { } self . isLeaf = False # true when node is a leaf node # Iterative function to insert a String into a Trie def insert ( root , str ) : # start from the root node curr = root for ch in str : # go to the next node (create if path doesn't exists) curr = curr . character . setdefault ( ch , Trie ( ) ) curr . isLeaf = True # Below lists details all 8 possible movements from a cell # (top, right, bottom, left and 4 diagonal moves) row = [ - 1 , - 1 , - 1 , 0 , 1 , 0 , 1 , 1 ] col = [ - 1 , 1 , 0 , - 1 , - 1 , 1 , 0 , 1 ] # The function returns false if (x, y) is not valid matrix coordinates # or cell (x, y) is already processed or doesn't lead to the solution def isSafe ( x , y , processed , board , ch ) : return ( 0 <= x < M ) and ( 0 <= y < N ) and \ not processed [ x ] [ y ] and ( board [ x ] [ y ] == ch ) # A recursive function to search valid words present in a boggle using trie def searchBoggle ( root , board , i , j , processed , path , result ) : # if leaf node is encountered if root . isLeaf : # update result with the current word result . add ( path ) # mark current cell as processed processed [ i ] [ j ] = True # traverse all children of the current Trie node for key , value in root . character . items ( ) : # check for all 8 possible movements from current cell for k in range ( 8 ) : # skip if cell is invalid or it is already processed # or doesn't lead to any path in the Trie if isSafe ( i + row [ k ] , j + col [ k ] , processed , board , key ) : searchBoggle ( value , board , i + row [ k ] , j + col [ k ] , processed , path + key , result ) # mark current cell as unprocessed processed [ i ] [ j ] = False # Function to search for given set of words in a boggle def searchInBoggle ( board , words ) : # insert all words into a trie root = Trie ( ) for word in words : insert ( root , word ) # construct a set for storing the result result = set ( ) # construct a matrix to store whether a cell is processed or not processed = [ [ False for x in range ( N ) ] for y in range ( M ) ] # consider each character in the matrix for i in range ( M ) : for j in range ( N ) : ch = board [ i ] [ j ] # current character # proceed only if current character is child of the Trie root node if ch in root . character : searchBoggle ( root . character [ ch ] , board , i , j , processed , ch , result ) # print each word in the result set print ( result ) if __name__ == '__main__' : board = [ [ 'M' , 'S' , 'E' , 'F' ] , [ 'R' , 'A' , 'T' , 'D' ] , [ 'L' , 'O' , 'N' , 'E' ] , [ 'K' , 'A' , 'F' , 'B' ] ] ( M , N ) = ( len ( board ) , len ( board [ 0 ] ) ) words = [ "START" , "NOTE" , "SAND" , "STONED" ] searchInBoggle ( board , words ) Download Run Code Output:



{‘STONED’, ‘SAND’, ‘NOTE’}













(18 votes, average: 4.78 out of 5)

Loading...

Thanks for reading.