image.png
image.png

方法一:Trie

字符串前缀的处理可以使用 Trie(前缀树)来进行处理:

  1. class TrieNode {
  2. value = 0
  3. next = new Map<string, TrieNode>()
  4. }
  5. class MapSum {
  6. root: TrieNode
  7. constructor() {
  8. this.root = new TrieNode()
  9. }
  10. insert(key: string, val: number): void {
  11. // 1. 遍历 key 中的所有字符
  12. // 2. 如果字符原本并不在 Trie 中,则将字符保存在 Trie 中
  13. // 3. 遍历完 key 中的所有字符之后,在最有一个节点中赋值 value
  14. let cur = this.root
  15. for (const c of key) {
  16. if (!cur.next.get(c)) {
  17. cur.next.set(c, new TrieNode())
  18. }
  19. cur = cur.next.get(c) as TrieNode
  20. }
  21. cur.value = val
  22. }
  23. sum(prefix: string): number {
  24. // 1. 遍历 prefix 中的所有字符,如果 prefix 中的字符不在 Trie 中,那么直接返回0
  25. // 2. 如果 prefix 中的字符为单词的结尾,直接累加节点的 value 值
  26. // 3. 当遍历完字符之后,递归遍历其后的所有节点的 next
  27. let cur = this.root
  28. for (const c of prefix) {
  29. const tmp = cur.next.get(c)
  30. if (!tmp) {
  31. return 0
  32. }
  33. cur = tmp
  34. }
  35. const result = cur.value + this.recursion(cur)
  36. return result
  37. }
  38. private recursion(node: TrieNode) {
  39. // 1. 遍历节点 node 的所有 next 节点
  40. // 2. 如果 next 的某个节点有 value,则与 result 进行相加
  41. // 3. 对该节点进行递归
  42. let result = 0
  43. for (let key of node.next.keys()) {
  44. const nextNode = node.next.get(key) as TrieNode
  45. if (nextNode.value) {
  46. result += nextNode.value
  47. }
  48. result += this.recursion(nextNode)
  49. }
  50. return result
  51. }
  52. }