diff --git a/java/Tries/DesignATrie.java b/java/Tries/DesignATrie.java new file mode 100644 index 0000000..3c67581 --- /dev/null +++ b/java/Tries/DesignATrie.java @@ -0,0 +1,60 @@ +import java.util.HashMap; +import java.util.Map; + +class TrieNode { + Map children; + boolean isWord; + public TrieNode() { + this.children = new HashMap<>(); + this.isWord = false; + } +} + +public class DesignATrie { + TrieNode root; + + public DesignATrie() { + this.root = new TrieNode(); + } + + public void insert(String word) { + TrieNode node = this.root; + for (char c : word.toCharArray()) { + // For each character in the word, if it's not a child of + // the current node, create a new TrieNode for that + // character. + node.children.putIfAbsent(c, new TrieNode()); + node = node.children.get(c); + } + // Mark the last node as the end of a word. + node.isWord = true; + } + + public boolean search(String word) { + TrieNode node = this.root; + for (char c : word.toCharArray()) { + // For each character in the word, if it's not a child of + // the current node, the word doesn't exist in the Trie. + if (!node.children.containsKey(c)) { + return false; + } + node = node.children.get(c); + } + // Return whether the current node is marked as the end of the + // word. + return node.isWord; + } + + public boolean hasPrefix(String prefix) { + TrieNode node = this.root; + for (char c : prefix.toCharArray()) { + if (!node.children.containsKey(c)) { + return false; + } + node = node.children.get(c); + } + // Once we've traversed the nodes corresponding to each + // character in the prefix, return True. + return true; + } +} diff --git a/java/Tries/FindAllWordsOnABoard.java b/java/Tries/FindAllWordsOnABoard.java new file mode 100644 index 0000000..53a5fee --- /dev/null +++ b/java/Tries/FindAllWordsOnABoard.java @@ -0,0 +1,69 @@ +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +class TrieNode { + Map children; + String word; + public TrieNode() { + this.children = new HashMap<>(); + this.word = null; + } +} + +public class FindAllWordsOnABoard { + public List findAllWordsOnABoard(char[][] board, String[] words) { + TrieNode root = new TrieNode(); + // Insert every word into the trie. + for (String word : words) { + TrieNode node = root; + for (char c : word.toCharArray()) { + node.children.putIfAbsent(c, new TrieNode()); + node = node.children.get(c); + } + node.word = word; + } + List res = new ArrayList<>(); + // Start a DFS call from each cell of the board that contains a + // child of the root node, which represents the first letter of a + // word in the trie. + for (int r = 0; r < board.length; r++) { + for (int c = 0; c < board[0].length; c++) { + if (root.children.containsKey(board[r][c])) { + dfs(board, r, c, root.children.get(board[r][c]), res); + } + } + } + return res; + } + + private void dfs(char[][] board, int r, int c, TrieNode node, List res) { + // If the current node represents the end of a word, add the word to + // the result. + if (node.word != null) { + res.add(node.word); + // Ensure the current word is only added once. + node.word = null; + } + char temp = board[r][c]; + // Mark the current cell as visited. + board[r][c] = '#'; + // Explore all adjacent cells that correspond with a child of the + // current TrieNode. + int[][] dirs = new int[][]{{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; + for (int[] d : dirs) { + int nextR = r + d[0]; + int nextC = c + d[1]; + if (isWithinBounds(nextR, nextC, board) && node.children.containsKey(board[nextR][nextC])) { + dfs(board, nextR, nextC, node.children.get(board[nextR][nextC]), res); + } + } + // Backtrack by reverting the cell back to its original character. + board[r][c] = temp; + } + + private boolean isWithinBounds(int r, int c, char[][] board) { + return 0 <= r && r < board.length && 0 <= c && c < board[0].length; + } +} diff --git a/java/Tries/InsertAndSearchWordsWithWildcards.java b/java/Tries/InsertAndSearchWordsWithWildcards.java new file mode 100644 index 0000000..944c009 --- /dev/null +++ b/java/Tries/InsertAndSearchWordsWithWildcards.java @@ -0,0 +1,57 @@ +import java.util.HashMap; +import java.util.Map; + +class TrieNode { + Map children; + boolean isWord; + public TrieNode() { + this.children = new HashMap<>(); + this.isWord = false; + } +} + +public class InsertAndSearchWordsWithWildcards { + TrieNode root; + + public InsertAndSearchWordsWithWildcards() { + this.root = new TrieNode(); + } + + public void insert(String word) { + TrieNode node = this.root; + for (char c : word.toCharArray()) { + node.children.putIfAbsent(c, new TrieNode()); + node = node.children.get(c); + } + node.isWord = true; + } + + public boolean search(String word) { + // Start searching from the root of the trie. + return searchHelper(0, word, this.root); + } + + private boolean searchHelper(int wordIndex, String word, TrieNode node) { + for (int i = wordIndex; i < word.length(); i++) { + char c = word.charAt(i); + // If a wildcard character is encountered, recursively + // search for the rest of the word from each child node. + if (c == '.') { + for (TrieNode child : node.children.values()) { + // If a match is found, return true. + if (searchHelper(i + 1, word, child)) { + return true; + } + } + return false; + } else if (node.children.containsKey(c)) { + node = node.children.get(c); + } else { + return false; + } + } + // After processing the last character, return true if we've + // reached the end of a word. + return node.isWord; + } +}