难度中等题。
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。
思路有多种。
1. 纯粹的自底向上。后序遍历中,先找到该节点,那么返回一个true。当某个节点的左右子树都返回true时,该节点就是要求的。如果两个点是祖先后代关系,那么返回为当前节点值等于其中一个查询值且一个子树为true时,那么该节点也是要找的。
2. 自底向上和自顶向下结合的。首先在递归遍历中从根节点出发自顶向下找到第一个值的位置,然后暂定该点为要求的。接着找其子树是否存在第二个点,如果存在,那么返回刚刚暂定的结果。如果不存在,那么就会在回溯过程中回溯到该点(用暂定结果点等于当前遍历值表示回溯到暂定结果了,该子树下没有第二个,那么下一步回溯就要吧暂定结果向上取,继续这个过程)。
3. 用一个HashMap<当前点,父节点>,放进去这个树,根据两个给定值在HashMap中找父节点序列,第一个共同都是父节点的就是要求的。
我的代码是第二种。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public TreeNode res;//就是暂存结果的
public boolean isRoot = true;//用于标记是否还在遍历当前暂定结果的子树找第二个点
public boolean success = false;//找到了
public void find(TreeNode root, int p,int q){
if(root == null || success)
return;
if ((root.val == p || root.val == q) && res == null){//找到了第一个点
res = new TreeNode(root.val);
}
find(root.left,p,q);
if(success)
return;
if(!isRoot){//设定暂时结果点
res = root;
isRoot = true;
}
find(root.right,p,q);
if(success)
return;
if((root.val == p || root.val == q) && res.val != root.val){//找到第二个点
success = true;
return;
}
if(res != null){//标记该树遍历完了还是没有找到第二个
if(res.val == root.val && isRoot){
isRoot = false;
}
}
}