开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第24天,点击查看活动详情
LeetCode 236. Lowest Common Ancestor of a Binary Tree
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
示例 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 。因为根据定义最近公共祖先节点可以为节点本身。
示例 3:
输入: root = [1,2], p = 1, q = 2
输出: 1
提示:
- 树中节点数目在范围
[2, 105]内。 -109 <= Node.val <= 109- 所有
Node.val互不相同。 p != qp和q均存在于给定的二叉树中。
算法
(DFS) O(n) 此题与 Lowest Common Ancestor of a Binary Search Tree 最大的不同就是这道题给定的二叉树不再是二叉查找树。 所以我们需要通过遍历整棵树,分别找到 p 和 q 结点到根结点的路径,然后枚举匹配路径上的点找到最近公共祖先。 遍历的算法采用的深度优先搜索,搜索时,需要一个数组记录路径;在每一层尝试两个方向的路径,如果某一个方向找到了目标结点或者当前点就是目标结点,则当且结点加入数组,并返回 true;否则返回 false。 最后根据两个数组的路径,找到最低的公共结点即可。 时间复杂度 由于需要遍历整棵树,每个结点仅遍历两次,故时间复杂度为 O(n)。
ac代码
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
bool dfs(TreeNode *cur, TreeNode *des, vector<TreeNode*> &path_node) {
if (cur == NULL)
return false;
if (cur == des) {
path_node.push_back(cur);
return true;
}
if (dfs(cur -> left, des, path_node) || dfs(cur -> right, des, path_node)) {
path_node.push_back(cur);
return true;
}
return false;
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
vector<TreeNode*> path_node_p, path_node_q;
dfs(root, p, path_node_p);
dfs(root, q, path_node_q);
reverse(path_node_p.begin(), path_node_p.end());
reverse(path_node_q.begin(), path_node_q.end());
int n = min(path_node_p.size(), path_node_q.size());
for (int i = n - 1; i >= 0; i--)
if (path_node_p[i] == path_node_q[i])
return path_node_p[i];
return NULL;
}
};