05 August 2008
Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree.
According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes p and q as the lowest node in T that has both p and q as descendants (where we allow a node to be a descendant of itself).”
Given the following binary tree: root = [3,5,1,6,2,0,8,null,null,7,4]
1
2
3
4
5
6
7
_______3______
/ \
___5__ ___1__
/ \ / \
6 _2 0 8
/ \
7 4
Example 1:
1
2
3
Input: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
Output: 3
Explanation: The LCA of of nodes 5 and 1 is 3.
Example 2:
1
2
3
4
Input: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
Output: 5
Explanation: The LCA of nodes 5 and 4 is 5, since a node can be a descendant of itself
according to the LCA definition.
Note:
这道题跟235-Lowest Common Ancestor of a Binary Search Tree相比,这道题是普通的二叉树,结点的值不会重复,不能用二叉搜索树的特征,同样用递归,先看当前结点是否为null,若为null直接返回null,如果为p或q中的任意一个,直接返回当前结点;如果都不是就对齐左右子结点,然后分别调用递归函数,因为p和q一定存在,所以如果当前结点不等于p或q的时候,有可能:
1)p和q分别在左右子树,对左右子结点调用递归函数,会分别返回p和q的位置,那当前结点恰好就是p和q的最小父结点,直接返回;
2)p和q都在左子树,这样又有两种情况,一种情况是left会返回p和q中较高的那个位置,而right会返回空,所以我们最终返回非空的left即可,这就是题目中的例子2的情况。还有一种情况是会返回p和q的最小父结点,就是说当前结点的左子树中的某个结点才是p和q的最小父结点,会被返回;
3)若p和q同时位于右子树,同样这里有两种情况,一种情况是right会返回p和q中较高的那个位置,而left会返回空,所以我们最终返回非空的right即可,还有一种情况是会返回p和q的最小父结点,就是说当前结点的右子树中的某个结点才是p和q的最小父结点,返回。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
//递归的基线条件,要么返回null,要么返回p或者q,然后递归回来的时候根据此结果判断
if (root == null || p == root || q == root) {
return root;
}
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);
//p,q分别在当前root的左右子树
if (left != null && right != null) {
return root;
}
return left != null ? left : right;//上面2)3)的分析
}
}
上面的解法可以稍微优化一下:如果当前结点不为空,且既不是p也不是q,那么根据上面的分析,p和q的位置就有三种情况,p和q要么分别位于左右子树中,或者同时位于左子树,或者同时位于右子树。这里需要优化的情况就是当p和q同时为于左子树或右子树中,而且返回的结点并不是p或q(如果是p或q,不能说明p和q都在left或者都在right,因为不知道q或者p是否在下面,而递归已返回),那么返回值就是p和q的最小父结点了,已经求出来了,就不用再对右结点调用递归函数了,同样,对返回的right也做同样的优化处理。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root == null || p == root || q == root) {
return root;
}
TreeNode left = lowestCommonAncestor(root.left, p, q);
if (left != null && left != p && left != q) {
return left;
}
TreeNode right = lowestCommonAncestor(root.right, p, q);
if (right != null && right != p && right != q) {
return right;
}
//这是p和q分别在左右子树的情况,这个解法没有优化这种情况
if (left != null && right != null) {
return root;
}
return left != null ? left : right;
}
}