236. 二叉树的最近公共祖先 - 力扣(LeetCode) (leetcode-cn.com)
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
示例 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 = [1,2], p = 1, q = 2
输出:1
提示:
树中节点数目在范围 [2, 105] 内。
-109 <= Node.val <= 109
所有 Node.val 互不相同 。
p != q
p 和 q 均存在于给定的二叉树中。
解法一:
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root == null){
return null;
}
if(p == root || q == root){
return root;
}
//上面两个if是去判断返回值的,接下来去不断递归,每递归一次去判断是不是有返回值(否则就是不满足上面两种情况,那么继续去递归)
TreeNode left = lowestCommonAncestor(root.left,p,q);
TreeNode right = lowestCommonAncestor(root.right,p,q);
//通过下面的图我们知道,基本分成三种情况,但你用代码去处理很简单。第一种情况的时候,在p和q分别在根的左右子树上,我们去递归左子树找到一个就去返回,然后去递归右子树找到了了就返回,记录下这两个返回值,当这两个返回值不为null时,就说明是对称的。
//第二种是p/q都在左子树的时候,此时,你第一次递归就返回左子树然后去递归右子树,最后记录下的发现
左子树最终递归的不是null,而右子树是null,说明两个本来都是在root的左子树上,而且一个还是另一个的祖先。
//第三种也是一样的,左子树递归为null,然后去右子树递归发现找到了,就返回,下面的代码一判断就知道返回的那个肯定就是本身和另一个的祖先
if(left == null){
return right;
}
if(right == null){
return left;
}
//这里表示的是left和right都不为空
return root;
}
}
解法二:链表求交点法
1、用两个栈去存储这两个节点的路径的结点
2、求栈的大小
3、让栈中多的元素 出差值步
4、开始出栈、直到栈顶元素相同时知道了最近祖先
那么此时最大的困难就是如何去找到存储的路径(回溯的思想),深度优先遍历嘛
直接上代码:看不懂再去看视频讲解
class Solution {
boolean getpath(TreeNode root,TreeNode node,Stack<TreeNode> stack){
if(root == null || node == null){
return false;
}
stack.push(root);
if(root == node){
return true;
}
boolean flg = getpath(root.left,node,stack);
if(flg == true ){
return true;
}
flg = getpath(root.right,node,stack);
if(flg == true ){
return true;
}
stack.pop();
return false;
}
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
Stack<TreeNode> stack1 = new Stack<>();
Stack<TreeNode> stack2 = new Stack<>();
getpath(root,p,stack1);
getpath(root,q,stack2);
int size1 = stack1.size();
int size2 = stack2.size();
int size = size1-size2;
if(size>0){
while(size != 0){
stack1.pop();
size--;
}
while(!stack1.isEmpty() && !stack2.isEmpty()){
if(stack1.peek() == stack2.peek()){
return stack1.pop();
}else{
stack1.pop();
stack2.pop();
}
}
}else{
size = size2-size1;
while(size != 0){
stack2.pop();
size--;
}
while(!stack1.isEmpty() && !stack2.isEmpty()){
if(stack1.peek() == stack2.peek()){
return stack1.pop();
}else{
stack1.pop();
stack2.pop();
}
}
}
return null;
}
}