学习记录:js算法(六十):实现 Trie (前缀树)

实现 Trie (前缀树)

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

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

解释
Trie trie = new Trie();
trie.insert("apple");
trie.search("apple");   // 返回 True
trie.search("app");     // 返回 False
trie.startsWith("app"); // 返回 True
trie.insert("app");
trie.search("app");     // 返回 True

思路一

class TrieNode {
    constructor() {
        this.children = {}; // 存储子节点
        this.isEndOfWord = false; // 标记是否为单词的结束
    }
}

class Trie {
    constructor() {
        this.root = new TrieNode(); // 初始化根节点
    }

    // 插入单词
    insert(word) {
        this._insertRecursive(this.root, word, 0);
    }

    _insertRecursive(node, word, index) {
        if (index === word.length) {
            node.isEndOfWord = true; // 记录单词的结束
            return;
        }

        const char = word[index];
        if (!node.children[char]) {
            node.children[char] = new TrieNode(); // 创建新节点
        }

        // 递归插入下一个字符
        this._insertRecursive(node.children[char], word, index + 1);
    }

    // 搜索单词
    search(word) {
        return this._searchRecursive(this.root, word, 0);
    }

    _searchRecursive(node, word, index) {
        if (index === word.length) {
            return node.isEndOfWord; // 检查是否到达单词的结束
        }

        const char = word[index];
        if (!node.children[char]) {
            return false; // 字符不存在,返回 false
        }

        // 递归搜索下一个字符
        return this._searchRecursive(node.children[char], word, index + 1);
    }

    // 检查前缀
    startsWith(prefix) {
        return this._startsWithRecursive(this.root, prefix, 0);
    }

    _startsWithRecursive(node, prefix, index) {
        if (index === prefix.length) {
            return true; // 前缀存在
        }

        const char = prefix[index];
        if (!node.children[char]) {
            return false; // 字符不存在,返回 false
        }

        // 递归检查下一个字符
        return this._startsWithRecursive(node.children[char], prefix, index + 1);
    }
}

讲解

  1. TrieNode 类:表示每个节点,包含一个 children 对象(用于存储子节点)和一个 isEndOfWord 布尔值(标记是否为单词的结束)。
  2. Trie 类:包含根节点并实现了插入、搜索和前缀检查的方法。
    insert 方法通过 _insertRecursive 递归地插入每个字符。
    search 方法通过 _searchRecursive 检查单词是否存在。
    startsWith 方法通过 _startsWithRecursive 检查前缀是否存在。

思路二

// Trie 结构定义
var Trie = function() {
  // 初始化 Trie 结构
  this.root = {};
};

// 插入单词到 Trie 中
Trie.prototype.insert = function(word) {
  let node = this.root;
  for (let char of word) {
    // 如果当前节点没有这个字符作为子节点,则创建新的子节点
    if (!node[char]) {
      node[char] = {};
    }
    // 移动到下一个节点
    node = node[char];
  }
  // 设置单词结束标志
  node.isEnd = true;
};

// 搜索单词是否存在于 Trie 中
Trie.prototype.search = function(word) {
  let node = this.root;
  for (let char of word) {
    // 如果在某处找不到对应的字符,则返回 false
    if (!node[char]) {
      return false;
    }
    // 移动到下一个节点
    node = node[char];
  }
  // 返回是否到达单词结束标志
  return node.isEnd === true;
};

// 检查 Trie 是否包含以 prefix 开头的任何单词
Trie.prototype.startsWith = function(prefix) {
  let node = this.root;
  for (let char of prefix) {
    // 如果在某处找不到对应的字符,则返回 false
    if (!node[char]) {
      return false;
    }
    // 移动到下一个节点
    node = node[char];
  }
  // 到达前缀的末尾,返回 true
  return true;
};

讲解

  1. Trie 结构: Trie 是一种树形结构,用于高效地存储和检索字符串。每个节点代表一个字符,从根节点到任意一个叶子节点的路径上的所有字符组合成一个字符串。通常,我们会用一个标志位来表示该节点是否代表了一个单词的结束。
  2. 插入操作 (insert): 遍历字符串中的每个字符,如果当前节点不存在对应的子节点,则创建一个新的子节点;否则,移动到对应的子节点继续遍历。最后,在最后一个字符的节点上设置标志位表示一个单词的结束。
  3. 搜索操作 (search): 类似于插入操作,遍历字符串中的每个字符,如果在某个点字符对应的子节点不存在,则返回false。如果完整遍历字符串并且最后一个字符的节点有单词结束的标志,则返回 true
  4. 前缀查找 (startsWith): 同样地,遍历前缀中的每个字符,如果在某个点字符对应的子节点不存在,则返回 false 。如果完整遍历前缀字符串,则返回 true ,因为我们只关心是否存在这个前缀,而不关心它是否构成一个完整的单词。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值