寻找二叉树中的最低公共祖先结点----LCA(Lowest Common Ancestor )问题(递归)

转自 剑指Offer之 - 树中两个结点的最低公共祖先

题目:

求树中两个节点的最低公共祖先。

思路一:

——如果是二叉树,而且是二叉搜索树,那么是可以找到公共节点的。

二叉搜索树都是排序过的,位于左子树的节点都比父节点小,而位于右子树上面的节点都比父节点大。

如果当前节点的值比两个结点 的值都大,那么最低的共同的父节点一定是在当前节点的左子树中,于是下一步遍历当前节点的左子节点。

如果当前节点的值比两个结点的值都小,那么最低的共同的父节点一定是在当前节点的右子树中,于是下一步遍历当前节点的右子节点。

这样从上到下,找到的第一个在两个输入结点的值之间的节点,就是最低的公共祖先。

题目和代码参考:http://blog.csdn.net/u012243115/article/details/46875537

思路二:

如果这棵树不是二叉搜索树,甚至连二叉树都不是,而只是普通的树。

——如果有指向父节点的指针,那么这个题目转换成了求,两个双向链表的第一个公共结点的问题。

思路三:

这棵树是普通的树,而且这个树中的结点没有指向父节点的指针。

——遍历这个树,看以这个节点为根的子树是否包含这两个节点,如果包含,判断这个节点的子节点是否包含,

——知道子节点都不包含而这个当前的节点包含,那么这个节点就是最低的公共祖先。

ps.这里存在大量的重复遍历,效率不高。

思路三:

这棵树是普通的树,而且这个树中的结点没有指向父节点的指针。

——用两个链表分别保存从根节点到输入的两个结点的路径,然后把问题转换成两个链表的最后公共节点。

代码:

(这里假设树是普通二叉树,用思路三求解)

#include <iostream>
#include <list>
using namespace std;  

struct TreeNode
{
    int m_nValue;
    TreeNode *m_pLeft;
    TreeNode *m_pRight;
    TreeNode(){}
    TreeNode(int value):m_nValue(value),m_pLeft(NULL),m_pRight(NULL){}
};  

//得到pNode结点的路径,放入path中 也可以用栈来实现 ,递归的本质就是一个压栈和出栈的过程
// 本题可为剑指offer原题P252,其解法可参考面试题25(P143)
bool GetNodePath(TreeNode * pRoot , TreeNode *pNode , list<TreeNode *> &path)
{
    if(pRoot == NULL)
        return false;
    path.push_back(pRoot);  

    bool found = false;
    if(pRoot == pNode)
    {
        found = true;
        return found;
    }
    // 注意理解这里的递归问题
    found = GetNodePath(pRoot->m_pLeft , pNode , path) || GetNodePath(pRoot->m_pRight , pNode , path);
    if(!found)
        path.pop_back();
    return found;
}  

//找到两条路径的最后一个公共结点即是公共祖先
TreeNode * GetLastCommonNode(const list<TreeNode *> &path1 , const list<TreeNode*> &path2)
{
    list<TreeNode *>::const_iterator iterator1 = path1.begin();
    list<TreeNode *>::const_iterator iterator2 = path2.begin();
    TreeNode *pLast = NULL;
    while(iterator1 != path1.end() && iterator2 != path2.end())
    {
        if(*iterator1 == *iterator2)
            pLast = *iterator1;
        iterator1++;
        iterator2++;
    }
    return pLast;
}  

TreeNode * GetLastCommonNodeParent(TreeNode *pRoot , TreeNode *pNode1 , TreeNode *pNode2)
{
    if(pRoot == NULL || pNode1 == NULL || pNode2 == NULL)
        return NULL;
    list<TreeNode *> path1;
    GetNodePath(pRoot , pNode1 , path1);
    list<TreeNode *> path2;
    GetNodePath(pRoot , pNode2 , path2);
    return GetLastCommonNode(path1 , path2);
}  

TreeNode * findLCA(TreeNode *pRoot , TreeNode *pNode1 , TreeNode *pNode2)
{
    if(pRoot == NULL)
        return NULL;
    if(pRoot == pNode1 || pRoot == pNode2)
        return pRoot;
    TreeNode *left_lca = findLCA(pRoot->m_pLeft , pNode1 , pNode2);
    TreeNode *right_lca = findLCA(pRoot->m_pRight , pNode1 , pNode2);
    if(left_lca && right_lca )
        return pRoot;
    return (left_lca != NULL) ? left_lca : right_lca;
}  

int main()
{
    TreeNode *p1 = new TreeNode(1);
    TreeNode *p2 = new TreeNode(2);
    TreeNode *p3 = new TreeNode(3);
    TreeNode *p4 = new TreeNode(4);
    TreeNode *p5 = new TreeNode(5);
    TreeNode *p6 = new TreeNode(6);
    TreeNode *p7 = new TreeNode(7);
    TreeNode *p8 = new TreeNode(8);
    TreeNode *p9 = new TreeNode(9);
    TreeNode *p10 = new TreeNode(10);
    p1->m_pLeft = p2;
    p1->m_pRight = p3;
    p2->m_pLeft = p4;
    p2->m_pRight = p5;
    p3->m_pLeft = p6;
    p3->m_pRight = p7;
    p4->m_pLeft = p8;
    p4->m_pRight = p9;
    p5->m_pLeft = p10;
    TreeNode *p;
    p = GetLastCommonNodeParent(p1 , p8 , p7);//p8和p7的最近公共祖先
    if(p)
        cout<<"最近的公共祖先是p"<<p->m_nValue<<endl;
    else
        cout<<"不存在公共祖先"<<endl;
    TreeNode *q;
    q = findLCA(p1 , p8 , p7);//p8和p7的最近公共祖先
    if(q)
        cout<<"最近的公共祖先是p"<<q->m_nValue<<endl;
    else
        cout<<"不存在公共祖先"<<endl;
}  

