题目:求树中两个结点的最低公共祖先
分析:其实这是一组题目,考官没有说清楚树的结构,那么做法就不尽相同。
比如,如果是二叉搜索树的话,我们只需从根结点判断,如果二结点与根的左右子树比较一大一小,那么跟结点就是二者最低公共祖先;如果二结点都比左子结点小,向左子树递归进行比较;如果二结点都比右子树结点大,向右子树递归进行比较;
如果不是二叉搜索树,但带有指向父节点的指针,那么此题转换成在两个有相交的链表上求第一个相交点。
如果不带指向父节点的指针,那么我们可以记录从根结点到这两个结点的路径即可求出。
以下代码是:普通树(多个子树),子树没有指向父节点的指针
package go.jacob.day520;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import javax.management.RuntimeErrorException;
public class Demo1 {
public static void main(String[] args) {
test01();
System.out.println("==========");
test02();
System.out.println("==========");
test03();
}
// 形状普通的树
// 1
// / \
// 2 3
// / \
// 4 5
// / \ / | \
// 6 7 8 9 10
public static void test01() {
TreeNode n1 = new TreeNode(1);
TreeNode n2 = new TreeNode(2);
TreeNode n3 = new TreeNode(3);
TreeNode n4 = new TreeNode(4);
TreeNode n5 = new TreeNode(5);
TreeNode n6 = new TreeNode(6);
TreeNode n7 = new TreeNode(7);
TreeNode n8 = new TreeNode(8);
TreeNode n9 = new TreeNode(9);
TreeNode n10 = new TreeNode(10);
n1.children.add(n2);
n1.children.add(n3);
n2.children.add(n4);
n4.children.add(n6);
n4.children.add(n7);
n3.children.add(n5);
n5.children.add(n8);
n5.children.add(n9);
n5.children.add(n10);
System.out.println(getLastCommonParent(n1, n9, n10));
}
// 树退化成一个链表
// 1
// /
// 2
// /
// 3
// /
// 4
// /
// 5
private static void test02() {
TreeNode n1 = new TreeNode(1);
TreeNode n2 = new TreeNode(2);
TreeNode n3 = new TreeNode(3);
TreeNode n4 = new TreeNode(4);
TreeNode n5 = new TreeNode(5);
n1.children.add(n2);
n2.children.add(n3);
n3.children.add(n4);
n4.children.add(n5);
System.out.println(getLastCommonParent(n1, n4, n5));
}
// 树退化成一个链表,一个结点不在树中
// 1
// /
// 2
// /
// 3
// /
// 4
// /
// 5
private static void test03() {
TreeNode n1 = new TreeNode(1);
TreeNode n2 = new TreeNode(2);
TreeNode n3 = new TreeNode(3);
TreeNode n4 = new TreeNode(4);
TreeNode n5 = new TreeNode(5);
TreeNode n6 = new TreeNode(6);
n1.children.add(n2);
n2.children.add(n3);
n3.children.add(n4);
n4.children.add(n5);
System.out.println(getLastCommonParent(n1, n5, n6));
}
/*
* 获取两个节点的最低公共祖先
*/
public static TreeNode getLastCommonParent(TreeNode root, TreeNode p1, TreeNode p2) {
//path1和path2分别存储根节点到p1和p2的路径(不包括p1和p2)
List<TreeNode> path1 = new ArrayList<TreeNode>();
List<TreeNode> path2 = new ArrayList<TreeNode>();
List<TreeNode> tmpList = new ArrayList<TreeNode>();
getNodePath(root, p1, tmpList, path1);
getNodePath(root, p2, tmpList, path2);
//如果路径不存在,返回空
if (path1.size() == 0 || path2.size() == 0)
return null;
return getLastCommonParent(path1, path2);
}
// 获取根节点到目标节点的路径
public static void getNodePath(TreeNode root, TreeNode target, List<TreeNode> tmpList, List<TreeNode> path) {
//鲁棒性
if (root == null || root == target)
return;
tmpList.add(root);
List<TreeNode> children = root.children;
for (TreeNode node : children) {
if (node == target) {
path.addAll(tmpList);
break;
}
getNodePath(node, target, tmpList, path);
}
tmpList.remove(tmpList.size() - 1);
}
//将问题转化为求链表最后一个共同节点
private static TreeNode getLastCommonParent(List<TreeNode> p1, List<TreeNode> p2) {
TreeNode tmpNode = null;
for (int i = 0; i < p1.size(); i++) {
if (p1.get(i) != p2.get(i))
break;
tmpNode = p1.get(i);
}
return tmpNode;
}
// 节点类
private static class TreeNode {
int val;
List<TreeNode> children = new ArrayList<>();
public TreeNode(int val) {
this.val = val;
}
@Override
public String toString() {
return val + "";
}
}
}
点击打开链接