剑指68:二叉搜索树的最近公共祖先,k个子节点

方法一:逐个比较节点

/**
 * 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* res;
    bool flag=0;  //root是否为其中一个节点
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        findCommomRoot(root,p,q);
        return res;
    }

    int findCommomRoot(TreeNode* root, TreeNode* p, TreeNode* q){
        if( root==nullptr)
            return 0;
        int l=findCommomRoot(root->left,p,q);
        int r=findCommomRoot(root->right,p,q);
        if(root==p || root==q){ 
            if(l || r)     //一个节点是另一个节点的子节点
                res=root;
            return 1;      //另一个节点不是子节点,那么返回1
        }
        if(l && r)   // 分别在左右子树时
            res=root; 
        return l || r;
    }
};

方法二:利用二叉搜索树性质,利用大小关系,最近公共节点一定是大于一个,小于一个。可以分别用迭代,递归的方法写。以下为迭代

class Solution {
public:
    TreeNode* res;
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        while(root!=nullptr){
            if(root->val<p->val && root->val<q->val )  //值都比root大,说明都在右子树里
                root=root->right;
            else if(root->val>p->val && root->val>q->val )  //值都比root小,说明都在左子树里
                root=root->left;
            else
                break;
        }
        return root;

        //只有最近根节点才会满足一大一小,或者是等于某一个节点
    }
};

方法三:巧妙

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root == null) return null; // 如果树为空,直接返回null
        if(root == p || root == q) return root; // 如果 p和q中有等于 root的,那么它们的最近公共祖先即为root(一个节点也可以是它自己的祖先)
        TreeNode left = lowestCommonAncestor(root.left, p, q); // 递归遍历左子树,只要在左子树中找到了p或q,则先找到谁就返回谁
        TreeNode right = lowestCommonAncestor(root.right, p, q); // 递归遍历右子树,只要在右子树中找到了p或q,则先找到谁就返回谁
        if(left == null) return right; // 如果在左子树中 p和 q都找不到,则 p和 q一定都在右子树中,右子树中先遍历到的那个就是最近公共祖先(一个节点也可以是它自己的祖先)
        else if(right == null) return left; // 否则,如果 left不为空,在左子树中有找到节点(p或q),这时候要再判断一下右子树中的情况,如果在右子树中,p和q都找不到,则 p和q一定都在左子树中,左子树中先遍历到的那个就是最近公共祖先(一个节点也可以是它自己的祖先)
        else return root; //否则,当 left和 right均不为空时,说明 p、q节点分别在 root异侧, 最近公共祖先即为 root
    }
}

方法四:k个子节点的公共祖先

利用k来计数,遇到一个子节点的值就-1

class Solution {
    private TreeNode res;
    private int k;

    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        k = 2;
        dfs(root, p, q);
        return res;
    }

    private void dfs(TreeNode note, TreeNode p, TreeNode q) {
        if (note == null || k == 0) return;
        int kOld = k;
        if (note.val == p.val || note.val == q.val) k--;
        dfs(note.left, p, q);
        dfs(note.right, p, q);
        if (kOld == 2 && k == 0 && res == null)
            res = note;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值