findLCA参考:http://www.acmerblog.com/lca-lowest-common-ancestor-5574.html

时间: 2025-01-02 03:44:30

寻找二叉树中的最低公共祖先结点----LCA(Lowest Common Ancestor )问题(递归)的相关文章

求解二叉查找树中的最低公共祖先结点

一,问题描述 请构造一棵二叉查找树,并给定两个结点,请找出这两个结点的最低公共祖先结点. 这里假设二叉查找树中的结点的权值存储是整型数字(见代码中的BinaryNode内部类),最低公共祖先结点如下:结点5 和 结点12 的最低公共祖先结点是结点10 二,实现思路 假设给定的两个结点的权值分别为 node1 和 node2 如果根的权值处于 node1 和 node2 之间,则根就是它们的最低公共祖先结点 如果根的权值比 node1 和 node2 都大,则它们的最低公共祖先结点在根的左子树中

二叉树中寻找共同节点的最低公共祖先节点

问题:在一棵二叉树中,给定两个节点,求这两个节点的最低的公共祖先节点,如下图中的,节点 6 和 节点 9 的最低公共祖先节点是节点 5. 最容易联想到的是,这个问题似乎与公共子串的问题有关系,如果我们能求出两个节点到根节点的路径,再使用匹配算法得到公共的路径,取这个路径上最后一个节点,即是所求的最低公共祖先节点. 哈夫曼编码启迪了我,我打算使用 0 表示向左走,1 表示向右走.如,101 表示自根节点,走到右孩子 A,再走到 A 的左孩子 B,再走到 B 的右孩子 C .于是,根节点到节点 C

二叉树求两节点最低公共祖先,求随意两节点距离

-------1.求最低公共祖先LCA( Lowest Common Ancestor ) 什么是最低公共祖先?例如以下图.2与3的LCA是1:1与4的LCA是1:4与5的LCA是2. 那么给定两个节点n1和n2,如今要找出它们的LCA,怎样找?首先分析一下,n1和n2有几种情况?第一种.n1和n2分别在一个节点的左右子树中,比方4和5,LCA就是2,5和6,LCA就是1.2和3,LCA就是1:另外一种.n1和n2都在左子树或右子树,比方2和4,LCA就是2,1和4.LCA就是1. 一共这两种情

二叉树中找两个结点的最近的公共祖先结点

#pragma once #include <iostream> using namespace std; /****************  * 二叉树中 找两个结点的最近的公共祖先结点 ******************/ struct Node {     Node* left;     Node* right;     int value;     Node(int v)         :value(v)         ,left(NULL)         ,right(NU

求解二叉树中两个结点的最低公共父结点

一,问题描述 构建一棵二叉树(不一定是二叉查找树),求出该二叉树中某两个结点的最低公共父结点.借用一张图如下: 结点8 和 结点5 的最低公共父结点为 结点2 二,二叉树的构建 与 求二叉树中第K层结点的个数 文章中的第二点:二叉树构建相同 三,求解最低公共父结点的算法实现 有两种思路,一种是通过中序遍历和后序遍历.由于中序遍历是先左子树中的结点,再访问根,再访问右子树中结点,因此这两个结点的公共父结点一定处于这两个结点之间. 如:中序遍历:8, 4, 9, 2, 5, 1, 6, 3, 7  

树中两个结点的最低公共祖先

情况1: 树为二叉排序树. 思路:从根结点开始和输入的两个结点进行比较,如果当前结点的值比两个结点的值都大,那么最低的祖先肯定在左子树中,于是下一步遍历当前结点的左子结点.如果当前结点的值比两个结点的值都小,那么最低的祖先肯定在右子树种,于是下一步遍历当前结点的右子结点.如果当前结点正好是输入的两个结点之一,说明这两个结点有一个是另一个的祖先,这时输出当前结点的父节点即可. /* 二叉树的公共祖先系列 1.二叉树为二叉排序树 by Rowandjj 2014/8/20 */ #include<i

求二叉树的最低公共祖先

这个题目来讲,应该是在二叉树里面较为容易的题目了.那么如何下手呢?其实对于这样一棵二叉树来讲. 我们如何求它们的最低公共父节点呢? 假如是要你求5.6的公共父节点,那么是3.啰 为什么是3? 因为3的左子树是5,而右子树是6啰. 那么7.8的最低公共祖先呢? 1啊,因为1的左子树中有7.而1的右子树中有8啊. 那么思路来了.我们只要证明某一节点的左子树和右子树分别包含这两个节点就行了. 于是思路来了. 源代码: 注意:在本题中为了方便 ,我们传入的两个节点的值,而不是两个节的地址,呵呵,为了方便

编程算法 - 二叉树的最低公共祖先 代码(C)

二叉树的最低公共祖先 代码(C) 本文地址: http://blog.csdn.net/caroline_wendy 二叉树的最低公共祖先(lowest common ancestor), 首先先序遍历找到两个结点的路径, 然后依据链表路径找到最低的公共祖先. 代码: /* * main.cpp * * Created on: 2014.6.12 * Author: Spike */ /*eclipse cdt, gcc 4.8.1*/ #include <iostream> #include

求解二叉树中两个节点的最近公共祖先(LCA)

/************************************************************************/ /* 非递归的方法 下面是一个简单的复杂度为 O(n) 的算法,解决LCA问题 1) 找到从根到n1的路径,并存储在一个向量或数组中. 2)找到从根到n2的路径,并存储在一个向量或数组中. 3) 遍历这两条路径,直到遇到一个不同的节点,则前面的那个即为最低公共祖先. */ /*************************************