Guest User

Untitled

a guest
Jul 16th, 2018
93
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.54 KB | None | 0 0
  1. /*
  2. 437. Path Sum III
  3.  
  4. You are given a binary tree in which each node contains an integer value.
  5.  
  6. Find the number of paths that sum to a given value.
  7.  
  8. The path does not need to start or end at the root or a leaf, but it must go downwards (traveling only from parent nodes to child nodes).
  9.  
  10. The tree has no more than 1,000 nodes and the values are in the range -1,000,000 to 1,000,000.
  11.  
  12. Example:
  13.  
  14. root = [10,5,-3,3,2,null,11,3,-2,null,1], sum = 8
  15.  
  16. 10
  17. / \
  18. 5 -3
  19. / \ \
  20. 3 2 11
  21. / \ \
  22. 3 -2 1
  23.  
  24. Return 3. The paths that sum to 8 are:
  25.  
  26. 1. 5 -> 3
  27. 2. 5 -> 2 -> 1
  28. 3. -3 -> 11
  29.  
  30.  
  31. Think:
  32. There's a great explanation on the discussion by Kekezi
  33. DP+Memorization <-- perfect
  34.  
  35. I only mention the 2nd step with a sample
  36. """
  37. The sum from any node in the middle of the path to the current node = the difference between the sum from the root to the current node and the prefix sum of the node in the middle
  38. """
  39.  
  40. if there's a subtree [1,2,3] and target is 3, due to top-down method, you will store
  41. 1 first. (Memorization)
  42. Then go left, and you will get 3( 1+ 2) in memorization. For sure, it is a valid path
  43. Take the other side, and you will get 4(1+3) in memorization.
  44. Meanwhile, If we could possibly get rid of this one node in the middle, and we will get valid path, which means 4 - 3.
  45. We now check the memorization, there's 1 in the memorization, so 1->3 would be a valid answer w/o 1.
  46.  
  47. Take other example w/ negative one. [-2,1,-1] -1
  48. [-2] at first
  49. -2->1 would be an answer
  50. -2->-1 w/o -2 would be answer (-3-(-1))
  51.  
  52. Detailed example for question
  53.  
  54.  
  55.  
  56.  
  57. map[0:1] &{10 0xc42000a1a0 0xc42000a1c0}
  58. -->10, 10, 2, 0
  59. &map[0:1 10:1] &{5 0xc42000a200 0xc42000a220}
  60. -->5, 15, 7, 0
  61. &map[0:1 10:1 15:1] &{3 0xc42000a260 0xc42000a280}
  62. -->3, 18, 10, 1
  63. &map[18:1 0:1 10:1 15:1] &{3 <nil> <nil>}
  64. -->3, 21, 13, 0
  65. &map[21:1 0:1 10:1 15:1 18:1] <nil>
  66. &map[10:1 15:1 18:1 21:1 0:1] <nil>
  67. &map[0:1 10:1 15:1 18:1 21:0] &{-2 <nil> <nil>}
  68. -->-2, 16, 8, 0
  69. &map[21:0 16:1 0:1 10:1 15:1 18:1] <nil>
  70. &map[0:1 10:1 15:1 18:1 21:0 16:1] <nil>
  71. &map[16:0 0:1 10:1 15:1 18:0 21:0] &{2 <nil> 0xc42000a2a0}
  72. -->2, 17, 9, 0
  73. &map[15:1 18:0 21:0 16:0 17:1 0:1 10:1] <nil>
  74. &map[16:0 17:1 0:1 10:1 15:1 18:0 21:0] &{1 <nil> <nil>}
  75. -->1, 18, 10, 1
  76. &map[0:1 10:1 15:1 18:1 21:0 16:0 17:1] <nil>
  77. &map[10:1 15:1 18:1 21:0 16:0 17:1 0:1] <nil>
  78. &map[0:1 10:1 15:0 18:0 21:0 16:0 17:0] &{-3 <nil> 0xc42000a240}
  79. -->-3, 7, -1, 0
  80. &map[10:1 15:0 18:0 21:0 16:0 17:0 7:1 0:1] <nil>
  81. &map[18:0 21:0 16:0 17:0 7:1 0:1 10:1 15:0] &{11 <nil> <nil>}
  82. -->11, 18, 10, 1
  83. &map[17:0 7:1 0:1 10:1 15:0 18:1 21:0 16:0] <nil>
  84. &map[15:0 18:1 21:0 16:0 17:0 7:1 0:1 10:1] <nil>
  85.  
  86. And the reference from Leetcode discussion.
  87. -----------------------------------------------
  88.  
  89. This is an excellent idea and took me some time to figure out the logic behind.
  90. Hope my comment here could help understanding this solution.
  91.  
  92.  
  93. 1. The prefix stores the sum from the root to the current node in the recursion
  94. 2. The map stores <prefix sum, frequency> pairs before getting to the current node. We can imagine a path from the root to the current node. The sum from any node in the middle of the path to the current node = the difference between the sum from the root to the current node and the prefix sum of the node in the middle.
  95. 3. We are looking for some consecutive nodes that sum up to the given target value, which means the difference discussed in 2. should equal to the target value. In addition, we need to know how many differences are equal to the target value.
  96. 4. Here comes the map. The map stores the frequency of all possible sum in the path to the current node. If the difference between the current sum and the target value exists in the map, there must exist a node in the middle of the path, such that from this node to the current node, the sum is equal to the target value.
  97. 5. Note that there might be multiple nodes in the middle that satisfy what is discussed in 4. The frequency in the map is used to help with this.
  98. 6. Therefore, in each recursion, the map stores all information we need to calculate the number of ranges that sum up to target. Note that each range starts from a middle node, ended by the current node.
  99. 7. To get the total number of path count, we add up the number of valid paths ended by EACH node in the tree.
  100. 8. Each recursion returns the total count of valid paths in the subtree rooted at the current node. And this sum can be divided into three parts:
  101. - the total number of valid paths in the subtree rooted at the current node's left child
  102. - the total number of valid paths in the subtree rooted at the current node's right child
  103. - the number of valid paths ended by the current node
  104. The interesting part of this solution is that the prefix is counted from the top(root) to the bottom(leaves), and the result of total count is calculated from the bottom to the top :D
  105.  
  106. The code below takes 16 ms which is super fast.
  107.  
  108.  
  109.  
  110.  
  111.  
  112.  
  113. */
  114.  
  115. func pathSum(root *TreeNode, sum int) int {
  116. if root == nil {
  117. return 0
  118. }
  119.  
  120. m := make(map[int]int) // bottom-up map and
  121. m[0]=1
  122. return backtrack(&m, root, 0, sum)
  123. }
  124.  
  125. func backtrack(_m *map[int]int, root *TreeNode, sum, target int) int {
  126. fmt.Println(_m, root)
  127. if root == nil {
  128. return 0
  129. }
  130. sum += root.Val
  131. m := *_m
  132. numPathToCur := 0
  133. fmt.Printf("-->%d, %d, %d, %d\n",root.Val, sum, sum-target, m[sum-target])
  134. if _,ok := m[sum-target]; ok {
  135. numPathToCur = m[sum-target]
  136. }
  137. if _,ok := m[sum]; !ok {
  138. m[sum] = 1
  139. } else {
  140. m[sum] += 1
  141. }
  142. rst :=numPathToCur + backtrack(&m, root.Left, sum, target)+backtrack(&m, root.Right, sum, target)
  143. m[sum] -= 1
  144. return rst
  145. }
Add Comment
Please, Sign In to add comment