C++二叉树和二叉搜索树的公共祖先查找(后序遍历)

C++二叉树和二叉搜索树的公共祖先查找(后序遍历)_第1张图片
当我们用递归去做这个题时不要被题目误导,应该要明确一点
这个函数的功能有三个:给定两个节点 p 和 q
如果 p 和 q 都存在,则返回它们的公共祖先;
如果只存在一个,则返回存在的一个;
如果 p 和 q 都不存在,则返回NULL
本题说给定的两个节点都存在,那自然还是能用上面的函数来解决
具体思路:
(1) 如果当前结点 root 等于 NULL,则直接返回 NULL
(2) 如果 root 等于 p 或者 q ,那这棵树一定返回 p 或者 q
(3) 然后递归左右子树,因为是递归,使用函数后可认为左右子树已经算出结果,用 left 和right 表示
(4) 此时若left为空,那最终结果只要看 right;若 right 为空,那最终结果只要看 left
(5) 如果 left 和 right 都非空,因为只给了 p和 q 两个结点,都非空,说明一边一个,因此 root是他们的最近公共祖先
(6) 如果 left 和 right 都为空,则返回空(其实已经包含在前面的情况中了)

问题就在于查找两个节点分别在那个分支?
直接依次遍历左分支右分支,分情况返回节点,

当left和right都不为空的时候说明他们分别在某一个root的左右分支中,那就公共祖先是root,
如果出现p和q有一个是另一个的祖先,那必然是查到一个不为空,另外一个为空,直接返回不为空的那个就行。
C++二叉树和二叉搜索树的公共祖先查找(后序遍历)_第2张图片
C++二叉树和二叉搜索树的公共祖先查找(后序遍历)_第3张图片
C++二叉树和二叉搜索树的公共祖先查找(后序遍历)_第4张图片

class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if (!root || root == p || root == q)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 right;
        else return left;
    }

};

题目若改成二叉搜索树,那么显然会变得更简单一点:

如果当前节点的值大于 p 和 q 的值,说明 p 和 q 应该在当前节点的左子树,因此将当前节点移动到它的左子节点;

如果当前节点的值小于 p 和 q 的值,说明 p 和 q 应该在当前节点的右子树,因此将当前节点移动到它的右子节点;

如果当前节点的值不满足上述两条要求,那么说明当前节点就是「分岔点」。此时,p 和 q 要么在当前节点的不同的子树中,要么其中一个就是当前节点。

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        while(true){
            if(root.val>q.val&&root.val>p.val){
                root=root.left;
            }
            else if(root.val<q.val&&root.val<p.val)root=root.right;
            else break;
        }
        return root;
    }
}

你可能感兴趣的:(数据结构,C++,二叉树,c++,最近公共祖先,后序遍历,二叉搜索树)