二叉树中查找两个节点的最低公共祖先

这是一道企业面试中,经常会被问到的面试题目。

在网上看到一些此题的实现,其中有两种方法是比较适合编程的。本项目的源代码,请点击这里下载。

方法一:

  此方法是根据二叉树的DFS查找并标记祖先,根据递归出栈的原理,找到公共祖先。

  其主要代码如下:

#include <iostream>
#include <list>
#include "LinerLCA.h"

//DFS左右子树,查找pNode是否存在
/*@param pRoot 根节点
/*@param pNode 需要查找的节点
/*@param path pNode所存在的路径
*/
bool GetNodePath(BinaryTreeNode* pRoot, BinaryTreeNode* pNode, list<BinaryTreeNode*>& path)
{
    if(pRoot == pNode)
        return true;

    path.push_back(pRoot);

    bool found = false;

    if (pRoot->m_pLeft != NULL)
    {
        found = GetNodePath(pRoot->m_pLeft, pNode, path);
    }

    if (pRoot->m_pRight != NULL && !found)
    {
        found = GetNodePath(pRoot->m_pRight, pNode, path);
    }

    if(!found)
        path.pop_back();

    return found;
}
//遍历path1、path2,找到最后面的公共节点
BinaryTreeNode* GetLastCommonNode(list<BinaryTreeNode*>& path1, list<BinaryTreeNode*>& path2)
{
    list<BinaryTreeNode*>::const_iterator iterator1 = path1.begin();
    list<BinaryTreeNode*>::const_iterator iterator2 = path2.begin();

    BinaryTreeNode* pLast = NULL;

    while(iterator1 != path1.end() && iterator2 != path2.end() && *iterator1 == *iterator2)
    {
        pLast = *iterator1;
        iterator1++;
        iterator2++;
    }

    return pLast;
}
//函数入口
BinaryTreeNode* GetLastCommonParent(BinaryTreeNode* pRoot, BinaryTreeNode* pNode1, BinaryTreeNode* pNode2)
{
    if(pRoot == NULL || pNode1 == NULL || pNode2 == NULL)
        return NULL;

    list<BinaryTreeNode*> path1;
    GetNodePath(pRoot, pNode1, path1);

    list<BinaryTreeNode*> path2;
    GetNodePath(pRoot, pNode2, path2);

    return GetLastCommonNode(path1, path2);
}

方法二:

  此方法是在一本书里看到的,其主要思想是,先遍历二叉树,找到从根到两个节点的两条路径,然后再求解出两条路径的第一个公共交点,为最低共同祖先。

  主要代码如下:

#include "RecursionLCA.h"

/*递归计算根节点与node1、node2的关系
* @param root 要查找节点的根节点 
* @param node1 节点一
* @param node2 节点二
* @param restult 共同父节点结果的引用
* @param parent 根节点的父节点
*/  
bool LCA(BinaryTreeNode* root, BinaryTreeNode* node1, BinaryTreeNode* node2, BinaryTreeNode*& restult, BinaryTreeNode* parent)
{
     if (!root)
     {
        return false;
     }

     bool falg1 = LCA(root->m_pLeft, node1, node2, restult, root);
     bool falg2 = LCA(root->m_pRight, node1, node2, restult, root);
     //在节点的两个子树上
     if (falg1 && falg2)
     {
        //只有确定在两棵子树上时,根节点为共同父节点
        restult = root;
        return true;
     }
     //其中的一个节点是根节点
     if (root->m_nValue == node1->m_nValue || root->m_nValue == node2->m_nValue)
     {
         if (falg1 || falg2)
         {
             restult = parent;
         }
         return true;
     }
     return falg1 || falg2; 
}
//函数入口
BinaryTreeNode* RecurLCA(BinaryTreeNode* root, BinaryTreeNode* node1, BinaryTreeNode* node2)
{
    BinaryTreeNode* restult = NULL;
    LCA(root, node1, node2, restult, NULL);
    return restult;
}

测试数据如下:

《二叉树中查找两个节点的最低公共祖先》

测试结果:

《二叉树中查找两个节点的最低公共祖先》

小结:

  方法一:比较直观,在查找节点的同时,还做了标记,一气呵成,想到此方法要求分析能力较强。

  方法二:思想比较简单,逻辑清晰,但空间复杂度较多。

  在时间效率上,两者相差不多,方法一应为只有递归操作,省去了开辟额外空间的开销,效率略高。

  读者如有更好的方法,欢迎交流、指正。

    原文作者:二叉查找树
    原文地址: https://blog.csdn.net/fy2462/article/details/31760087
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