zoukankan      html  css  js  c++  java
  • 二叉树中两个结点最近的公共祖先汇总

    一、若二叉树为搜索二叉树

    原题链接:https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-search-tree/#/description

    Given a binary search tree (BST), find the lowest common ancestor (LCA) of two given nodes in the BST.

    According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes v and w as the lowest node in T that has both v and w as descendants (where we allow a node to be a descendant of itself).”

            _______6______
           /              
        ___2__          ___8__
       /              /      
       0      _4       7       9
             /  
             3   5
    

    For example, the lowest common ancestor (LCA) of nodes 2 and 8 is 6. Another example is LCA of nodes 2 and 4 is 2, since a node can be a descendant of itself according to the LCA definition.

    搜索二叉树:当所有结点互不相等时,满足:在任一结点r的左(右)子树中,所有结点(若存在)均小于(大于)r。更一般性的特点是:任何一棵二叉树是二叉搜索树,当且仅当其中序遍历序列单调非降。

    由二叉搜索树的特定可得:

    从根结点开始,和给定两结点开始比较,有四种情况:

    1、结点的值第一次位于两给定结点值得中间,则该结点为最近的公共祖先;

    2、结点的值大于两给定结点的值,则最近祖先一定在当前结点的左子树中;

    3、结点的值小于两给定结点的值,则最近祖先一定在当前结点的右子树中;

    4、结点的值等于两给定结点值得其中一个,则当前结点就是公共结点;

    情况三、四可以合并为一个。故理解以上三种情况,要好好的理解二叉搜索树的结构特点。

     1 /**
     2  * Definition for a binary tree node.
     3  * struct TreeNode {
     4  *     int val;
     5  *     TreeNode *left;
     6  *     TreeNode *right;
     7  *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     8  * };
     9  */
    10 class Solution {
    11 public:
    12     TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) 
    13     {
    14         int n1=min(p->val,q->val);
    15         int n2=max(p->val,q->val);
    16         while (true) {
    17             if (root->val >n2) 
    18                 root = root->left;
    19             else if (root->val < n1) 
    20                 root = root->right;
    21             else  break;
    22         }      
    23         return root;    
    24     }
    25 };

     参考了Grandyang的博客。

    二、二叉树为一般二叉树

    1)如果为三叉链表,即包含指向父节点的指针。

     结构体定义;

     1 /**
     2  * Definition for binary tree
     3  * struct TreeNode {
     4  *     int val;
     5  *     TreeNode *left;
     6  *     TreeNode *right;
     7  *     TreeNode *parent;
     8  *     TreeNode(int x) : val(x), left(NULL), right(NULL),parent(NULL) {}
     9  * };
    10  */

    方法一:将node1的父结点的值和node2所有的父结点的值相比较,若相等,则返回当前node1的父结点;若不相等,取node1父结点的父结点和node2的所有父结点比较,在包括node1和其父结点都存在(即,直到根结点)在内,找到相等的结点,返回即可。

     1 class Solution {
     2 public:
     3 {
     4     TreeNode *lowestCommonAncestor(TreeNode *root,TreeNode *node1,TreeNode *node2)
     5     {
     6         TreeNode *cur=NULL;
     7         while(node1 !=NULL)
     8         {
     9             node1=node1->parent;
    10             cur=node2;
    11             whlie(cur !=NULL)
    12             {
    13                 if(node1==cur->parent)
    14                     return node1;
    15                 cur=cur->parent;
    16             }
    17         }
    18     }
    19 }

    特别值得注意:如本文开始的那张图中,若给定结点的值为2和4,则该方法中,认为根结点6为最近的公共祖先。注意和二叉树为搜索二叉树的区别,要是想一样,则在判断时,要增加对node1、node2两结点中是否有一个结点为LCA的情况。

    算法的复杂度是O(n^2),n为二叉树的深度。

    方法二:我们注意到,两结点从根结点到它们最近的公共祖先的深度相同。所以我们可以先移动node1或node2,使两者到根结点的距离相同,然后两结点同步移动,直到遇到第一个值相等的情况。转换成了链表相交的情况。

     1 TreeNode *lowestCommonAncestor(TreeNode *root,TreeNode *node1,TreeNode *node2)
     2 {
     3     if(root==NULL||node1==NULL||node2==NULL)
     4         return NULL;
     5     int len1=getDepth(node1);
     6     int len2=getDepth(node2);
     7 
     8     while(len1 !=len2)
     9     {
    10         if(len1>len2)
           {
    11 node1=node1->parent;
             len1--;
           }
    12 if(len1<len2)
           {
    13 node2=node2->parent;
             len2--;
           }
    14 } 15 16 while(node1 !=NULL&&node2 !=NULL &&node1->val !=node2->val) 17 { 18 node1=node1->parent; 19 node2=node2->parent; 20 } 21 return (node1 !=NULL&&node2 !=NULL)?node1:NULL; 22 } 23 24 /*某一个结点到根节点的距离*/ 25 int getDepth(TreeNode *node) 26 { 27 int len=0; 28 while(node !=NULL) 29 { 30 node=node->parent; 31 len++; 32 } 33 return len; 34 }

    时间复杂度为O(n)。

    方法三:可以将node1到根结点建立一张hash表(使用unordered_set),然后从node2到根结点边遍历,查找Hash表,直到第一次在hash表在查找到结点值存在的。

    参考了czyseu的博客,dream的博客

    3、一般的二叉树

    原题连接:https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree/tabs/description/

    Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree.

    According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes v and w as the lowest node in T that has both v and w as descendants (where we allow a node to be a descendant of itself).”

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

    For example, the lowest common ancestor (LCA) of nodes 5 and 1 is 3. Another example is LCA of nodes 5 and 4 is 5, since a node can be a descendant of itself according to the LCA definition.

    思路:若一个结点的左子树有目标结点中的一个,而右子树没有,则该结点肯定不是最小公共祖先;若一个结点右子树有两个目标结点中的一个,而左子树中没有,那么这个结点肯定也不是最小公共祖先;只有一个结点,当其左子树有,右子树也有,这时才是最小的公共祖先。

    深度优先搜索算法,代码如下:

     1 /**
     2  * Definition for a binary tree node.
     3  * struct TreeNode {
     4  *     int val;
     5  *     TreeNode *left;
     6  *     TreeNode *right;
     7  *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     8  * };
     9  */
    10 class Solution {
    11 public:
    12     TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) 
    13     {
    14         if(root==NULL||root==p||root==q)
    15             return root;
    16 
    17         TreeNode *left=lowestCommonAncestor(root->left,p,q);
    18         TreeNode *right=lowestCommonAncestor(root->right,p,q);
    19 
    20         if(left !=NULL&&right !=NULL)   return root;
    21 
    22         return left==NULL?right:left;    
    23     }
    24 };

     注:若p和q不是树中结点时,应该返回NULL,这时上面的代码不正确,对于这种情况请参见 Cracking the Coding Interview 5th Edition 的第233-234页(参见Grandyang的博客)。这里默认的是。

    参考了 Ethan Li 的技术专栏

    另外重要连接:

    http://www.cdn.geeksforgeeks.org/lowest-common-ancestor-binary-tree-set-1/

    个人水平有限,各位看官若是发现不对的地方,欢迎留言指出。谢谢~~

  • 相关阅读:
    智能交通监控
    YOLOV4知识点分析(二)
    YOLOV4知识点分析(一)
    错误日志写入到本地磁盘(lock 队列)
    $.each(data, function (index, value) { })的用法;json和list<>的互相转换
    ArraySegment 的使用 【转载】
    Ajax往后台传参数,无参数,一个参数,多个参数,一个对象等
    在gridview里查找模板里的button控件
    数据可视化之PowerQuery篇(十六)使用Power BI进行流失客户分析
    数据可视化之PowerQuery篇(十五)如何使用Power BI计算新客户数量?
  • 原文地址:https://www.cnblogs.com/love-yh/p/7242774.html
Copyright © 2011-2022 走看看