題目:java
樹中兩個節點的最低公共祖先。.net
最近公共祖先簡稱LCA(Lowest Common Ancestor),所謂LCA,是當給定一個有根樹T時,對於任意兩個結點u、v,找到一個離根最遠的結點x,使得x同時是u和v的祖先,x 即是u、v的最近公共祖先。指針
思路一:排序
輸入兩個樹節點,求他們的最低公共祖先,內存
——若是是二叉樹,並且是二叉搜索樹,那麼是能夠找到公共節點的。get
二叉搜索樹都是排序過的,位於左子樹的節點都比父節點小,而位於右子樹上面的節點都比父節點大。ast
package cglib;class
class TreeNode {
int data;
TreeNode left;
TreeNode right;
}效率
public class List1
{
public static TreeNode getLastCommonParent(TreeNode root,TreeNode a,TreeNode b)
{
if (root==null || a==null || b==null)
return null;
while (root != null) {
if (root.data > a.data && root.data > b.data )
root = root.left;
else if (root.data < a.data && root.data < b.data)
root = root.right;
else
return root;
}
return null;
}
public static void main(String args[]){
TreeNode n1 = new TreeNode();
TreeNode n2 = new TreeNode();
TreeNode n3 = new TreeNode();
TreeNode n4 = new TreeNode();
TreeNode n5 = new TreeNode();
TreeNode n6 = new TreeNode();
TreeNode n7 = new TreeNode();
n1.left=n2;
n1.right=n3;
n2.left=n4;
n2.right=n5;
n3.left=n6;
n3.right=n7;
n1.data=10;
n2.data=8;
n3.data=13;
n4.data=4;
n5.data=9;
n6.data=12;
n7.data=17;
// 搜索二叉樹
// 10
// / \
// 8 13
// / \ / \
// 4 9 12 17
System.out.println(n1.data);
System.out.println(n6.data);
System.out.println(n7.data);
TreeNode parent=getLastCommonParent(n1, n6, n7);
System.out.println(parent.data);
}import
}
輸出:
10
12
17
13
思路二:
若是這棵樹是普通的樹,並且樹中結點沒有指向父結點的指針,解法以下:
思路三:
咱們能夠用深度優先搜索,從葉子節點向上,標記子樹中出現目標節點的狀況。若是子樹中有目標 節點,標記爲那個目標節點,若是沒有,標記爲null。顯然,若是左子樹、右子樹都有標記,說明就已經找到最小公共祖先了。若是在根節點爲p的左右子樹中 找p、q的公共祖先,則一定是p自己。
換個角度,能夠這麼想:若是一個節點左子樹有兩個目標節點中的一個,右子樹沒有,那這個節點 確定不是最小公共祖先。若是一個節點右子樹有兩個目標節點中的一個,左子樹沒有,那這個節點確定也不是最小公共祖先。只有一個節點正好左子樹有,右子樹也 有的時候,纔是最小公共祖先。
package cglib;
class TreeNode {
int data;
TreeNode left;
TreeNode right;
}
public class List1
{
//兩個節點的最低公共祖先,參數爲兩個節點
public static TreeNode getLastCommonParent(TreeNode root,TreeNode a,TreeNode b)
{
//發現目標節點則經過返回值標記該子樹發現了某個目標結點
//若是在根節點爲a的左右子樹中找a、b的公共祖先,則一定是a自己。
//同理,若是在根節點爲b的左右子樹中找a、b的公共祖先,則一定是b自己。
if (root == null || root == a || root == b)
return root;
//查看左子樹中是否有目標結點,沒有爲null
TreeNode left = getLastCommonParent(root.left, a, b);
//查看右子樹是否有目標節點,沒有爲null
TreeNode right = getLastCommonParent(root.right, a, b);
//都不爲空,說明左右子樹都有目標結點,則公共祖先就是自己
if (left != null&&right != null)
return root;
//若是發現了目標節點,則繼續向上標記爲該目標節點
return left == null ? right : left;
}
public static void main(String args[]){
TreeNode n1 = new TreeNode();
TreeNode n2 = new TreeNode();
TreeNode n3 = new TreeNode();
TreeNode n4 = new TreeNode();
TreeNode n5 = new TreeNode();
TreeNode n6 = new TreeNode();
TreeNode n7 = new TreeNode();
n1.left=n2;
n1.right=n3;
n2.left=n4;
n2.right=n5;
n3.left=n6;
n3.right=n7;
n1.data=1;
n2.data=2;
n3.data=3;
n4.data=4;
n5.data=5;
n6.data=6;
n7.data=7;
// 搜索二叉樹
// 1
// / \
// 2 3
// / \ / \
// 4 5 6 7
System.out.println(n1.data);
System.out.println(n6.data);
System.out.println(n7.data);
TreeNode parent=getLastCommonParent(n1, n6, n7);
System.out.println(parent.data);
}
}
輸出:
1
6
7
3
以上解法須要對同一個結點重複遍歷不少次,效率較低,若是容許使用輔助內存,則能夠有效率更高的方法,解法以下:
package cglib;
import java.util.Stack;
class TreeNode {
int data;
TreeNode left;
TreeNode right;
}
public class List1
{
public static TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q){
Stack<TreeNode> stackp = new Stack<TreeNode>();
Stack<TreeNode> stackq = new Stack<TreeNode>();
getPath(root, p, stackp);
getPath(root, q, stackq);
return lowestCommonAncestor(stackp, stackq);
}
private static TreeNode lowestCommonAncestor(Stack<TreeNode> stackp, Stack<TreeNode> stackq) {
TreeNode target = null;
while (!stackp.isEmpty() && !stackq.isEmpty() && stackp.peek() == stackq.peek())
{
target = stackp.peek();
stackp.pop();
stackq.pop();
}
return target;
}
private static boolean getPath(TreeNode root, TreeNode p, Stack<TreeNode> stackp) {
// TODO Auto-generated method stub
if (root == null)
return false;
if (root == p)
{
stackp.push(root);
return true;
}
else
{
if (getPath(root.left, p, stackp) || getPath(root.right, p, stackp))
{
stackp.push(root);
return true;
}
}
return false;
}
/***
*
* 這個代碼在實現過程當中,是當找到給定節點的時候纔將路徑依次壓入stack中的,
* 也就是說,兩個stack的棧頂都是存放着root節點。
* 所以,此時就應該找兩條路徑分離開以前的最後一個節點,
* 此節點就是所求的最低公共祖先。
* @param args
*/
public static void main(String args[]){
TreeNode n1 = new TreeNode();
TreeNode n2 = new TreeNode();
TreeNode n3 = new TreeNode();
TreeNode n4 = new TreeNode();
TreeNode n5 = new TreeNode();
TreeNode n6 = new TreeNode();
TreeNode n7 = new TreeNode();
n1.left=n2;
n1.right=n3;
n2.left=n4;
n2.right=n5;
n3.left=n6;
n3.right=n7;
n1.data=1;
n2.data=2;
n3.data=3;
n4.data=4;
n5.data=5;
n6.data=6;
n7.data=7;
// 搜索二叉樹
// 1
// / \
// 2 3
// / \ / \
// 4 5 6 7
System.out.println(n1.data);
System.out.println(n6.data);
System.out.println(n7.data);
TreeNode parent=lowestCommonAncestor(n1, n6, n7);
System.out.println(parent.data);
}
}
輸出: 1 6 7 3