zoukankan      html  css  js  c++  java
  • 48. 二叉树两结点的最低共同父结点(3种变种情况)[Get lowest common ancestor of binary tree]

    题目

    输入二叉树中的两个结点,输出这两个结点在数中最低的共同父结点。

    二叉树的结点定义如下:

     C++ Code 
    1
    2
    3
    4
    5
    6
     
    struct BinaryTreeNode
    {
        
    int value;
        BinaryTreeNode *left;
        BinaryTreeNode *right;
    };

    【分析】

    求数中两个结点的最低共同结点是面试中经常出现的一个问题。这个问题有几个变种。

    【变种1】

    第一个变种是二叉树是一种特殊的二叉树:查找二叉树。也就是树是排序过的,位于左子树上的结点都比父结点小,而位于右子树的结点都比父结点大。我们只需要从根结点开始和两个结点进行比较。如果当前结点的值比两个结点都大,则最低的共同父结点一定在当前结点的左子树中。如果当前结点的值比两个结点都小,则最低的共同父结点一定在当前结点的右子树中。

    具体代码如下:

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
     
    // 48_GetLowestCommonAncessor.cpp : Defines the entry point for the console application.
    //

    #include "stdafx.h"

    struct BinaryTreeNode
    {
        
    int value;
        BinaryTreeNode *left;
        BinaryTreeNode *right;
    };

    BinaryTreeNode* create_tree_r(
    int a[],int left,int right)
    {
        
    // base case for leaf-node
        if (left>right)
            
    return NULL;
        
    int mid = (left+right)/2;
        BinaryTreeNode *root = 
    new BinaryTreeNode();
        root->value = a[mid];
        
    if(left<=mid)
            root->left = create_tree_r(a,left,mid-
    1);
        
    if (right>=mid)
            root->right = create_tree_r(a,mid+
    1,right);
        
    return root;
    }

    BinaryTreeNode* CreateTree(
    int a[],int length)
    {
        
    if(NULL==a||length<=0)
            
    return NULL;
        
    return create_tree_r(a,0,length-1);
    }

    // whether tree root has node x?
    bool HasNode(BinaryTreeNode *root,int x)
    {
        
    if(NULL==root)
            
    return false;
        
    if (root->value==x)
        {
            
    return true;
        }
        
    else if (root->value<x)
        {
            
    return HasNode(root->right,x);
        }
        
    else 
        {
            
    return HasNode(root->left,x);
        }
    }

    // check whether root tree has node
    bool HasNode(BinaryTreeNode *root,BinaryTreeNode *node)
    {
        
    if (root==node)
            
    return true;
        
    bool bLeft = false;
        
    bool bRight = false;
        
    // check in left sub-tree
        if (root->left!=NULL)
            bLeft = HasNode(root->left,node);

        
    // check in left right-tree
        if (root->right!=NULL)
            bRight = HasNode(root->right,node);
        
    return bLeft||bRight;
    }

    // get lowest common ancestor recursively
    BinaryTreeNode* GetLowestCommonAncestor_Recursively(BinaryTreeNode *root,int x,int y)
    {
        
    if(NULL==root)
            
    return NULL;
        
    if(root->value>=x && root->value<=y)
        {
    // x in left and y in right sub-tree
            return root;
        }
        
    else if (root->value<x)
        {
    // x y in right sub-tree
            return GetLowestCommonAncestor_Recursively(root->right,x,y);
        }
        
    else
        
    //else if(root->value>y)
        {// x y in left sub-tree 
            return GetLowestCommonAncestor_Recursively(root->left,x,y);
        }
    }

    // get lowest common ancestor iteratively
    BinaryTreeNode* GetLowestCommonAncestor_Iteratively(BinaryTreeNode *root,int x, int y)
    {
        
    if(NULL==root)
            
    return NULL;
        BinaryTreeNode *cur = root;
        
    while(cur!=NULL)
        {
            
    if(cur->value>=x && cur->value<=y)
            {
    // x in left and y in right sub-tree
                return cur;
            }
            
    else if (cur->value<x)
            {
    // x y in right sub-tree
                cur = cur->right;
            }
            
    else 
            {
    // x y in left sub-tree 
                cur = cur->left;
            }
        }
        
    return cur;
    }

    // get lca for x and y 
    BinaryTreeNode* GetLCA_Solution(BinaryTreeNode *root,int x,int y)
    {
        
    // check whether root has x and y
        if (HasNode(root,x)&&HasNode(root,y))
            
    return GetLowestCommonAncestor_Iteratively(root,x,y);
        
    else 
            
    return NULL;
    }

    void test_base(BinaryTreeNode *root,int x,int y)
    {
        BinaryTreeNode *result = GetLCA_Solution(root,x,y);
        
    if (NULL==result)
        {
            printf(
    "%s ","can not find lca.");
        }
        
    else
        {
            printf(
    "%d,%d--->%d ",x,y,result->value);
        }
    }

    void test_case()
    {
        
    /*
                     5
                    /
                   /  
                  /    
                 2     7
                /    / 
               /  |   |  
              1   3  6  8
                            
                    4         9
        */

        
    int a[] = {1,2,3,4,5,6,7,8,9};
        
    int length = sizeof(a)/sizeof(int);
        BinaryTreeNode *root = CreateTree(a,length);
        test_base(root,
    4,9); // 5
        test_base(root,1,4); // 2
        test_base(root,6,9); // 7
        // special case
        test_base(root,-1,4); // cannot find lca
        test_base(root,6,100);// cannot find lca
    }

    int _tmain(int argc, _TCHAR* argv[])
    {
        test_case();
        
    return 0;
    }
    /*
    4,9--->5
    1,4--->2
    6,9--->7
    can not find lca.
    can not find lca.
    */

    【变种2】

    第二个变种是树为多叉树,每个结点都有一个指针指向它的父结点。于是我们可以从任何一个结点出发,得到一个到达树根结点的单向链表。因此这个问题转换为两个单向链表的第一个公共结点,之前35.两链表的第一个公共结点已经讨论过。

    【变种3】

    第三个变种是树为多叉树,每个父节点有若干个子节点,但是子节点没有指向父节点指针。我们只能从根节点遍历树,从而得到从根节点到某一节点的路径,然后求这两个路径的最后一个公共节点

    本题中的二叉树是第三个变种的一个特例,即每个父节点只有左右子节点。

    具体代码如下:

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
     
    #include <vector>
    #include <iostream>
    using namespace std;

    // treenode
    struct TreeNode
    {
        
    int value;
        vector<TreeNode*> vChildren;
    };

    // get tree node path from root to node
    bool GetNodePath(TreeNode *root,TreeNode *node,vector<TreeNode*> &path)
    {
        
    if(root==node)
            
    return true;
        path.push_back(root);
        
    // find node in root's children
        bool found = false;
        vector<TreeNode*>::iterator iter = root->vChildren.begin();
        
    while(!found&&iter<root->vChildren.end())
        {
            found = GetNodePath(*iter,node,path);
            iter++;
        }
        
    // if not found in root's children,then remove it from path
        if (!found)
            path.pop_back();
        
    return found;
    }

    // get last common node of path1 and path2
    TreeNode* GetLastCommonNode(const vector<TreeNode*> &path1,const vector<TreeNode*> &path2)
    {
    // A-B-D, A-B-E
        vector<TreeNode*>::const_iterator iter1= path1.begin();
        vector<TreeNode*>::const_iterator iter2= path2.begin();

        TreeNode *lastNode = 
    NULL;
        
    while(iter1!=path1.end()&&iter2!=path2.end())
        {
            
    if (*iter1==*iter2)
                lastNode = *iter1;
            iter1++;
            iter2++;
        }
        
    return lastNode;
    }

    // get lowest common ancestor 
    TreeNode* GetLCA(TreeNode* root,TreeNode *node1,TreeNode *node2)
    {
    // O(n)+O(n)+O(n) = O(n)
        if(NULL==root||NULL==node1||node2==NULL)
            
    return NULL;
        vector<TreeNode*> path1;
        GetNodePath(root,node1,path1);
        vector<TreeNode*> path2;
        GetNodePath(root,node2,path2);
        
    return GetLastCommonNode(path1,path2);
    }

    【参考】

    http://zhedahht.blog.163.com/blog/static/25411174201081263815813/

    http://blog.csdn.net/dahai_881222/article/details/7801356

    http://www.cnblogs.com/venow/archive/2012/08/31/2664969.html

    【本文链接】

    http://www.cnblogs.com/hellogiser/p/get-lowest-common-ancestor-of-binary-tree.html

    个人学习笔记,欢迎拍砖!---by hellogiser

    Author: hellogiser
    Warning: 本文版权归作者和博客园共有,欢迎转载,但请保留此段声明,且在文章页面明显位置给出原文连接。Thanks!
    Me: 如果觉得本文对你有帮助的话,那么【推荐】给大家吧,希望今后能够为大家带来更好的技术文章!敬请【关注】
  • 相关阅读:
    vue中使用第三方UI库的移动端rem适配方案
    前端规范--eslint standard
    从上往下打印二叉树
    栈的压入,弹出序列
    随机森林
    LR
    顺时针打印矩阵
    包含min函数的栈
    树的子结构
    合并两个有序链表
  • 原文地址:https://www.cnblogs.com/hellogiser/p/get-lowest-common-ancestor-of-binary-tree.html
Copyright © 2011-2022 走看看