题目链接:
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出:3
解释:节点 5 和节点 1 的最近公共祖先是节点 3 。
示例 2:
输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
输出:5
解释:节点 5 和节点 4 的最近公共祖先是节点 5 。因为根据定义最近公共祖先节点可以为节点本身。
示例 3:
输入:root = [1,2], p = 1, q = 2
输出:1
提示:
-
树中节点数目在范围
[2, 105]
内。 -
-109 <= Node.val <= 109
-
所有
Node.val
互不相同
。 -
p != q
-
p
和q
均存在于给定的二叉树中。
解题思路
参考链接:
首先,该题需要实现自底向上的查找,所以采用“后序遍历”,这样最先处理的一定是叶子节点。
接着,判断一个节点是节点q和节点p的公共公共祖先:如果找到一个节点,发现左子树出现结点p,右子树出现节点q,或者 左子树出现结点q,右子树出现节点p,那么该节点就是节点p和q的最近公共祖先。
最后,递归处理该二叉树(该题需要遍历整棵树,并且要处理递归返回的值)。
代码
C++
// 递归(后序遍历) class Solution { public: TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) { // 如果找到了 节点p或者q,或者遇到空节点,就返回。 if (root == p || root == q || root == nullptr) return root; // 需要利用left和right做逻辑处理,不能立刻返回,而是要等left与right逻辑处理完之后才能返回 TreeNode* left = lowestCommonAncestor(root->left, p, q); TreeNode* right = lowestCommonAncestor(root->right, p, q); // 如果left 和 right都不为空,说明此时root就是最近公共节点 if (left != nullptr && right != nullptr) return root; // 如果left为空,right不为空,就返回right,说明目标节点是通过right返回的,反之依然。 else if (left == nullptr && right != nullptr) return right; else if (left != nullptr && right == nullptr) return left; // 如果left和right都为空,则返回left或者right都是可以的,也就是返回空。 else { // if (left == nullptr && right == nullptr) return nullptr; } } };
JavaScript
/** * @param {TreeNode} root * @param {TreeNode} p * @param {TreeNode} q * @return {TreeNode} */ var lowestCommonAncestor = function(root, p, q) { if (root === p || root === q || root === null) return root; let left = lowestCommonAncestor(root.left, p, q); let right = lowestCommonAncestor(root.right, p, q); if (left != null && right != null) return root; else if (left === null && right != null) return right; else if (left != null && right === null) return left; else return null; };