给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大 (一个节点也可以是它自己的祖先)
输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出:3
解释:节点 5 和节点 1 的最近公共祖先是节点 3 。
【问题介绍】:
这种题属于最近公共祖先问题中的一次性查询问题。
如果是一次查询,那么解法还是比较多的,例如两次搜索、递归、后续遍历等。如果是多次查询就很难了,需要用到倍增法的预处理。
一次查询和多次查询在力扣上都有题目,下面结合例题给出具体解法。注意多次查询的题目很难,大家可以结合自身对知识的掌握情况选做。
给定一棵有根树,若 z 既是 x 的祖先,又是 y 的祖先,
则称 z 是 x,y 的最近公共祖先,记为 z = lca(x, y)。
lca(x, y) 的两条重要性质:
lca(x, y) 是 x 到根的路径和 y 到根的路径的交点。
lca(x, y) 是 x 到 y 的路径中顺度最小的节点。。
【思路】:
直接暴力法。
遍历每个节点,判断该节点是否同时有a,b两个子节点。如果是,就把它加到栈中,然后继续遍历。最后取出栈中最上面的一个节点,即为最近的公共祖先。
【代码】:
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @param {TreeNode} p p,q都是两个子节点
* @param {TreeNode} q
* @return {TreeNode}
*/
//判断某个节点是不是含有val这个子节点
//return boolean
var hasThisChild = function(node, val){
if(node != null){
if(node.val == val) return true;
return hasThisChild(node.left, val) || hasThisChild(node.right, val);
}else{
return false;
}
}
//return void
var preOrder = function(node, firstChild, secondChild, stack){
if(node != null){
//针对每个节点,去判断它是否含有某个val的子节点
let tag = hasThisChild(node, firstChild.val) && hasThisChild(node, secondChild.val);
if(tag){
stack.push(node);
}
preOrder(node.left, firstChild, secondChild, stack);
preOrder(node.right, firstChild, secondChild, stack);
}
}
var lowestCommonAncestor = function(root, p, q) {
var stack = [];
preOrder(root, p, q, stack);
var len = stack.length;
return stack[len - 1];
};