给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x的深度尽可能大(一个节点也可以是它自己的祖先)。”
例如,给定如下二叉树: root = [3,5,1,6,2,0,8,null,null,7,4]
示例 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。因为根据定义最近公共祖先节点可以为节点本身。
说明:
- 所有节点的值都是唯一的。
- p、q 为不同节点且均存在于给定的二叉树中。
思路一:使用栈来判断路径
这个思路是我自己想的,我竟然可以自己做出这么复杂的题目了,哈哈哈。
首先利用递归,找到目标节点,然后将它入栈里,再把它的父节点入栈……一直到根节点。两个节点分别对应两个栈,然后再分别出栈,最后一个相等的节点就是最近公共祖先啦。
- 时间复杂度:不会算
- 空间复杂度:O(n)
class Solution {
Stack<TreeNode> stack1;
Stack<TreeNode> stack2;
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
stack1 = new Stack<TreeNode>();
stack2 = new Stack<TreeNode>();
findNode(root,p,stack1);
findNode(root,q,stack2);
TreeNode res = null;
while(!stack1.empty() && !stack2.empty()){
if(stack1.peek()==stack2.peek()){
res = stack1.pop();
stack2.pop();
}else{
break;
}
}
return res;
}
//判断有没有找到对应节点
public boolean findNode(TreeNode node,TreeNode target,Stack<TreeNode> stack){
if(node == target){
stack.push(node); //找到就入栈
return true;
}
if(node==null) return false;
if(findNode(node.left,target,stack) || findNode(node.right,target,stack)){
stack.push(node);
return true;
}
return false;
}
}
思路二:
这个思路和我差不多,都是用递归加一个boolean判断。不过这个就精巧很多,不需要判断路径,只要一个节点的左右子节点返回都为true,那么这个节点就是最近公共祖先。
class Solution {
TreeNode res;
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
findNode(root,p,q);
return res;
}
//判断有没有找到对应节点
public boolean findNode(TreeNode node,TreeNode p,TreeNode q){
if(node==null) return false;
if(node==p || node==q) {//这里只要找到相等就把它当作结果,如果此节点恰好是最近公共祖先,那就正好;如果不是,后面会替换掉的。
res = node;
return true;
}
boolean leftFind = findNode(node.left,p,q);
boolean rightFind = findNode(node.right,p,q);
if(leftFind && rightFind){
res = node;
return true;
}
if(leftFind || rightFind){
return true;
}
return false;
}
}