Programming & Development / April 10, 2025

🔢 Problem 211. Add and Search Word - Data structure design

Trie DFS Backtracking Design Go

🧩 Problem Statement

Design a data structure that supports adding new words and searching for a string, where . can represent any letter.

Implement the WordDictionary class:

go

type WordDictionary struct {
    // implement
}

func Constructor() WordDictionary
func (this *WordDictionary) AddWord(word string)
func (this *WordDictionary) Search(word string) bool
  • AddWord(word) adds word to the data structure.
  • Search(word) returns true if word matches any previously added word. A word could contain the dot character '.' to represent any one letter.

🧪 Example

go

Input:
["WordDictionary","addWord","addWord","addWord","search","search","search","search"]
[[],["bad"],["dad"],["mad"],["pad"],["bad"],[".ad"],["b.."]]

Output:
[null,null,null,null,false,true,true,true]

🧠 Approach

We use a Trie (Prefix Tree) to store words efficiently.

To handle . in search:

  • Traverse all child nodes recursively when . is encountered.
  • For regular characters, just follow the matching child.

✅ Go Implementation

go

package main

import "fmt"

type TrieNode struct {
    children map[rune]*TrieNode
    isEnd    bool
}

type WordDictionary struct {
    root *TrieNode
}

func Constructor() WordDictionary {
    return WordDictionary{root: &TrieNode{children: make(map[rune]*TrieNode)}}
}

func (this *WordDictionary) AddWord(word string) {
    node := this.root
    for _, ch := range word {
        if _, ok := node.children[ch]; !ok {
            node.children[ch] = &TrieNode{children: make(map[rune]*TrieNode)}
        }
        node = node.children[ch]
    }
    node.isEnd = true
}

func (this *WordDictionary) Search(word string) bool {
    return dfs(this.root, []rune(word), 0)
}

func dfs(node *TrieNode, word []rune, index int) bool {
    if index == len(word) {
        return node.isEnd
    }

    ch := word[index]
    if ch == '.' {
        for _, child := range node.children {
            if dfs(child, word, index+1) {
                return true
            }
        }
        return false
    }

    if child, ok := node.children[ch]; ok {
        return dfs(child, word, index+1)
    }

    return false
}

📦 Example Usage

go

func main() {
    dict := Constructor()
    dict.AddWord("bad")
    dict.AddWord("dad")
    dict.AddWord("mad")

    fmt.Println(dict.Search("pad")) // false
    fmt.Println(dict.Search("bad")) // true
    fmt.Println(dict.Search(".ad")) // true
    fmt.Println(dict.Search("b..")) // true
}

⏱️ Complexity

  • AddWord
  • Time: O(n), where n is length of the word.
  • Search
  • Worst-case Time: O(26^d), where d is the length of the word and all characters are ..
  • Space: O(N * L) where N is number of words and L is average word length.

🧠 Key Concepts

  • Trie traversal
  • Recursive DFS for wildcard search
  • Dot . as wildcard character

Let me know if you want a Breadth-First Search (BFS) variation or a version with memory optimization tips!


Comments

No comments yet

Add a new Comment

NUHMAN.COM

Information Technology website for Programming & Development, Web Design & UX/UI, Startups & Innovation, Gadgets & Consumer Tech, Cloud Computing & Enterprise Tech, Cybersecurity, Artificial Intelligence (AI) & Machine Learning (ML), Gaming Technology, Mobile Development, Tech News & Trends, Open Source & Linux, Data Science & Analytics

Categories

Tags

©{" "} Nuhmans.com . All Rights Reserved. Designed by{" "} HTML Codex