54.实现 Trie (前缀树)

57 阅读1分钟

题目链接

Trie(发音类似 "try")或者说 前缀树 是一种树形数据结构,用于高效地存储和检索字符串数据集中的键。这一数据结构有相当多的应用情景,例如自动补全和拼写检查。

请你实现 Trie 类:

  • Trie() 初始化前缀树对象。
  • void insert(String word) 向前缀树中插入字符串 word 。
  • boolean search(String word) 如果字符串 word 在前缀树中,返回 true(即,在检索之前已经插入);否则,返回 false 。
  • boolean startsWith(String prefix) 如果之前已经插入的字符串 word 的前缀之一为 prefix ,返回 true ;否则,返回 false 。

解法 数组和ascii码实现

思路

利用 ascii 码的特性算出数组的 index

代码

const CHAR_CODE_A = "a".charCodeAt(0);
function toIndex(char: string): number {
    return char.charCodeAt(0) - CHAR_CODE_A;
}

class TrieNode {
    children: Array<TrieNode | null>;
    isEnd: boolean;
    constructor() {
        this.children = new Array(26).fill(null);
        this.isEnd = false;
    }
}

class Trie {
    private root: TrieNode;
    constructor() {
        this.root = new TrieNode();
    }

    insert(word: string): void {
        let node = this.root;

        for (let i = 0; i < word.length; i++) {
            const index = toIndex(word[i]);

            if (!node.children[index]) {
                node.children[index] = new TrieNode();
            }
            node = node.children[index];
        }
        node.isEnd = true;
    }

    search(word: string): boolean {
        let node = this.root;

        for (let i = 0; i < word.length; i++) {
            const index = toIndex(word[i]);

            if (!node.children[index]) {
                return false;
            }
            node = node.children[index];
        }
        return node.isEnd;
    }

    startsWith(prefix: string): boolean {
        let node = this.root;

        for (let i = 0; i < prefix.length; i++) {
            const index = toIndex(prefix[i]);

            if (!node.children[index]) {
                return false;
            }
            node = node.children[index];
        }
        return true;
    }
}

解法2 map实现

思路

方法的整体逻辑和数组实现一样,只不过换了底层的数据结构,map 适合存储稀疏的数据。

代码

class TrieNode {
    children: Map<string, TrieNode>;
    isEnd: boolean;
    constructor() {
        this.children = new Map();
        this.isEnd = false;
    }
}

class Trie {
    private root: TrieNode;
    constructor() {
        this.root = new TrieNode();
    }

    insert(word: string): void {
        let node = this.root;

        for (let char of word) {
            if (!node.children.has(char)) {
                node.children.set(char, new TrieNode());
            }
            node = node.children.get(char);
        }

        node.isEnd = true;
    }

    search(word: string): boolean {
        let node = this.root;

        for (let char of word) {
            if (!node.children.has(char)) {
                return false;
            }
            node = node.children.get(char);
        }

        return node.isEnd;
    }

    startsWith(prefix: string): boolean {
        let node = this.root;

        for (let char of prefix) {
            if (!node.children.has(char)) {
                return false;
            }
            node = node.children.get(char);
        }

        return true;
    }
}