Introduction

A trie is a tree-like data structure that stores a dynamic set of strings, where the keys are usually strings. In practice, tries are used to facilitate operations on strings, such as searching and prefix matching.

Implementation

Dictionary Implementation

class Trie:
    # https://github.com/cheran-senthil/PyRival/blob/master/pyrival/data_structures/Trie.py
    def __init__(self, *words):
        self.root = dict()
        for word in words:
            self.add(word)
 
    def add(self, word):
        current_dict = self.root
        for letter in word:
            current_dict = current_dict.setdefault(letter, dict())
        current_dict["_end_"] = True
 
    def __contains__(self, word):
        current_dict = self.root
        for letter in word:
            if letter not in current_dict:
                return False
            current_dict = current_dict[letter]
        return "_end_" in current_dict
 
    def delete(self, word, prune=False):
        current_dict = self.root
        nodes = [current_dict]
        objects = []
        for letter in word:
            current_dict = current_dict[letter]
            nodes.append(current_dict)
            objects.append(current_dict)
 
        del current_dict["_end_"]
 
        if prune:
            # https://leetcode.com/problems/maximum-genetic-difference-query/discuss/1344900/
            for c, obj in zip(word[::-1], objects[:-1][::-1]):
                if not obj[c]:
                    del obj[c]
                else:
                    break
 
        # assert word not in self  # confirm that the number has been removed

Defaultdict Implementation

class TrieNode:
    def __init__(self):
        self.children = defaultdict(TrieNode)
        self.hasEnd = False
 
class Trie:
    def __init__(self):
        self.root = TrieNode()
 
    def insert(self, word: str) -> None:
        curr = self.root
 
        for x in word:
            curr = curr.children[x]
 
        curr.hasEnd = True
 
    def search(self, word: str) -> bool:
        curr = self.root
 
        for x in word:
            if x not in curr.children:
                return False
 
            curr = curr.children[x]
 
        return curr.hasEnd
 
    def startsWith(self, prefix: str) -> bool:
        curr = self.root
 
        for x in prefix:
            if x not in curr.children:
                return False
 
            curr = curr.children[x]
 
        return True