-
题目描述:
-
给定一棵树,同时给出树中的两个结点,求它们的最低公共祖先。
-
输入:
-
输入可能包含多个测试样例。
对于每个测试案例,输入的第一行为一个数n(0<n<1000),代表测试样例的个数。
其中每个测试样例包括两行,第一行为一个二叉树的先序遍历序列,其中左右子树若为空则用0代替,其中二叉树的结点个数node_num<10000。
第二行为树中的两个结点的值m1与m2(0<m1,m2<10000)。
-
输出:
-
对应每个测试案例,
输出给定的树中两个结点的最低公共祖先结点的值,若两个给定结点无最低公共祖先,则输出“My God”。
-
样例输入:
-
2 1 2 4 6 0 0 7 0 0 5 8 0 0 9 0 0 3 0 0 6 8 1 2 4 6 0 0 7 0 0 5 8 0 0 9 0 0 3 0 0 6 12
-
样例输出:
-
2 My God
-
分析:
-
如果是二叉查找树,可以利用查找树的性质,有O(lgn)的方法。
这里是一棵普通的二叉树。分为两种情况:(1)已知每个节点的父节点;(2)不知道每个节点的父节点。
如果不知道父节点,采用递归的方法,从上到下(最坏O(n^2)),或从下到上(最坏O(n))均可,参见http://leetcode.com/2011/07/lowest-common-ancestor-of-a-binary-tree-part-i.html
如果知道父节点,可采用非递归的方法,也有两种方法,利用哈希表,或利用节点的高度差(不需要额外空间),复杂度为O(h),h为树的高度,参见http://leetcode.com/2011/07/lowest-common-ancestor-of-a-binary-tree-part-ii.html
此外,第一篇文章里还给出了一个查找复杂度为O(sqt(n)),初始化复杂度为O(n)的方法:http://community.topcoder.com/tc?module=Static&d1=tutorials&d2=lowestCommonAncestor,这个方法很像“1到100层楼,有两个鸡蛋,如何在最少次数内找到鸡蛋临界摔碎的点”的感觉,先分层,再在层里找,不过这里分层是均匀分的。
下面展示的是复杂度为O(h)的非递归、利用节点高度差的方法,已经AC。针对这道题,创建树的过程只需要记录每个节点的父节点即可,左右子节点可以无视,但创建过程复杂度已经O(n)了,还递归了,喧宾夺主了。- -!
解答:
import java.util.HashMap;
import java.util.Scanner;
public class LowestCommonAncestor {
private class TreeNode {
int val;
TreeNode parent;
TreeNode(int x) {
val = x;
}
}
private HashMap<Integer, TreeNode> records = new HashMap<Integer, TreeNode>();
private int[] preOrder;
private int index;
public int lowestCommonAncestor(int[] preOrder, int p, int q) {
if (preOrder.length <= 1) {
return 0;
}
this.preOrder = preOrder;
records.clear();
index = 0;
buildTree(null);
TreeNode p1 = records.get(p);
TreeNode p2 = records.get(q);
if (p1 == null || p2 == null) {
return 0;
}
int h1 = getHeight(p1);
int h2 = getHeight(p2);
if (h1 > h2) {
int tmp = h1;
h1 = h2;
h2 = tmp;
TreeNode tmpNode = p1;
p1 = p2;
p2 = tmpNode;
}
int dh = h2 - h1;
for (int h = 0; h < dh; ++h) {
p2 = p2.parent;
}
while (p1 != null && p2 != null) {
if (p1.equals(p2)) {
return p1.val;
}
p1 = p1.parent;
p2 = p2.parent;
}
return 0;
}
private void buildTree(TreeNode parent) {
int val = preOrder[index++];
if (val != 0) {
TreeNode node = new TreeNode(val);
records.put(val, node);
node.parent = parent;
buildTree(node);
buildTree(node);
}
}
private int getHeight(TreeNode p) {
int height = 0;
while (p != null) {
++height;
p = p.parent;
}
return height;
}
public static int[] str2IntArray(String line) {
String[] strArray = line.split(" ");
int n = strArray.length;
int[] intArray = new int[n];
for (int i = 0; i < n; ++i) {
intArray[i] = Integer.parseInt(strArray[i]);
}
return intArray;
}
public static void main(String[] args) {
LowestCommonAncestor lca = new LowestCommonAncestor();
Scanner reader = new Scanner(System.in);
int n = reader.nextInt();
reader.nextLine();
for (int i = 0; i < n; ++i) {
int[] preOrder = str2IntArray(reader.nextLine());
int[] pq = str2IntArray(reader.nextLine());
int p = pq[0];
int q = pq[1];
int ret = lca.lowestCommonAncestor(preOrder, p, q);
System.out.println(ret == 0 ? "My God" : ret);
}
reader.close();
}
}