寻找二叉树的最近公共祖先

104 阅读2分钟

RT,注释都在代码中,直接上代码。

/**
 * 寻找二叉树的最近公共祖先
 * 题目描述:给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。最近公共祖先节点可以为节点本身。
 *
 * 命题关键字:二叉树、递归
 *            3
 *         /     \
 *       5        1
 *     /  \      / \
 *    6    2    0   8
 *        / \
 *       7  4
 *
 * ------------------------
 * 命题关键字:二叉树、递归
 *
 * 怎么算上报:一层层往上透传返回目标节点(如果到了边界 null,那就一层层往上透传返回 null)
 *
 */
funMap.lowestCommonAncestor = () => {
  let root = {
    val: 3,
    left: {
      val: 5,
      left: {
        val: 6,
      },
      right: {
        val: 2,
        left: {
          val: 7,
        },
        right: {
          val: 4,
        },
      },
    },
    right: {
      val: 1,
      left: {
        val: 0,
      },
      right: {
        val: 8,
      },
    },
  }

  function lowestCommonAncestor(root, val1, val2) {
    function dfs(root) {
      /**
       * 找到空或目标节点就是边界,
       * 如果找的是 5 6,
       * 到 5 这里直接就不再往下遍历了,而且 6 如果是它的子树上的某个节点,那本身结果就应该是 5。
       * 这就进入了 节点 3 的 return left || right 的逻辑,结果 right 这时是 null,
       * 那就返回了 5。
       *
       * 如果找的是 6 2,就进入了 5 的 if (left && right) 的逻辑,就返回了 5,
       * 然后又回到了 3 的 return left || right 的逻辑,结果 right 这时是 null,
       * 那就返回了 5。
       *
       * 最终递归栈都会回到根节点,除非本身目标就包含根节点,如求:3, 5 的最近共同祖先,那到 3 就直接返回了。
       */
      if (!root || root.val === val1 || root.val === val2) {
        return root
      }

      // 注意这里传入参数的时候 root.left root.right 要写对
      let left = dfs(root.left)
      let right = dfs(root.right)

      // 左子树和右子树都有,这里刚好是交叉点
      if (left && right) {
        return root
      }

      // 这里返回啥?本能反应是返回 root,那岂不是上面的判断和遍历就没用了,
      // 所以应该返回 dfs 的结果,远远的传上去,
      // 让递归栈回退到上面的时候再判断
      return left || right
    }

    return dfs(root).val
  }

  console.log(lowestCommonAncestor(root, 5, 6))
}

funMap.lowestCommonAncestor()