原题链接
之前做了二叉搜索树的最近公共祖先寻找,因为搜索树的有序性,很好做。但是这个题换成了一般二叉树,递归上略微复杂。
看了评论里面大神的杰作,实在太nb了嗷。本质上和我的想法是一样的,都是在看目标节点是否在根节点的左右子树中,注意返回值的写法,判断结构 A ? B : C 其中的 B 和C是可以嵌套使用该结构的,学到了。
给出代码:
struct TreeNode* lowestCommonAncestor(struct TreeNode* root, struct TreeNode* p, struct TreeNode* q){
/* 二叉树为空或者结点 p/q 为根结点 */
if (root == NULL || root == p || root == q) {
return root;
}
/* 在根结点的左右子树查找 */
struct TreeNode *left = lowestCommonAncestor(root->left, p, q);
struct TreeNode *right = lowestCommonAncestor(root->right, p, q);
/* 结点 p/q 不在左子树中,就在右子树中查找,如果能找到,就返回在右子树中找到的结点(反之亦然) */
/* 结点 p/q 分别存在左右两颗子树, 根结点为最近公共祖先 */
/* 结点 p/q 在左右子树都找不到,则它们没有最近公共祖先 */
return left == NULL ? right : right == NULL ? left : root;
}
以下是我的第一次想的思路:
- 每个节点判断一次,是否有目标节点在以这个节点为根节点的子树中,isThere()函数返回在与否的真值。
- 从根节点开始看。如果在,则看其左右子树的isThere()函数返回值。
- 如果公共子节点不是目标节点之间的一个,至少有一个子树的isThere()函数值为true,进入返回值为true的子树中,递归进入isThere()返回值为true的树,直到左右子树的isThere()返回值都是true。证明找到了这个节点,赋值给全局变量result。
- 如果公共子节点是目标节点之间的一个呢,再返回节点之前稍微判断一下,如果是就把当前根节点赋值给result。
- 返回result。
值得注意的是,这里result更新的时候,是函数按照出栈的顺序更新的,所以要把第4点说到的情况放在return前面。
但是毫不意外的超时了哈哈哈,因为递归的次数太多了,双重递归有点沙雕,但是感觉值得记录一下这种思路。
给出代码(这次换成了C语言):
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
struct TreeNode* result;
// 判断目标子节点是否在该以 root 为根的子树中,如果在,就返回true,不在返回false
bool isThere(struct TreeNode* root, struct TreeNode* p, struct TreeNode* q){
if(!root) return false;
if(root->val == p->val || root->val == q->val) return true;
return isThere(root->left,p,q) || isThere(root->right,p,q);
}
struct TreeNode* lowestCommonAncestor(struct TreeNode* root, struct TreeNode* p, struct TreeNode* q){
if(isThere(root, p, q)){ // 只有此节点中包含有目标节点才能进一步判断
if(isThere(root->left,p,q) && isThere(root->right, p, q)) result = root; // 如果左右子节点中均存在目标节点,证明这个是他们的公共祖先节点
else if(isThere(root->left, p, q)) lowestCommonAncestor(root->left, p, q); // 进入左右子节点中isThere函数返回值是true的分支判断
else if(isThere(root->right, p, q)) lowestCommonAncestor(root->right, p, q);
}
if(root->val == p->val || root->val == q->val) result = root; // 看根节点是否是目标节点两个之间的一个
return result;
}