题目描述:
给定一棵树,同时给出树中的两个结点,求它们的最低公共祖先。
1 2 4 6 0 0 7 0 0 5 8 0 0 9 0 0 3 0 0 6 8存在, 2
1 2 4 6 0 0 7 0 0 5 8 0 0 9 0 0 3 0 0 6 12
不存在
方法一:
后序遍历
基本思想:
1、两个节点不在一条线上(即两个节点不存在一个节点是另一个节点的祖先的情况),则它们必定分别在所求节点A的左子树和右子树上,
后序遍历到第一个满足这个条件的节点就是所要求的节点A。
2、当这两个节点在一条线上,所求节点A则是这两个节点中深度最低的节点的父节点。
package com.offer.chapter_7;
import java.util.Scanner;
class BinaryTreeNode {
public int elem;
public BinaryTreeNode left;
public BinaryTreeNode right;
}
/**
* @author hadoop
*
* 求二叉树中任意两个节点的最近公共祖先也称为LCA问题(Lowest Common Ancestor)
*
*/
public class Interviews_50 {
public static int curIndex = 0;
public static BinaryTreeNode result = null;
/**
*
* 构建二叉树
*
*/
public static void createBinaryTree(BinaryTreeNode curRoot, int[] data) {
int leftElem = data[curIndex ++];
if(leftElem == 0) {
curRoot.left = null;
} else {
BinaryTreeNode leftChild = new BinaryTreeNode();
leftChild.elem = leftElem;
leftChild.left = leftChild.right = null;
curRoot.left = leftChild;
createBinaryTree(curRoot.left, data);
}
int rightElem = data[curIndex ++];
if(rightElem == 0) {
curRoot.right = null;
} else {
BinaryTreeNode rightChild = new BinaryTreeNode();
rightChild.elem = rightElem;
rightChild.left = rightChild.right = null;
curRoot.right = rightChild;
createBinaryTree(curRoot.right, data);
}
}
/**
*
* 基本思想:如果这两个节点不在一条线上(即这两个节点不存在一个节点是另一个节点的祖先的情况),则它们必定分别在所求节点A的左子树和右子树上,
* 后序遍历到第一个满足这个条件的节点就是所要求的节点A。否则,当这两个节点在一条线上,所求节点A则是这两个节点中深度最低的节点的父节点。
*
* result 始终记录当前是否已经找到目标共同祖先结点
*
*/
public static int findLowestCommonAncestor(BinaryTreeNode curRoot, int a, int b, BinaryTreeNode parent) {
int left = 0;
int right = 0;
// 判断左子树是否含有要判断的两节点之一
if(result == null && curRoot.left != null) {
left = findLowestCommonAncestor(curRoot.left, a, b, curRoot);
}
// 判断右子树是否含有要判断的两节点之一
if(result == null && curRoot.right != null) {
right = findLowestCommonAncestor(curRoot.right, a, b , curRoot);
}
// 判断当前结点是否是所查找结点之一
int mid = 0;
if(curRoot.elem == a || curRoot.elem ==b) {
mid = 1;
}
// 当前已经找到两个结点
if(result == null && (left + right + mid) == 2) {
// 如果两个结点在一条路径上,则当前结点的父节点为共同祖先结点
if(mid == 1) {
result = parent;
} else {
// 如果分别在当前结点的左右子树上,则当前结点为共同祖先结点
result = curRoot;
}
}
// 返回当前子树中包含查找结点的个数
return (left + right + mid) > 0 ? 1 : 0;
}
/**
* 二叉树中任意两个节点的最近公共祖先
*/
public static void LowestCommonAncestor(BinaryTreeNode root, int a, int b) {
result = null;
if(root == null) {
return;
}
findLowestCommonAncestor(root, a, b, null);
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int num = scanner.nextInt();
while(num -- > 0) {
BinaryTreeNode root = null;
scanner.nextLine();
String string = scanner.nextLine();
String[] strs = string.split(" ");
int[] data = new int[strs.length];
int a = scanner.nextInt();
int b = scanner.nextInt();
for(int i=0; i<strs.length; i++) {
data[i] = Integer.parseInt(strs[i]);
}
if(data.length < 2) {
System.out.println("My God");
} else {
root = new BinaryTreeNode();
root.elem = data[0];
curIndex = 1;
createBinaryTree(root, data);
LowestCommonAncestor(root, a, b);
if(result == null) {
System.out.println("My God");
} else {
System.out.println(result.elem);
}
}
}
}
}