【剑指offer】 面试题50: 树中两个结点的最低公共祖先

题目描述:

给定一棵树,同时给出树中的两个结点,求它们的最低公共祖先。


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);
				}
			}
		}
	}
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值