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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二叉树中两个结点最近的公共祖先汇总相关的知识,希望对你有一定的参考价值。

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

原题链接: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;
12         if(len1<len2)
13             node2=node2->parent;
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/

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

以上是关于二叉树中两个结点最近的公共祖先汇总的主要内容,如果未能解决你的问题,请参考以下文章

python代码实现二叉树中最低的公共祖先

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

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

二叉树中任意两个节点的最近公共祖先

二叉树 最近公共祖先(LCA)

二叉树 最近公共祖先(LCA)