https://blog.csdn.net/m0_46202073/article/details/107253959
https://leetcode.cn/problems/implement-trie-prefix-tree/solution/trie-tree-de-shi-xian-gua-he-chu-xue-zhe-by-huwt/

208. 实现 Trie (前缀树)

  1. /*
  2. * @lc app=leetcode.cn id=208 lang=javascript
  3. *
  4. * [208] 实现 Trie (前缀树)
  5. */
  6. // @lc code=start
  7. var TrieNode =function(){ // 节点
  8. this.isEnd = false;
  9. this.next = Array(26);
  10. }
  11. var Trie = function () { // 前缀树
  12. this.node= new TrieNode();
  13. };
  14. /**
  15. * @param {string} word
  16. * @return {void}
  17. */
  18. Trie.prototype.insert = function (word) {
  19. let node = this.node;
  20. for (let w of word) {
  21. const index = w.charCodeAt() - 'a'.charCodeAt()
  22. if (!node.next[index]) {
  23. node.next[index] = new Trie();
  24. }
  25. node = node.next[index]
  26. }
  27. node.isEnd = true;
  28. };
  29. /**
  30. * @param {string} word
  31. * @return {boolean}
  32. */
  33. Trie.prototype.search = function (word) {
  34. let node = this;
  35. for (let w of word) {
  36. const index = w.charCodeAt() - 'a'.charCodeAt()
  37. if (!node.next[index]) return false;
  38. node = node.next[index]
  39. }
  40. return node.isEnd
  41. };
  42. /**
  43. * @param {string} prefix
  44. * @return {boolean}
  45. */
  46. Trie.prototype.startsWith = function (prefix) {
  47. let node = this;
  48. for (let w of prefix) {
  49. const index = w.charCodeAt() - 'a'.charCodeAt()
  50. if (!node.next[index]) return false;
  51. node = node.next[index]
  52. }
  53. return true;
  54. };
  55. /**
  56. * Your Trie object will be instantiated and called as such:
  57. * var obj = new Trie()
  58. * obj.insert(word)
  59. * var param_2 = obj.search(word)
  60. * var param_3 = obj.startsWith(prefix)
  61. */
  62. // @lc code=end

820. 单词的压缩编码

  1. var minimumLengthEncoding = function (words) {
  2. words.sort((a, b) => { //需要先排序,让长的单词先插入
  3. return b.length - a.length;
  4. })
  5. let sum = 0;
  6. let trie = new Trie();
  7. for (let word of words) {
  8. sum += trie.insert(word);
  9. }
  10. return sum;
  11. };
  12. var TrieNode =function(){ // 节点
  13. this.next = Array(26);
  14. }
  15. class Trie {
  16. constructor() {
  17. this.node= new TrieNode();
  18. }
  19. insert(word) {
  20. let node = this.node;
  21. let flag = false;
  22. for (let i = word.length - 1; i >= 0; i--) { //倒着插入
  23. const index = word[i].charCodeAt() - 'a'.charCodeAt();
  24. if (!node.next[index]) {
  25. flag = true; //如果有新建节点则
  26. node.next[index] = new TrieNode();
  27. }
  28. node = node.next[index];
  29. }
  30. return flag ? word.length + 1 : 0;
  31. }
  32. }

211. 添加与搜索单词 - 数据结构设计

前几道题的search都是迭代的方式,这有一点弊端:“cur一条路走到黑”,但有时我们需要走一个分叉的路,去尝试更多的可能。
所以接下来用递归的方式去搜索。

  1. var TrieNode = function () {
  2. this.next = Array(26);
  3. this.isEnd = false;
  4. }
  5. var WordDictionary = function () {
  6. this.node = new TrieNode();
  7. };
  8. /**
  9. * @param {string} word
  10. * @return {void}
  11. */
  12. WordDictionary.prototype.addWord = function (word) {
  13. let node = this.node;
  14. for (let w of word) {
  15. const index = w.charCodeAt() - 'a'.charCodeAt();
  16. if (!node.next[index]) {
  17. node.next[index] = new TrieNode();
  18. }
  19. node = node.next[index];
  20. }
  21. node.isEnd = true;
  22. };
  23. /**
  24. * @param {string} word
  25. * @return {boolean}
  26. */
  27. WordDictionary.prototype.search = function (word) {
  28. return match(word, this.node, 0);
  29. };
  30. function match(word, node, start) {
  31. if (start === word.length) {
  32. return node.isEnd;
  33. }
  34. if (word[start] === '.') {
  35. for (let i = 0; i < 26; i++) {
  36. if (node.next[i] != null && match(word, node.next[i], start + 1)) {
  37. return true;
  38. }
  39. }
  40. return false;
  41. } else {
  42. const index = word[start].charCodeAt() - 'a'.charCodeAt();
  43. return node.next[index] != null && match(word, node.next[index], start + 1)
  44. }
  45. }

676. 实现一个魔法字典

与211题类似,

  1. var TrieNode = function () {
  2. this.next = Array(26);
  3. this.isEnd = false;
  4. }
  5. var MagicDictionary = function () {
  6. this.node = new TrieNode();
  7. };
  8. /**
  9. * @param {string[]} dictionary
  10. * @return {void}
  11. */
  12. MagicDictionary.prototype.buildDict = function (dictionary) {
  13. for (let dic of dictionary) {
  14. let node = this.node;
  15. for (let w of dic) {
  16. const index = w.charCodeAt() - 'a'.charCodeAt();
  17. if (!node.next[index]) {
  18. node.next[index] = new TrieNode();
  19. }
  20. node = node.next[index];
  21. }
  22. node.isEnd = true;
  23. }
  24. };
  25. /**
  26. * @param {string} searchWord
  27. * @return {boolean}
  28. */
  29. MagicDictionary.prototype.search = function (searchWord) {
  30. return match(searchWord, this.node, 0, true)
  31. };
  32. var match = function (word, node, start, hasChance) {
  33. if (start === word.length) {
  34. return node.isEnd && !hasChance;
  35. }
  36. //这样写,当字典树中有"hello"和"hallo"时,search("hello")会返回false。
  37. // const index = word[start].charCodeAt() - 'a'.charCodeAt();
  38. // if (!node.next[index]) {
  39. // if (hasChance) {
  40. // for (let i = 0; i < 26; i++) {
  41. // if (node.next[i] != null && match(word, node.next[i], start + 1, false)) {
  42. // return true;
  43. // }
  44. // }
  45. // }
  46. // return false;
  47. // } else {
  48. // return match(word, node.next[index], start + 1, hasChance)
  49. // }
  50. // 所以改为一次for(26)的遍历。
  51. for (let i = 0; i < 26; i++) {
  52. if (node.next[i]) {
  53. const index = word[start].charCodeAt() - 'a'.charCodeAt();
  54. if (index === i && match(word, node.next[i], start + 1, hasChance)) {
  55. return true;
  56. } else if (index !== i && hasChance && match(word, node.next[i], start + 1, false)) {
  57. return true;
  58. }
  59. }
  60. }
  61. return false;
  62. }

面试题 17.13. 恢复空格