Skip to content
Text Size

Tries

Java solutions with explanations, time and space complexity for Tries problems.

-- min read

Trie Pattern

Tries (Prefix Trees) are tree-like data structures used to store and retrieve strings. They’re particularly useful for:

  • Autocomplete features
  • Spell checkers
  • IP routing tables
  • Dictionary implementations
  • Prefix-based searches

1. Implement Trie (Prefix Tree) (Medium)

Problem: Implement a Trie data structure with insert, search, and startsWith methods.

Solution:

class Trie {
    private class TrieNode {
        private TrieNode[] children;
        private boolean isEndOfWord;
        
        public TrieNode() {
            children = new TrieNode[26];
            isEndOfWord = false;
        }
    }
    
    private TrieNode root;
    
    public Trie() {
        root = new TrieNode();
    }
    
    public void insert(String word) {
        TrieNode current = root;
        
        for (char c : word.toCharArray()) {
            int index = c - 'a';
            if (current.children[index] == null) {
                current.children[index] = new TrieNode();
            }
            current = current.children[index];
        }
        
        current.isEndOfWord = true;
    }
    
    public boolean search(String word) {
        TrieNode node = searchPrefix(word);
        return node != null && node.isEndOfWord;
    }
    
    public boolean startsWith(String prefix) {
        return searchPrefix(prefix) != null;
    }
    
    private TrieNode searchPrefix(String prefix) {
        TrieNode current = root;
        
        for (char c : prefix.toCharArray()) {
            int index = c - 'a';
            if (current.children[index] == null) {
                return null;
            }
            current = current.children[index];
        }
        
        return current;
    }
}

Time Complexity:

  • insert: O(m) where m is the word length
  • search: O(m) where m is the word length
  • startsWith: O(m) where m is the prefix length Space Complexity: O(ALPHABET_SIZE * N * M) where N is the number of words and M is the average word length

2. Design Add and Search Words Data Structure (Medium)

Problem: Design a data structure that supports adding new words and finding if a string matches any previously added string. The ’.’ character can match any single character.

Solution:

class WordDictionary {
    private class TrieNode {
        private TrieNode[] children;
        private boolean isEndOfWord;
        
        public TrieNode() {
            children = new TrieNode[26];
            isEndOfWord = false;
        }
    }
    
    private TrieNode root;
    
    public WordDictionary() {
        root = new TrieNode();
    }
    
    public void addWord(String word) {
        TrieNode current = root;
        
        for (char c : word.toCharArray()) {
            int index = c - 'a';
            if (current.children[index] == null) {
                current.children[index] = new TrieNode();
            }
            current = current.children[index];
        }
        
        current.isEndOfWord = true;
    }
    
    public boolean search(String word) {
        return searchInNode(word, 0, root);
    }
    
    private boolean searchInNode(String word, int index, TrieNode node) {
        if (node == null) return false;
        if (index == word.length()) return node.isEndOfWord;
        
        char c = word.charAt(index);
        if (c == '.') {
            for (TrieNode child : node.children) {
                if (child != null && searchInNode(word, index + 1, child)) {
                    return true;
                }
            }
            return false;
        } else {
            return searchInNode(word, index + 1, node.children[c - 'a']);
        }
    }
}

Time Complexity:

  • addWord: O(m) where m is the word length
  • search: O(26^m) in worst case where m is the word length (when word contains only ’.’ characters) Space Complexity: O(ALPHABET_SIZE * N * M) where N is the number of words and M is the average word length

3. Word Search II (Hard)

Problem: Given an m x n board of characters and a list of strings words, return all words on the board. Each word must be constructed from letters of sequentially adjacent cells, where adjacent cells are horizontally or vertically neighboring.

Solution:

class Solution {
    private class TrieNode {
        private TrieNode[] children;
        private String word;
        
        public TrieNode() {
            children = new TrieNode[26];
            word = null;
        }
    }
    
    private TrieNode root;
    private List<String> result;
    
    public List<String> findWords(char[][] board, String[] words) {
        root = new TrieNode();
        result = new ArrayList<>();
        
        // Build Trie
        for (String word : words) {
            TrieNode current = root;
            for (char c : word.toCharArray()) {
                int index = c - 'a';
                if (current.children[index] == null) {
                    current.children[index] = new TrieNode();
                }
                current = current.children[index];
            }
            current.word = word;
        }
        
        // Search in board
        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board[0].length; j++) {
                dfs(board, i, j, root);
            }
        }
        
        return result;
    }
    
    private void dfs(char[][] board, int i, int j, TrieNode node) {
        char c = board[i][j];
        if (c == '#' || node.children[c - 'a'] == null) return;
        
        node = node.children[c - 'a'];
        if (node.word != null) {
            result.add(node.word);
            node.word = null; // Avoid duplicates
        }
        
        board[i][j] = '#'; // Mark as visited
        
        if (i > 0) dfs(board, i - 1, j, node);
        if (j > 0) dfs(board, i, j - 1, node);
        if (i < board.length - 1) dfs(board, i + 1, j, node);
        if (j < board[0].length - 1) dfs(board, i, j + 1, node);
        
        board[i][j] = c; // Backtrack
    }
}

Time Complexity: O(m * n * 4^L) where m and n are board dimensions and L is the maximum word length Space Complexity: O(ALPHABET_SIZE * N * M) where N is the number of words and M is the average word length

Key Takeaways

  1. Trie is perfect for:

    • String operations
    • Prefix-based searches
    • Autocomplete features
    • Spell checking
    • Dictionary implementations
  2. Common patterns:

    • Node structure with children array/map
    • End of word marker
    • Prefix-based traversal
    • Backtracking with DFS
    • Character to index mapping
  3. Tips:

    • Consider space optimization (using HashMap instead of array)
    • Handle special characters (like ’.’ in wildcard matching)
    • Use backtracking for board-based problems
    • Consider memory usage for large datasets
    • Implement proper cleanup for memory management
Was this helpful?
Found an issue? Report it
GA

Gaurav Aryal

Building scalable systems and products. Passionate about distributed systems, backend architecture, and sharing what I learn.

Comments

Keyboard Shortcuts

Navigation

j Next post
k Previous post
h Go home

Actions

/ Open search
? Show shortcuts
Esc Close modal