BST的最近公共祖先结点
链接:235. Lowest Common Ancestor of a Binary Search Tree。
- 如果根节点等于p或q,那么该根节点就是p和q的最近公共祖先结点;
- 如果根节点值位于p和q的值之间,说明p和q分别在其左右子树上,那么根节点就是p和q的最近公共祖先;
- 如果根节点值大于p和q的值,说明p和q都在根节点的左子树上,我们去根节点的左子树上找;
- 如果根节点值小于p和q的值,说明p和q都在根节点的右子树上,我们去根节点的右子树上找。
var lowestCommonAncestor = function(root, p, q) {
const max = Math.max(p.val,q.val), min = Math.min(p.val,q.val);
let res = null;
dfs(root);
return res;
function dfs(node) {
if (res||!node) return;
if (node.val===p.val) res = p;
else if (node.val===q.val) res = q;
else if (node.val>min&&node.val<max) res = node;
else if (node.val>max) dfs(node.left);
else dfs(node.right);
}
};
二叉树的最近公共祖先结点
链接:236. Lowest Common Ancestor of a Binary Tree。
思路一:首先通过dfs找到从根节点到p、q结点的路径,这两条路径的前面部分是他俩的公共祖先结点,只要找到最后一个相同的结点即可。
var lowestCommonAncestor = function(root, p, q) {
const path1 = [], path2 = [];
getPath(root,p,path1);
getPath(root,q,path2);
let res = null;
const min = Math.min(path1.length,path2.length);
for (let i = 0; i < min; i++) {
if (path1[i]===path2[i]) res = path1[i];
else return res;
}
return res;
function getPath(node, targetNode, path) {
if (!node) return false;
path.push(node);
if (targetNode===node) return true;
else {
if (getPath(node.left,targetNode,path)) return true;
if (getPath(node.right,targetNode,path)) return true;
path.pop();
return false;
}
}
};
思路二:与第一题类似,dfs,如果p和q分别在某结点的左右子树上,那么该结点就是p和q的最近公共祖先;如果某节点等于p或q,且其子树上有q或p,则该结点也是p和q的最近公共祖先。因此我们每个dfs中要返回该子树上是否包含p和q。
var lowestCommonAncestor = function(root, p, q) {
let res = null;
dfs(root);
return res;
function dfs(node) {
// 返回2:该子树上有p和q;返回1:该子树上有p和q之一;返回0:该子树上无p或q
if (!node) return 0;
if (res) return 2;
let left = dfs(node.left);
if (left===2) return 2;
if (left===1&&(node===p||node===q)) {
res = node;
return 2;
}
let right = dfs(node.right);
if (right===2) return 2;
if (right===1&&(node===p||node===q)) {
res = node;
return 2;
}
if (left+right===2) {
res = node;
return 2;
}
return left+right+(node===p||node===q)?1:0;
}
};
最深叶节点的最近公共祖先
链接:1123. Lowest Common Ancestor of Deepest Leaves。
一种思路是参考第二题的思路一,找到所有从根节点到最深叶节点的路径,然后找到最后一个公共祖先结点。
还有一种更好的方法:对于一个结点,如果它的左右子树高度相等,那么它就是它所在根节点的最深叶节点的最近公共祖先结点。看代码。
var lcaDeepestLeaves = function(root) {
let res = null, maxDepth = 0;
dfs(root,0);
return res;
function dfs(node,depth) {
// 返回该子树最深深度
if (!node) return depth;
let d1 = dfs(node.left,depth+1), d2 = dfs(node.right,depth+1);
if (d1===d2&&d1>=maxDepth) {
res = node;
maxDepth = d1;
}
return Math.max(d1,d2);
}
};