【LeetCode 208.实现Trie(字典树)】 - JavaScript

715 阅读2分钟

这是我参与8月更文挑战的第22天,活动详情查看:8月更文挑战


说明:文章部分内容及图片出自网络,如有侵权请与我本人联系(主页有公众号:小攻城狮学前端)

作者:小只前端攻城狮、 主页:小只前端攻城狮的主页、 来源:掘金

GitHub:P-J27、 CSDN:PJ想做前端攻城狮

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。


LeetCode 208.实现Trie(字典树) - JavaScript


实现一个 Trie (前缀树),包含 insert, search, 和 startsWith 这三个操作。

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

说明:

  • 你可以假设所有的输入都是由小写字母 a-z 构成的。
  • 保证所有输入均为非空字符串。

题目分析

本题的目的是实现一个字典树,这个字典树的主要功能就是 2 个:

  • 存放单词
  • 查找单词是否存在

代码实现

节点单独封装为一个类,它有两个属性:

  • next:next[i]保存着下一个字符i的节点引用
  • isEnd:当前节点是否可以作为一个单词的结束位置

可以看到,节点本身不存储字符,字符是保存在next对象中的 key 中。直观来看,字符是保存在节点之间的连线上的

代码实现如下:

var TrieNode = function() {
  this.next = {};
  this.isEnd = false;
};

var Trie = function() {
  this.root = new TrieNode();
};

Trie.prototype.insert = function(word) {
  if (!word) return false;

  let node = this.root;
  for (let i = 0; i < word.length; ++i) {
    if (!node.next[word[i]]) {
      node.next[word[i]] = new TrieNode();
    }
    node = node.next[word[i]];
  }
  node.isEnd = true;
  return true;
};

Trie.prototype.search = function(word) {
  if (!word) return false;

  let node = this.root;
  for (let i = 0; i < word.length; ++i) {
    if (node.next[word[i]]) {
      node = node.next[word[i]];
    } else {
      return false;
    }
  }
  return node.isEnd;
};

Trie.prototype.startsWith = function(prefix) {
  if (!prefix) return true;

  let node = this.root;
  for (let i = 0; i < prefix.length; ++i) {
    if (node.next[prefix[i]]) {
      node = node.next[prefix[i]];
    } else {
      return false;
    }
  }
  return true;
};

拓展思考:如何删除单词?

题目中的字典树的功能并不完整,它缺失 2 个重要功能:

  • 删除单词
  • 统计单词出现次数

为了解决这个问题,需要给每个 TrieNode 准备 2 个 number 类型变量:

  • path:代表从当前节点经过的单词数量
  • end:代表以当前节点为结束的单词数量

对于「统计单词次数」的功能,搜索完成后,读取最后结束节点的 end 即可。

对于「删除单词」的功能,依次在对路径上节点的 path 减 1。优化的地方是:当 path 为 0 时,说明没有单词经过了,不需要再向下遍历,直接移除以下所有节点即可。


感谢阅读,希望能对你有所帮助,文章若有错误或者侵权,可以在评论区留言或在我的主页添加公众号联系我。

写作不易,如果觉得不错,可以「点赞」+「评论」 谢谢支持❤