题目描述
给定一颗二叉树和两个任意节点,请求解出这两个节点的最小公共父节点,如果其中一个节点本身是另外一个的父类,那么就返回这个父节点,否则,就返回距离他们俩最近的公共父节点。此题给定的两个节点肯定在这颗二叉树中。
思路分析
常规思路,二叉树只能从父节点到孩子节点遍历,从孩子节点往上回溯比较困难,因此,此题既然要求求出最小公共父节点,那么,就构造一个从孩子节点回溯父节点的数据结构,用map保存孩子节点对应的父节点。
然后,从给定的两个节点中的任意一个开始向上回溯父节点,将路径上的所有节点都放入set中,然后,再回溯另一个,每遍历到一个父节点就在set中查找是否存在,返回找到的第一个节点,就是最小公共父节点。
代码
public static Node get(Node head,Node n1,Node n2){
HashMap<Node,Node> map=new HashMap<>();
map.put(head,head);
getMap(map,head);
HashSet<Node> set=new HashSet<>();
while (n1!=head){
set.add(n1);
n1=map.get(n1);
}
set.add(head);
while (true){
if(set.contains(n2)){
return n2;
}else {
n2=map.get(n2);
}
}
}
private static void getMap(HashMap map,Node node) {
if(node==null){
return;
}
Node left=node.left;
Node right=node.right;
if(left!=null){
map.put(left,node);
}
if(right!=null){
map.put(right,node);
}
getMap(map,left);
getMap(map,right);
}
思路二
总体思路是想利用递归向上返回的值来返回最小公共父节点。
分析题目的两种情况:
情况一:n1或者n2本身是另一个的父类节点,那么,最终结果应该是这个父节点本身。因此,向上返回的数据,返回它本身就可以了,如果它下面有另一个,也返回它自己本身就行,这样就会把下面的覆盖掉。然后,其余节点,如果不是n1和n2,就返回null,如果接收的返回值包含n1或者n2,就继续向上传递。
情况二:n1和n2本身没有父子关系,他们有一个公共的父节点,那么,向上传递的信息,n1或者n2就传递他们本身,但是,和上面有一点不同的地方在于,其余节点,有可能接收的返回值包含n1和n2两个,那么,其实这个节点就是最小的公共父类节点,因此,如果接收的左右孩子分别为n1和n2,那么,就返回他自己本身。其余节点还是接收什么就原样向上返回。
因此,总结一下上面分析的结果,向上返回的数据:
本身为n1或者n2,就向上返回自己
接收两个的话,就返回自己
如果接收一个,就原样照抄返回
自己不是n1和n2,且没有接收,就返回null
代码
public static Node getFather(Node node,Node n1,Node n2){
if(node==null||node==n1||node==n2){
return node;
}
Node left=getFather(node.left,n1,n2);
Node right=getFather(node.right,n1,n2);
if(left!=null&&right!=null){
return node;
}
return left!=null ? left:right;
}