Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree.
According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes v and w as the lowest node in T that has both v and w as descendants (where we allow a node to be a descendant of itself).”
_______3______
/ \
___5__ ___1__
/ \ / \
6 _2 0 8
/ \
7 4
找到两个节点的最近公共祖先,思想是找到这两个节点并找到这两个节点到根节点的路径,从下往上找到第一个相同的节点。
首先我想到的是使用递归找到这两个节点,并将路径保存在一个数组中,但是这样在递归的过程中会用掉太多的内存:
var lowestCommonAncestor = function(root, p, q) {
var paths = [];
var find = function(root, node, path) {
if (root===null) {
return 1;
}
path.push(root);
if (root===node) {
paths.push(path);
return 1;
}
find(root.left,node,path.concat());
find(root.right,node,path.concat());
return 1;
};
find(root,p,[]);
find(root,q,[]);
console.log(paths)
var n1 = paths[0].length;
var n2 = paths[1].length;
if (n1!==0&&n2!==0) {
for (let i = n1 - 1;i >= 0;i--) {
for (let j = n2 - 1;j >= 0;j--) {
if (paths[0][i]===paths[1][j])
return paths[0][j];
}
}
}
return null;
};
这主要是因为有太多的path保存了太多冗余的信息。
换一种思路,我们使用一个map来保存每个节点的父节点,这样我们在找到这两个节点的时候可以通过map生成这两个节点的路径,所以这个map中最多保存n个节点的数据。
然后使用传统的遍历方法找这两个节点就好了
var lowestCommonAncestor = function(root, p, q) {
if (!root)
return null;
var parent = new Map();
var stack = [];
parent[root.val] = undefined;
stack.push(root);
while ((parent.get(p) ===undefined || parent.get(q)===undefined) && stack.length!==0) {
var node = stack.pop();
if (node.left !== null) {
parent.set(node.left,node);
stack.push(node.left);
}
if (node.right !== null) {
parent.set(node.right,node);
stack.push(node.right);
}
}
var ancestors = [];
while (p !== undefined) {
ancestors.push(p);
p = parent.get(p);
}
while (q !== undefined) {
for (var i = 0;i < ancestors.length;i++ ) {
if (q===ancestors[i])
return q;
}
q = parent.get(q);
}
};