剑指offer面试题68 ---- 树中两个节点的最低公共祖先(java实现)
LCA(最近公共祖先)
1.树是二叉搜索树
1 package lca; 2 3 public class BinarySearchTree { 4 public static void main(String args[]) { 5 6 //放树节点的数组 7 TreeNode<Integer> node[] = new TreeNode[7]; 8 9 //给节点赋值的数组 10 int arr[] = {4,2,6,1,3,5,7}; 11 12 //处理引用关系 13 //从0开始对节点编号的话,第i个节点的左子节点下标为2*i+1,右子节点为2*i+2 14 for(int i=6;i>=0;i--) { 15 node[i] = new TreeNode(); 16 node[i].value = arr[i]; 17 //不是叶子节点的话(叶子节点没有子节点),把引用指向叶子节点 18 if (i < node.length/2) { 19 node[i].left = node[2 * i + 1]; 20 node[i].right = node[2 * i + 2]; 21 } 22 } 23 /* 24 4 25 / \ 26 2 6 27 / \ / \ 28 1 3 5 7 29 */ 30 //找值为3的节点和值为5的节点的LCA 31 TreeNode result = findLCA(node[4],node[5],node[0]); 32 33 System.out.println(result); 34 } 35 36 private static TreeNode findLCA(TreeNode node1, TreeNode node2, TreeNode current) { 37 // TODO Auto-generated method stub 38 //当前节点的值 39 int value = (int) current.value; 40 //比当前节点都小就到左子树中去找 41 if(value > (int)node1.value && value > (int)node2.value ) { 42 return findLCA(node1,node2,current.left); 43 } 44 //比当前节点都大就到左子树中去找 45 if(value < (int)node1.value && value < (int)node2.value ) { 46 return findLCA(node1,node2,current.right); 47 } 48 49 //否则就是当前节点 50 //***二叉搜索树的定义是左子节点小于等于根节点,右子节点大于等于根节点。 51 //***对于有值相等的情况也是输出当前节点,比如 52 /* 53 7 54 / \ 55 7 8 56 */ 57 58 return current; 59 } 60 61 62 } 63 64 class TreeNode<T>{ 65 T value; 66 TreeNode left; 67 TreeNode right; 68 @Override 69 public String toString() { 70 return "TreeNode [value=" + value + "]"; 71 } 72 73 }
2.树不是二叉树,但是有指向父节点的引用 ---- 转换为两个链表求公共节点
3.树不是二叉树,也没有指向父节点的引用。
思路 : 使用两个链表保存根节点到两个节点的路径,再求公共节点
1 package lca; 2 3 import java.util.Arrays; 4 5 //树结构定义 6 public class TreeNode1 { 7 char value; 8 TreeNode1 childs[]; 9 @Override 10 public String toString() { 11 return "TreeNode1 [value=" + value + "]"; 12 } 13 14 }
1 package lca; 2 3 import java.util.LinkedList; 4 5 public class WithoutParentNode { 6 7 static final int maxNumOfChilds = 10; 8 //使用两个链表来保存根节点到所求节点的路径 9 static LinkedList list1 = new LinkedList(); 10 static LinkedList list2 = new LinkedList(); 11 12 public static void main(String args[]) { 13 TreeNode1 A = new TreeNode1(); 14 A.value = 'A'; 15 TreeNode1 B = new TreeNode1(); 16 B.value = 'B'; 17 TreeNode1 C = new TreeNode1(); 18 C.value = 'C'; 19 TreeNode1 D = new TreeNode1(); 20 D.value = 'D'; 21 TreeNode1 E = new TreeNode1(); 22 E.value = 'E'; 23 TreeNode1 F = new TreeNode1(); 24 F.value = 'F'; 25 TreeNode1 G = new TreeNode1(); 26 G.value = 'G'; 27 TreeNode1 H = new TreeNode1(); 28 H.value = 'H'; 29 TreeNode1 I = new TreeNode1(); 30 I.value = 'I'; 31 TreeNode1 J = new TreeNode1(); 32 J.value = 'J'; 33 A.childs = new TreeNode1[] {B,C}; 34 B.childs = new TreeNode1[] {D,E}; 35 D.childs = new TreeNode1[] {F,G}; 36 E.childs = new TreeNode1[] {H,I,J}; 37 /* 38 A 39 / \ 40 B C 41 / \ 42 D E 43 / \ / | \ 44 F G H I J 45 */ 46 47 //找F,H节点的LCA 48 TreeNode1 lca = findLCA(F,H,A); 49 System.out.println(lca); 50 } 51 52 53 private static TreeNode1 findLCA(TreeNode1 node1, TreeNode1 node2, TreeNode1 root) { 54 // TODO Auto-generated method stub 55 getPathFromRootToNode(node1,root,list1); 56 getPathFromRootToNode(node2,root,list2); 57 //list1 : D -- B -- A 58 //list2 : E -- B -- A 59 60 //接下来遍历两个链表找到最近的公共节点 61 int index = 0; 62 int length1 = list1.size(); 63 int length2 = list2.size(); 64 int sub = length1 > length2?length1-length2:length2-length1; 65 if(length2 > length1) { 66 LinkedList temp = list1; 67 list1 = list2; 68 list2 = temp; 69 } 70 while(index != length2-1) { 71 if(((TreeNode1)list1.get(index+sub)).value == ((TreeNode1)list2.get(index)).value) { 72 return (TreeNode1)list2.get(index); 73 }else { 74 index++; 75 } 76 } 77 return null; 78 } 79 80 81 private static boolean getPathFromRootToNode(TreeNode1 node, TreeNode1 currentRoot, LinkedList list) { 82 // TODO Auto-generated method stub 83 84 //找到就直接返回true 85 if(node.value == currentRoot.value) { 86 return true; 87 } 88 89 //找不到就将当前节点加入路径,push是在链表的头插入的,offer是尾部 90 list.push(currentRoot); 91 92 boolean found = false; 93 94 TreeNode1[] childs = currentRoot.childs; 95 if (childs != null && childs.length > 0) { 96 //遍历当前节点的所有子节点,在子节点里边找 97 for (int i = 0; i < childs.length; i++) { 98 if (found) { 99 break; 100 } else { 101 found = getPathFromRootToNode(node, childs[i], list); 102 } 103 } 104 } 105 //找不到就将当前节点从路径中删除,因为是递归,当递归回来到这里的时候,当前节点一定是list的最后一个节点,即栈顶 106 if(!found) { 107 list.pop(); 108 } 109 110 return found; 111 } 112 113 114 }