二叉树两结点的最低公共祖先结点(一)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ssjhust123/article/details/7935537

题目

二叉树结点的定义如下:

struct node {
    int data;
    struct node* left;
    struct node* right;
};

给定二叉树中的两个结点,输出这两个结点的最低公共祖先结点(LCA)。注意,该二叉树不一定是二叉搜索树。

比如给定的二叉树如下所示,则可以知道结点1和5的最低公共祖先结点为5,结点4和5的最低公共祖先结点为5。

        _______3______
       /              \
    ___5__          ___1__
   /      \        /      \
   6      _2       0       8
         /  \
         7   4

 

解法

1)自顶向下的方法

我们可以从根结点出发,判断当前结点的左右子树是否包含这两个结点。如果左子树包含两个结点,则它们的最低公共祖先结点也一定在左子树中。如果右子树包含两个结点,则它们的最低公共祖先结点也一定在右子树中。如果一个结点在左子树,而另一个结点在右子树中,则当前结点就是它们的最低公共祖先结点。根据该思路写出代码如下,注意这里已经假定p和q是二叉树中的结点。

/*查找二叉树中两个结点最低公共祖先结点*/
struct node* LCA(struct node *root, struct node *p, struct node *q) 
{
    if (hasNode(root->left, p) && hasNode(root->left, q)) //p和q都在左子树中        
        return LCA(root->left, p, q);
    if (hasNode(root->right, p) && hasNode(root->right, q)) //p和q都在右子树中
        return LCA(root->right, p, q);
    return root; //p和q一个在左子树,一个在右子树中,直接返回root
}

/*判断root为根的树是否包含结点p*/
bool hasNode(struct node* root, struct node* p)
{
    if (!root) return false;
    if (root == p)
        return true;
    return hasNode(root->left, p) ||  hasNode(root->right, p);
}

由于我们对每个结点都调用了hasNode函数,而该函数类似于遍历二叉树,复杂度为O(N),所以总的时间复杂度为O(N^2),我们期望找到一个更好的方法。

 

2)自底向上的方法

由于自顶向下的方法需要重复遍历结点,使用自底向上的方法可以避免这种情况。

自底向上遍历结点,一旦遇到结点等于p或者q,则将其向上传递给它的父结点。父结点会判断它的左右子树是否都包含其中一个结点,如果是,则父结点一定是这两个节点p和q的LCA,传递父结点到root。如果不是,我们向上传递其中的包含结点p或者q的子结点,或者NULL(如果子结点不包含任何一个)。该方法时间复杂度为O(N)。

typedef struct node Node;
Node *LCA(Node *root, Node *p, Node *q) {
  if (!root) return NULL;
  if (root == p || root == q) return root;
  Node *L = LCA(root->left, p, q);
  Node *R = LCA(root->right, p, q);
  if (L && R) return root;  // 如果p和q位于不同的子树  
  return L ? L : R;  //p和q在相同的子树,或者p和q不在子树中
}

3)公共路径法

还有一个方法就是依次得到从根结点到结点p和q的路径,找出它们路径中的最后一个公共结点即是它们的LCA。该算法在何海涛先生的博客中有详细描述,这里就不赘述,详见http://zhedahht.blog.163.com/blog/static/25411174201081263815813/,该方法复杂度也为O(N),不过需要额外的空间存储路径,当然第2种方法中递归也是需要栈空间的,不过整体来看第2种方法简洁但是不是很好理解,而公共路径法则更加易懂。



 


 



 

没有更多推荐了,返回首页