题目
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 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, 10^5]
内。 -10^9 <= Node.val <= 10^9
- 所有
Node.val
互不相同 。 p != q
-
解题方法
递归
递归判断当前节点是否最近公共祖先,最近公共祖先的成立条件如下:
(left&&right) || ( (cur->val==p->val)||(cur->val==q->val) && (left||right) )
其中:left
代表当前节点的左子树中存在任意目标元素,right
代表当前节点的右子树中存在任意目标元素。
递归终止条件为:
当cur==NULL
时返回f否则返回false
否则递归判断左右子树及当前节点后,返回left || right || cur->val==p->val ||cur->val==q->val
时间复杂度O(n)
,空间复杂度O(n)
c++代码:/** * 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 { private: TreeNode* result; public: bool dfs(TreeNode* root, TreeNode* p, TreeNode* q) { if(!root) return false; bool left = dfs(root->left, p, q); bool right = dfs(root->right, p, q); if((left&&right) || ((root->val==p->val || root->val==q->val) && (left||right))) result = root; return left || right || root->val==p->val || root->val==q->val; } TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) { dfs(root, p, q); return result; } };
递归2
直接递归返回左右子树中包含包含
p
或q
的节点(包括只包含p
、q
和两者都包含),再判断当前节点是否为最近公共祖先。
时间复杂度O(n)
,空间复杂度O(n)
C++代码:/** * 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: TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) { if(root==p || root==q || !root) return root; TreeNode* left = lowestCommonAncestor(root->left, p, q); TreeNode* right = lowestCommonAncestor(root->right, p, q); if(left && right) return root; else if(left) return left; return right; } };
哈希表
通过哈希表重构二叉树,方便查找当前节点的父节点。从
p
、q
分别向上遍历,第一个公共父节点即最近公共祖先。
时间复杂度O(n)
,空间复杂度O(n)
C++代码:/** * 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 { private: unordered_map<int, TreeNode*> tree; unordered_map<int, bool> vis; public: void dfs(TreeNode* root) { if(!root) return; if(root->left) { tree[root->left->val] = root; dfs(root->left); } if(root->right) { tree[root->right->val] = root; dfs(root->right); } } TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) { if(!root) return NULL; tree[root->val] = NULL; dfs(root); while(p) { vis[p->val] = true; p = tree[p->val]; } while(q) { if(vis[q->val]) return q; q = tree[q->val]; } return root; } };