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 }