在二叉树中找到两个节点的最近公共祖先
给定一棵二叉树以及这棵树上的两个节点 o1 和 o2,请找到 o1 和 o2 的最近公共祖先节点。
示例1
输入
[3,5,1,6,2,0,8,#,#,7,4],5,1
输出
3
来源
我:
import java.util.*;
/*
* public class TreeNode {
* int val = 0;
* TreeNode left = null;
* TreeNode right = null;
* }
*/
public class Solution {
/**
*
* @param root TreeNode类
* @param o1 int整型
* @param o2 int整型
* @return int整型
*/
int o1;
int o2;
int commonFather;
public int lowestCommonAncestor (TreeNode root, int o1, int o2) {
// write code here
this.o1 = o1;
this.o2 = o2;
traverse(root, root.val, null);
return this.commonFather;
}
/**
*利用先序遍历的思想,在遍历的时候进行判断操作
*向左或向右遍历,找到第一个结点最近祖先
*再继续遍历,直到找到第二个结点,当前记录的最近祖先即是要求的最近祖先
*
*在当前找到的最近祖先结点要向上返回值的时候,要返回其父亲的值作为新的当前找到的最近祖先结点
*好了,我说不明白了,自己体会
*father记录当前结点的父亲结点值,commonFather是目前找到的o1或o2的共同祖先(包括本身)。
*返回值是当前这个结点遍历后能找到的共同祖先
**/
public Integer traverse(TreeNode node, int father, Integer commonFather) {
if (node == null) return commonFather;
if ((commonFather != null) && (node.val == o1 || node.val == o2))
this.commonFather = commonFather;//如果找到共同祖先,并且同时又找到o1或o2的另外一个,那么可以确定最近共同祖先
if (node.val == o1) {//如果找到o1或o2其中一个,那么将其设为共同祖先
commonFather = o1;
} else if (node.val == o2) {
commonFather = o2;
}
commonFather = traverse(node.left, node.val, commonFather);//遍历左子树
commonFather = traverse(node.right, node.val, commonFather);//遍历右子树
if (commonFather != null && node.val == commonFather) //在返回commonFather前,先进行判断
commonFather = father; //如果当前结点已经是一个共同祖先值,并且左右子树已经遍历完,则要返回当前结点的父亲
return commonFather;
}
}
大神:
就是向左找,找到就向上传;
/*最近公共祖先和o1,o2有三种关系:
o1,o2分别在祖先左右两侧
祖先是o1,o2在祖先左/右侧
祖先是o2,o1在祖先左/右侧
使用dfs深度遍历,如果节点为o1,o2中其中一个直接返回,如果节点超过叶子节点也返回
*/
public int lowestCommonAncestor (TreeNode root, int o1, int o2) {
return CommonAncestor(root, o1, o2).val;
}
public TreeNode CommonAncestor (TreeNode root, int o1, int o2) {
if (root == null || root.val == o1 || root.val == o2) { // 超过叶子节点,或者root为p、q中的一个直接返回
return root;
}
TreeNode left = CommonAncestor(root.left,o1,o2); // 返回左侧的p\q节点
TreeNode right = CommonAncestor(root.right,o1,o2); // 返回右侧的p\q节点
if (left == null) { // 都在右侧
return right;//左找不到,则取决于右
}
if (right == null) { // 都在左侧
return left;//右找不到,则取决于左
}
return root; // 在左右两侧
//两边都找到,则取决于当前结点
}