236. 二叉树的最近公共祖先 - 力扣(LeetCode)
题目
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 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 != q
p
和q
均存在于给定的二叉树中。
思路
- 首先定义一个全局结果节点,用于保存最早出现的满足条件的祖先节点。
- 然后利用后序遍历的深度优先搜索,保证最先找到的满足条件的节点一定是深度最大的(即最低的/最靠近两个目标节点的/最深的),因为都是先统计左右子树在算根,所以对任意节点,若左右子树有了,并赋给全局结果节点,那么该节点将不会更新,仅仅完成dfs的任务。
代码实现
/*** 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* ans;int find_descendant(TreeNode* now, TreeNode* p, TreeNode* q) {int cnt = 0;if(now==p || now==q) {cnt++;}if(now->left) cnt += find_descendant(now->left, p, q);if(now->right) cnt += find_descendant(now->right, p, q);if(!ans && cnt==2) ans = now;return cnt;}TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {ans = nullptr;int cnt = 0;if(root==p || root==q) cnt++;if(root->left) cnt += find_descendant(root->left, p, q);if(root->right) cnt += find_descendant(root->right, p, q);if(!ans && cnt==2) ans = root;return ans;}
};
复杂度分析
- 时间复杂度:深度优先搜索只对每个节点进行一次遍历,时间复杂度为O(n)。
- 空间复杂度:空间复杂度取决于栈空间的大小,等价于树的深度,最坏空间复杂度为O(n)(变成一条线的斜树)。