情景一:
假设该树是一棵二叉搜索树:
我们只需从根结点判断,如果二结点与根的左右子树比较一大一小,那么跟结点就是二者最低公共祖先;如果二结点都比左子结点小,向左子树递归进行比较;如果二结点都比右子树结点大,向右子树递归进行比较;
public static TreeNode getLastCommonNode(TreeNode pRoot,TreeNode pLeft,
TreeNode pRight) {
TreeNode treeNode = null;
if(pRoot==null || pLeft.val>pRight.val)
return null;
if((pRoot.val>=pRight.val) && (pRoot.val>=pLeft.val))
treeNode = getLastCommonNode(pRoot.left,pLeft,pRight);
if((pRoot.val<=pLeft.val) && (pRoot.val<=pRight.val))
treeNode = getLastCommonNode(pRoot.right,pLeft,pRight);
if(pRoot.val>=pLeft.val && pRoot.val<=pRight.val)
return pRoot;
return treeNode;
}
情景二:
假设该树是一棵普通的树,且有指向父节点的指针:
如果不是二叉搜索树,但带有指向父节点的指针,那么此题转换成在两个有相交的链表上求第一个相交点。
从下到上查找
package jianZhiOffer;
import java.util.ArrayList;
import java.util.HashMap;
/*
* //方法2:假设是普通的树,但是每个节点都有指向父节点的指针,类似于链表找公共节点
*/
public class Demo6802 {
private class TreeNode<T>{
T data;
TreeNode<T> parent = null;
ArrayList<TreeNode<T>> children = new ArrayList<TreeNode<T>>();
TreeNode(T data){
this.data = data;
}
}
public static void main(String[] args) {
Demo6802 my = new Demo6802();
TreeNode A = my.new TreeNode('A');
TreeNode B = my.new TreeNode('B');
TreeNode C = my.new TreeNode('C');
TreeNode D = my.new TreeNode('D');
TreeNode E = my.new TreeNode('E');
TreeNode F = my.new TreeNode('F');
TreeNode G = my.new TreeNode('G');
TreeNode H = my.new TreeNode('H');
G.parent = E;
E.parent = B;
B.parent = A;
F.parent = D;
D.parent = B;
C.parent = A;
System.out.println(findParent(A, F, G));
}
//Object类型的方法返回的类型不受限制,Object是所有类的父类
private static Object findParent(TreeNode<Character> root,
TreeNode<Character> node1,TreeNode<Character> node2) {
if(node1==null || node2==null)
return null;
//得到两链表的长度
int len1=1,len2=1;
TreeNode<Character> temp=node1;
while(temp.parent!=null) {
len1++;
temp=temp.parent;
}
temp=node2;
while(temp.parent!=null) {
len2++;
temp=temp.parent;
}
//长度长的链表先移动
int step = Math.abs(len1-len2);
TreeNode tempLong = len1>=len2? node1:node2;
TreeNode tempShort = len1<len2? node1:node2;
for(int i=0;i<step;i++)
tempLong = tempLong.parent;
//两链表一起移动,知道找到相等的节点则返回
for(int i=0;i<Math.min(len1, len2);i++) {
if(tempLong.data==tempShort.data) {
return tempLong.data;
}
tempLong = tempLong.parent;
tempShort = tempShort.parent;
}
return null;
}
}
情景三:
假设该树是普通的树,且没有指向父节点的指针:
需要保存从root根节点到p和q节点的路径,并将路径存入list中,则问题转化成求两个list集合的最后一个公共元素
从上到下查找
package jianZhiOffer;
import java.util.ArrayList;
import java.util.List;
public class Demo6801 {
private static class TreeNode{
int val;
List<TreeNode> children = new ArrayList<>();
public TreeNode(int val) {
this.val = val;
}
@Override
//重写
public String toString() {
return val+"";
}
}
public static void main(String[] args) {
// 形状普通的树
// 1
// / \
// 2 3
// / \
// 4 5
// / \ / | \
// 6 7 8 9 10
TreeNode n1 = new TreeNode(1);
TreeNode n2 = new TreeNode(2);
TreeNode n3 = new TreeNode(3);
TreeNode n4 = new TreeNode(4);
TreeNode n5 = new TreeNode(5);
TreeNode n6 = new TreeNode(6);
TreeNode n7 = new TreeNode(7);
TreeNode n8 = new TreeNode(8);
TreeNode n9 = new TreeNode(9);
TreeNode n10 = new TreeNode(10);
n1.children.add(n2);
n1.children.add(n3);
n2.children.add(n4);
n4.children.add(n6);
n4.children.add(n7);
n3.children.add(n5);
n5.children.add(n8);
n5.children.add(n9);
n5.children.add(n10);
System.out.println(getLastCommonParent(n1, n9, n10));
}
//方法3:假设是一棵普通的树,子节点没有指向父节点的指针
//需要保存从root根节点到p和q节点的路径,并将路径存入list中,
//则问题转化成求两个list集合的最后一个公共元素
public static TreeNode getLastCommonParent(TreeNode root,TreeNode p1,
TreeNode p2) {
//存储根节点到p1和p2的路径(不包括p1和p2)
List<TreeNode> path1 = new ArrayList<TreeNode>();
List<TreeNode> path2 = new ArrayList<TreeNode>();
List<TreeNode> tmpList = new ArrayList<TreeNode>();
getNodePath(root,p1,tmpList,path1);
getNodePath(root,p2,tmpList,path2);
//如果路径不存在,返回空
if(path1.size()==0 || path2.size()==0)
return null;
return getLastCommonParent(path1,path2);
}
//获取根节点到目标节点的路径
public static void getNodePath(TreeNode root,TreeNode target,
List<TreeNode>tmpList,List<TreeNode>path) {
//鲁棒性
if(root==null || root==target)
return ;
tmpList.add(root);
//System.out.println(root);
List<TreeNode> children = root.children;
for(TreeNode node : children) {
if(node==target) {
path.addAll(tmpList);
break;
}
getNodePath(node,target,tmpList,path);
}
tmpList.remove(tmpList.size()-1);
}
//将问题转换为求链表最后一个公共节点
private static TreeNode getLastCommonParent(List<TreeNode>p1,
List<TreeNode>p2) {
TreeNode tmpNode = null;
for(int i=0;i<p1.size();i++) {
if(p1.get(i) != p2.get(i))
break;
tmpNode = p1.get(i);
}
return tmpNode;
}
}