題目說明
給定一個二叉樹, 找到該樹中兩個指定節點的最近公共祖先。
百度百科中最近公共祖先的定義爲:“對於有根樹 T 的兩個結點 p、q,最近公共祖先表示爲一個結點 x,
滿足 x 是 p、q 的祖先且 x 的深度儘可能大(一個節點也可以是它自己的祖先)。”
例如,給定如下二叉樹: root = [3,5,1,6,2,0,8,null,null,7,4]
示例 1:
輸入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
輸出: 3
解釋: 節點 5 和節點 1 的最近公共祖先是節點 3。
示例 2:
輸入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
輸出: 5
解釋: 節點 5 和節點 4 的最近公共祖先是節點 5。因爲根據定義最近公共祖先節點可以爲節點本身。
說明:
所有節點的值都是唯一的。
p、q 爲不同節點且均存在於給定的二叉樹中。
解題思路一
層序
遍歷二叉樹,每遍歷到一個節點,就收集
該節點在內的所有子節點
。- 該節點
子節點集合
中是否同時存在p,q
,如果存在
,標記該節點,flag爲true
代表:該節點是p,q的一個公共祖先
,然後依次遍歷其左右節點
的子節點集合
。 - 若不存在,說明其子節點的集合肯定也不存在,就中斷遞歸,沒必要再繼續了。
- 最終遞歸會在左右節點都不存在的情況下終止遍歷。形成一個帶有標記的樹,每個節點上標記有
flag爲true
的都是p,q的公共祖先
- 最後再進行一次層序遍歷,收集
flag爲true
的節點,然後數組的末尾一位就是他們的最近公共祖先。
注意: 題目中的5,步驟也可以放在 2-3步驟中同時進行收集。
代碼實現中,我使用了unshift(),所以輸出的是第一位。
代碼實現一
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @param {TreeNode} p
* @param {TreeNode} q
* @return {TreeNode}
*/
// 注意是返回節點,不是返回節點的值!!!
var lowestCommonAncestor = function(root, p, q) {
p = p.val;
q = q.val;
find(root, p, q);
let help = [root]
let res = [];
while (help.length) {
let now = help.shift();
if(now.flag) {
res.unshift(now);
now.left && help.push(now.left);
now.right && help.push(now.right);
}
}
return res[0]
};
function find(root, p, q) {
let help = [root]
let res = [];
while (help.length) {
let now = help.shift();
res.push(now.val);
now.left && help.push(now.left);
now.right && help.push(now.right);
}
if (res.indexOf(p) !== -1 && res.indexOf(q) !== -1) {
root.flag = true;
root.left && (find(root.left, p, q))
root.right && (find(root.right, p, q))
}
}
解題思路二
- 收集所有的節點的祖先節點,類似於動態規劃,
每個節點
的所有公共祖先都是父節點所有公共祖先
的加上該節點本身
。 - 通過動態規劃和遞歸進行收集。
- 判斷該節點是否是
p
或者q
,收集
到對象中。 - 二叉樹遍歷完成後,將收集到的p,q所有的祖先節點進行遍歷,
倒序遍歷
到第一個相同
的節點就是他們的最近公共祖先
這個方法在實際提交中,超內存了。。。但是思路應該是沒毛病的。
代碼實現一
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @param {TreeNode} p
* @param {TreeNode} q
* @return {TreeNode}
*/
// 注意是返回節點,不是返回節點的值!!!
var lowestCommonAncestor = function(root, p, q) {
p = p.val;
q = q.val;
let res = {
p: [],
q: []
}
find(root, p, q, [], res);
for (let i = res.q.length; i >= 0; i--) {
if (res.p.indexOf(res.q[i]) !== -1) {
return res.q[i]
}
}
};
function find(root, p, q, prev, res) {
prev = [...prev, root];
if (root.val === p) {
res.p = [...prev]
}
if (root.val === q) {
res.q = [...prev]
}
root.left && (find(root.left, p, q, prev, res));
root.right && (find(root.right, p, q, prev, res));
}