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 v and w as the lowest node in T that has both v and w as descendants (where we allow a node to be a descendant of itself).”
_______3______ / \ ___5__ ___1__ / \ / \ 6 _2 0 8 / \ 7 4
For example, the lowest common ancestor (LCA) of nodes 5
and 1
is 3
. Another example is LCA of nodes 5
and 4
is 5
, since a node can be a descendant of itself according to the LCA definition.
题意:给定一棵二叉树,查找两个节点的最接近的共同祖先LCA
分类:二叉树
解法1:要找到共同祖先,由于不是BST树,没有大小关系存在。但是我们可以想到后序遍历,对于后序遍历,是先遍历左子树,再右子树,最后是当前节点。
假设要找的是p,q两个节点的共同祖先,对于root节点,我们假设有一个函数
p,q都在左子树,那么应该在左子树找到p和q,而右子树则两者都找不到,这是我们可以判断共同祖先在左子树,递归查找。
如果p,q都在右子树,同样道理,左子树一个都找不到,那么我们递归在右子树里面找。
如果p,q在root的两侧,那么左子树和右子树都应该有返回值,这是root就是最近共同祖先。
并且这里有一个技巧,就是不必p,q都找到,例如在递归左子树的时候,先找到了p,我们就可以直接去右子树找,如果右子树没有找到q,意味着q在左子树
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root == p || root == q || root == null) { return root; }//如果已经找到p,q返回,或者root为null,返回null
TreeNode left = lowestCommonAncestor(root.left, p, q);//先在左子树找
TreeNode right = lowestCommonAncestor(root.right, p, q);//再找右子树
if(left != null && right != null){//如果左右子树分别有一个,则返回根节点
return root;
}else if(left!=null){//如果只在左子树,返回left
return left;
}else{//如果只在右子树,返回right
return right;
}
}
}
解法2:同样是后序遍历,使用后序遍历非递归算法一边遍历一边存储路径,找到p,q并且把它们的路径分别存储起来
最后比较这两条路径,找到最后一个相同的节点,则为所求
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
Stack<TreeNode> stack = new Stack<TreeNode>();
ArrayList<TreeNode> path1 = new ArrayList<TreeNode>();
ArrayList<TreeNode> path2 = new ArrayList<TreeNode>();
int found = 0;//当前路径标志
TreeNode cur = root;
do{
if(found==2) break;
while(cur!=null){
stack.add(cur);
cur = cur.left;
}
TreeNode t = null;
boolean flag = false;
while(stack.size()>0&&!flag){
cur = stack.peek();
if(cur.right==t){//如果这个节点右节点为null或者右节点已经访问过
if(cur==p||cur==q){//判断是不是p,q,如果是就保存当前路径
if(found==0) path1.addAll(stack);
else path2.addAll(stack);
found++;
}
stack.pop();
t = cur;
}else{//如果右节点没有被访问过,先遍历右子树
flag = true;
cur = cur.right;
}
}
}while(stack.size()>0);
int i = 0;
while(i<path1.size()&&i<path2.size()){//从头开始查找最后一个相同的节点
if(path1.get(i)!=path2.get(i)) break;
else i++;
}
return path1.get(i-1);
}
}