树
深度优先搜索
二叉树
题目描述
给定一棵二叉树的根节点 root
,返回给定节点 p
和 q
的最近公共祖先(LCA)节点。如果 p
或 q
之一 不存在 于该二叉树中,返回 null
。树中的每个节点值都是互不相同的。
根据维基百科中对最近公共祖先节点的定义 :“两个节点 p
和 q
在二叉树 T
中的最近公共祖先节点是 后代节点 中既包括 p
又包括 q
的最深节点(我们允许 一个节点为自身的一个后代节点 )”。一个节点 x
的 后代节点 是节点 x
到某一叶节点间的路径中的节点 y
。
示例 1:
输入: 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 = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 10
输出: null
解释: 节点 10 不存在于树中,所以返回 null。
提示:
树中节点个数的范围是 [1, 104 ]
-109 <= Node.val <= 109
所有节点的值 Node.val
互不相同
p != q
进阶: 在不检查节点是否存在的情况下,你可以遍历树找出最近公共祖先节点吗?
解法
方法一:递归(后序遍历)
我们设计一个函数 $dfs(root, p, q)$,该函数返回以 $root$ 为根节点的二叉树中是否包含节点 $p$ 或节点 $q$,如果包含,则返回 true
,否则返回 false
。
函数 $dfs(root, p, q)$ 的递归过程如下:
如果当前节点 $root$ 为空,则返回 false
。
否则,我们递归地遍历左子树和右子树,得到 $l$ 和 $r$,分别表示左子树和右子树中是否包含节点 $p$ 或节点 $q$。
如果 $l$ 和 $r$ 都为 true
,说明当前节点 $root$ 就是我们要找的最近公共祖先节点,将其赋值给变量 $ans$。
如果 $l$ 或 $r$ 为 true
,并且当前节点 $root$ 的值等于节点 $p$ 或节点 $q$ 的值,说明当前节点 $root$ 就是我们要找的最近公共祖先节点,将其赋值给变量 $ans$。
最后,我们判断 $l$ 或 $r$ 是否为 true
,或者当前节点 $root$ 的值是否等于节点 $p$ 或节点 $q$ 的值,如果是,则返回 true
,否则返回 false
。
时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 是二叉树的节点个数。
Python3 Java C++ JavaScript
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 # Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution :
def lowestCommonAncestor (
self , root : 'TreeNode' , p : 'TreeNode' , q : 'TreeNode'
) -> 'TreeNode' :
def dfs ( root , p , q ):
if root is None :
return False
l = dfs ( root . left , p , q )
r = dfs ( root . right , p , q )
nonlocal ans
if l and r :
ans = root
if ( l or r ) and ( root . val == p . val or root . val == q . val ):
ans = root
return l or r or root . val == p . val or root . val == q . val
ans = None
dfs ( root , p , q )
return ans
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
32 /**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
private TreeNode ans ;
public TreeNode lowestCommonAncestor ( TreeNode root , TreeNode p , TreeNode q ) {
dfs ( root , p , q );
return ans ;
}
private boolean dfs ( TreeNode root , TreeNode p , TreeNode q ) {
if ( root == null ) {
return false ;
}
boolean l = dfs ( root . left , p , q );
boolean r = dfs ( root . right , p , q );
if ( l && r ) {
ans = root ;
}
if (( l || r ) && ( root . val == p . val || root . val == q . val )) {
ans = root ;
}
return l || r || root . val == p . val || root . val == q . val ;
}
}
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
32
33
34 /**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public :
TreeNode * lowestCommonAncestor ( TreeNode * root , TreeNode * p , TreeNode * q ) {
dfs ( root , p , q );
return ans ;
}
private :
TreeNode * ans = nullptr ;
bool dfs ( TreeNode * root , TreeNode * p , TreeNode * q ) {
if ( ! root ) {
return false ;
}
bool l = dfs ( root -> left , p , q );
bool r = dfs ( root -> right , p , q );
if ( l && r ) {
ans = root ;
}
if (( l || r ) && ( root -> val == p -> val || root -> val == q -> val )) {
ans = root ;
}
return l || r || root -> val == p -> val || root -> val == q -> val ;
}
};
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
32 /**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @param {TreeNode} p
* @param {TreeNode} q
* @return {TreeNode}
*/
var lowestCommonAncestor = function ( root , p , q ) {
const dfs = root => {
if ( ! root ) {
return false ;
}
const l = dfs ( root . left );
const r = dfs ( root . right );
if ( l && r ) {
ans = root ;
}
if (( l || r ) && ( root . val === p . val || root . val === q . val )) {
ans = root ;
}
return l || r || root . val === p . val || root . val === q . val ;
};
let ans = null ;
dfs ( root );
return ans ;
};
GitHub