题目: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