437. Path Sum III

You are given a binary tree in which each node contains an integer value.

Find the number of paths that sum to a given value.

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).

The tree has no more than 1,000 nodes and the values are in the range -1,000,000 to 1,000,000.

Example:

root = [10,5,-3,3,2,null,11,3,-2,null,1], sum = 8

      10
     /  \
    5   -3
   / \    \
  3   2   11
 / \   \
3  -2   1

Return 3. The paths that sum to 8 are:

1.  5 -> 3
2.  5 -> 2 -> 1
3. -3 -> 11

题解

此题的难点需想清每个节点都要当作根节点来对待, 因此题解为如下三部分之和:

  1. 当前节点作为根节点时相加为 sum 的路径之和。
  2. 当前节点左子树作为根节点时相加为 sum 的路径之和。
  3. 当前节点右子树作为根节点时相加为 sum 的路径之和。

同时递归可以分为两个部分: 根节点的递归分析总和的递归

/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {TreeNode} root
 * @param {number} sum
 * @return {number}
 */
var pathSum = function(root, sum) {
  if (!root) return 0
  // total means result value
  // initialSum means init sum value
  let result = { total: 0, initialSum: sum }
  analyzeSum(root, result, sum)
  return result.total
};

var analyzeSum = function(node, result, sum) {
  if (!node) return
  const extraSum = sum - node.val
  if (extraSum === 0) {
    result.total = result.total + 1
  }

  analyzeSum(node.left, result, extraSum)
  analyzeSum(node.right, result, extraSum)
  // handle it as root node.
  analyzeSum(node.left, result, result.initialSum)
  analyzeSum(node.right, result, result.initialSum)
}

submit 后, 卡在了如下测试用例中:

输入:
[1,null,2,null,3] // 该测试用例有点怪, 应该为 [1, null, 2, null, null, null, 3]
3

       1
     /   \
  null    2
        /   \
      null    3

输出:
3
预期:
2

经过排查, analyzeSum 函数存在冗余的调用, 并未将根节点的递归分析总和的递归给解耦。调整如下:

/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {TreeNode} root
 * @param {number} sum
 * @return {number}
 */
// recursive root node
var pathSum = function(root, sum) {
  if (!root) return 0
  const curTotal = analyzeSum(root, sum)
  const leftChildTotal = pathSum(root.left, sum)
  const rightChildTotal = pathSum(root.right, sum)
  return curTotal + leftChildTotal + rightChildTotal
};

// recursive anlyze total value
var analyzeSum = function(node, expectSum) {
  if (!node) return 0
  const extraSum = expectSum - node.val
  if (extraSum === 0) {
    return 1 + analyzeSum(node.left, extraSum) + analyzeSum(node.right, extraSum)
  } else {
    return analyzeSum(node.left, extraSum) + analyzeSum(node.right, extraSum)
  }
}