JZ86 在二叉树中找到两个节点的最近公共祖先

1. 问题描述

在这里插入图片描述

2. 样例说明

在这里插入图片描述

3. 解法一:递归

算法思想

分析可知,对于节点 o1, o2 的最近公共祖先,只存在三种情况:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码

/**
 * struct TreeNode {
 *	int val;
 *	struct TreeNode *left;
 *	struct TreeNode *right;
 * };
 */

class Solution {
public:
    TreeNode* dfs(TreeNode* root, int o1, int o2) {
        if(root == nullptr) return nullptr; //超过叶节点,返回空
        if(root->val == o1 || root->val == o2) return root; //节点为其中一个
        TreeNode* t1 = dfs(root->left, o1, o2);
        TreeNode* t2 = dfs(root->right, o1, o2);
        if(t1 == nullptr) return t2; //t1找不到o1,o2
        if(t2 == nullptr) return t1; //t2找不到o1,o2
        return root; //此时两个节点分别位于左右两侧
    }
    int lowestCommonAncestor(TreeNode* root, int o1, int o2) {
        return dfs(root, o1, o2)->val;
    }
};

时间空间复杂度分析

时间复杂度:O(n),n为树的节点数,最多访问每个节点一次。
空间复杂度:O(n),空间复杂度取决于递归的栈深。最差情况下,数退化为链表,树高为n,故需要O(n)空间

4. 解法二:非递归

算法思想

对root进行两次深度搜索,分别找到到达 o1 和 o2 的路径,两条路径的最后一个公共节点即为最近公共祖先
在这里插入图片描述
在这里插入图片描述

代码

class Solution {
public:
    bool find = false; //标记是否找到了

    void dfs(vector<int>& load, TreeNode* root, int o) {
        if(find || root == nullptr) return; //已经找到或者到达空节点
        load.push_back(root->val); //加入数组
        if(root->val == o) {
            find = true;
            return;
        }
        dfs(load, root->left, o);
        dfs(load, root->right, o);
        if(find) { //防止将节点去除
            return;
        }
        load.pop_back(); //不在这条路径,去除节点
    }

    int lowestCommonAncestor(TreeNode* root, int o1, int o2) {
        vector<int> load1, load2;
        dfs(load1, root, o1); //找到 root到o1路径
        find = false; //重置标记
        dfs(load2, root, o2); //找到 root到o2路径
        int leng = min(load1.size(), load2.size());
        //寻找最后一个相等节点
        for(int i = 1; i < leng; ++i) {
            if(load1[i] != load2[i]) {
                return load1[i - 1]; 
            }
        }
        return load1[leng - 1];
    }
};

时间空间复杂度分析

时间复杂度:O(n),n为树的节点数,因为需要进行两次深度搜索,每次最多搜索一个节点一次
空间复杂度:O(n), 需要两个数组以及深度搜索的栈空间

5. 若二叉树为二叉搜索树

则递归解法会简单一些

/**
 * struct TreeNode {
 *	int val;
 *	struct TreeNode *left;
 *	struct TreeNode *right;
 *	TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 * };
 */
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param root TreeNode类 
     * @param p int整型 
     * @param q int整型 
     * @return int整型
     */
    TreeNode * CommonAncestor(TreeNode* root, int p, int q){
       if(!root)  return nullptr;
        if(root->val==p||root->val==q) return root;
        if(p<root->val&&q<root->val)  return CommonAncestor( root->left, p, q);
        else if(p>root->val&&q>root->val)  return CommonAncestor( root->right, p, q);
        else return root;
    }
    int lowestCommonAncestor(TreeNode* root, int p, int q) {
        // write code here
        return CommonAncestor(root, p, q)->val;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

焦妮敲代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值