二叉树之最近公共祖先LCA

Posted 叶孤城_

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二叉树之最近公共祖先LCA相关的知识,希望对你有一定的参考价值。

问题描述

给你一个指向二叉树的根结点的指针,和两个指向二叉树中不同结点的指针 p 和 q,返回指向 p 和 q 的最近公共祖先的指针。(二叉树中的结点值唯一)

概念介绍

最近公共祖先:

According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes p and q as the lowest node in T that has both p and q as descendants (where we allow a node to be a descendant of itself).”

简单来说就是拥有 p 和 q 作为后代(允许一个结点作为自己的后代)的所有结点中层数最大的那个结点。

LCA主要是用来处理当两个点仅有唯一一条确定的最短路径时的路径。

算法

一、暴力解法

递归地看,对每一个传入的结点参数 root:

1 . 如果 root 的值等于 p 或 q 中的一个,那么 root 为最近公共祖先(因为是从上往下查找)
2 . 如果左子树同时拥有 p 和 q,或者右子树同时拥有 p 和 q,那么递归处理左或右子树
3 . 如果左右子树各拥有 p,q 中的一个,那么 root 为最近公共祖先

struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
class Solution {
public:
    int findNode(TreeNode* root, int target){
        if(!root) return 0;
        if(root->val==target) return 1;
        else return findNode(root->left, target) | findNode(root->right, target);
    }
    TreeNode* findLowest(TreeNode* root, int p, int q){
        if(!root) return nullptr;
        if(root->val==p || root->val==q){
            return root;
        }
        int lp,lq,rp,rq;
        lp=findNode(root->left, p);
        lq=findNode(root->left, q);
        rp=findNode(root->right, p);
        rq=findNode(root->right, q);
        if(lp && lq){
            return findLowest(root->left, p, q);
        }else if(rp && rq){
            return findLowest(root->right, p, q);
        }else{
            return root;
        }
    }
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        return findLowest(root, p->val, q->val);
    }
};

这个方法是第一时间顺着题目意思想出来的方法,可以明显看出来时间复杂度非常高,因为在每一个结点,都要搜索一遍其左右子树。

二、递归解法

struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if(!root) return nullptr;
        if(root->val==p->val || root->val==q->val){
            return root;
        }
        TreeNode* left=lowestCommonAncestor(root->left, p, q);
        TreeNode* right=lowestCommonAncestor(root->right, p, q);
        if(!left){
            return right;
        }else if(!right){
            return left;
        }else{
            return root;
        }
    }
};

三、区别

两种解法都是自顶向下查找,而其区别在于:

  1. 一中,findLowest() 函数每次递归必须确保其 root 参数中含有 p 和 q,实质上是找出了自顶向下对 LCA 的搜索路径
  2. 二中,lowestCommonAncestor() 函数则是 dfs 遍历整棵树,每一级在返回的时候也携带了搜索结点的结果信息,通过判断找出 LCA,其时间复杂度为 O(N)

以上是关于二叉树之最近公共祖先LCA的主要内容,如果未能解决你的问题,请参考以下文章

二叉树最近公共祖先

二叉树 最近公共祖先(LCA)

二叉树 最近公共祖先(LCA)

二叉树---最近公共父节点(LCA)

二叉树练习题3-最近公共祖先

LintCode 最近公共祖先