美文网首页算法C算法&面试题程序员
二叉树-最低公共父节点(2)

二叉树-最低公共父节点(2)

作者: AwesomeAshe | 来源:发表于2016-03-10 14:36 被阅读114次

在上一篇文章中我们用的是暴力的遍历判断的方法,然而在树有关的题目中,保存路径也是一个很常用的思路,比如求两个节点的最短路径,求路径长度。
并且为了改善算法的复杂度,我们可以尝试减少遍历的次数,上一种方法中,我们遍历了两次,这次,我们试着保存遍历的路径,然后求两个路径的公共节点。
首先我们有一个getNodePath 函数,该函数会将从头结点到给定节点的路径保存,然后有一个lastCommonNode函数求路径的公共节点。

首先我们看这个函数,这个函数的设计的思路值得我学习。

  • 返回量:该函数返回的是布尔型变量,表示该节点是否在包含指定node的路径上。
    为什么要如此选取呢?为什么不直接返回一个list的指针?我们要通过这个函数得到list,为什么要作为一个参数传进去而不是作为返回量?
    我们看函数的结构,和大多数遍历树的函数一样,该函数也是递归的。我们的参数之一是树的根节点,意思是从这个节点往下遍历。
    整个函数有四个分支,分别是
    1,该根节点就是要找的节点,返回true
    2,否则在左子树寻找
    3,否则在右子树寻找
    4,要找的节点不在当前根节点的下面。此时删除掉路径中存储的当前节点。
    由此,我们遍历整个树之后留下 的节点就是路径
bool getNodePath(node* ptree, node* pnode,std::list<node*>& path)
{
    if (ptree == pnode)
        return true;

    path.push_back(ptree);
    //在递归中,我们只关心这一轮要处理的节点,因此只需要把ptree放进去而不需要在left和right中加入push_back

    bool found = false;
    if (ptree->lnode)
    {
        found = getNodePath(ptree->lnode, pnode, path);
    }
    if (!found&&ptree->rnode)
    {
        found = getNodePath(ptree->rnode, pnode, path);
    }
    if (!found)
        path.pop_back();
    return found;
}

由于我对递归函数还是不太熟悉,在设想的时候总是会在左右子树分支的函数里面加上path.push_back(tree->left) ,总是觉得处理当前节点就要有显式的语句,但是实际上后面的递归调用会把这个节点加进去的,如果还写,那就是重复了。
在递归的函数中我们应该这样想,我们只处理当前节点,当前节点的子节点留给递归就行了。

下面是完整的函数:

//way2,get the path , the get the last common node of two paths
#include <list>

bool getNodePath(node* ptree, node* pnode,std::list<node*>& path)
{
    if (ptree == pnode)
        return true;

    path.push_back(ptree);
    //在递归中,我们只关心这一轮要处理的节点,因此只需要把ptree放进去而不需要在left和right中加入push_back

    bool found = false;
    if (ptree->lnode)
    {
        found = getNodePath(ptree->lnode, pnode, path);
    }
    if (!found&&ptree->rnode)
    {
        found = getNodePath(ptree->rnode, pnode, path);
    }
    if (!found)
        path.pop_back();
    return found;
}
node* lastCommonNode_l(std::list<node*>& path1, std::list<node*>& path2)
{
    node* path = NULL;
    std::list<node*>::const_iterator ptr1=path1.begin();
    std::list<node*>::const_iterator ptr2 = path2.begin();
    while (ptr1 != path1.end() && ptr2 != path2.end())
    {
        if (*ptr1 == *ptr2)
            path = *ptr1;//why *ptr
            //we do not return here since we need the last common node 
        ptr1++;
        ptr2++;
    }
    return path;//attention
    
}
node* LastCommonNode(node* tree, node* node1, node* node2)
{
    if (tree == NULL || !node1 || node2)
        return;

    std::list<node*> path1;
    std::list<node*> path2;
    getNodePath(tree, node1, path1);
    getNodePath(tree, node1, path2);

    return lastCommonNode_l(path1, path2);
}

文章参考何海涛大神文章

相关文章

  • Longest Common Ancetor

    二叉树公共父节点专题 BST,二叉搜索树的公共父节点 https://leetcode.com/problems/...

  • 二叉树-最低公共父节点(2)

    在上一篇文章中我们用的是暴力的遍历判断的方法,然而在树有关的题目中,保存路径也是一个很常用的思路,比如求两个节点的...

  • 二叉树-最近的公共祖先

    已知二叉树,求二叉树中给定的两个节点的最近公共祖先。 最近公共祖先: 两节点v与w的最近公共祖先u,满足在树上最低...

  • 【剑指Offer 50】树中两个结点的最低公共祖先

    题目:求树中两个结点的最低公共祖先,此树不是二叉树,并且没有指向父节点的指针。 代码如下: 来源:http://b...

  • 二叉树-最低公共父节点(1)

    给定一个二叉树(不是二叉查找树),和两个节点,求这两个节点的最低公共父节点。我们先介绍一个暴力的思路:遍历并判断。...

  • 最近公共祖先系列

    最近公共祖先I 描述: 给定一棵二叉树,找到两个节点的最近公共父节点 (LCA)。最近公共祖先是两个节点的公共的祖...

  • lintcode 最近公共祖先

    给定一棵二叉树,找到两个节点的最近公共父节点(LCA)。最近公共祖先是两个节点的公共的祖先节点且具有最大深度。样例...

  • 小米-基础算法-最近公共祖先

    给一棵二叉树和二叉树中的两个节点,找到这两个节点的最近公共祖先LCA。两个节点的最近公共祖先,是指两个节点的所有父...

  • 算法—— 最近公共祖先 III

    给一棵二叉树和二叉树中的两个节点,找到这两个节点的最近公共祖先LCA。两个节点的最近公共祖先,是指两个节点的所有父...

  • 剑指offer 76- 树中两个结点的最低公共祖先

    给出一个二叉树,输入两个树节点,求它们的最低公共祖先。 一个树节点的祖先节点包括它本身。 注意: 输入的二叉树不为...

网友评论

    本文标题:二叉树-最低公共父节点(2)

    本文链接:https://www.haomeiwen.com/subject/jsytlttx.html