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

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

原题链接: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/

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

时间: 2024-10-12 18:55:29

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

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

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

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

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

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

#include <iostream> using namespace std; template<class T> struct BinaryTreeNode {                 BinaryTreeNode< T>(const T& data)                                 :_data( data)                                 ,_left( NULL)         

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

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

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

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

求一棵普通树的两个结点的最低公共祖先

一棵普通树,树中的结点没有指向父节点的指针,求一棵普通树的两个结点的最低公共祖先. 代码如下,我太懒没有加注释,大家自己看吧! 1 #include <iostream> 2 #include <list> 3 #include <vector> 4 using namespace std; 5 6 struct TreeNode //节点 7 { 8 char m_nValue; 9 vector<TreeNode*> m_vChildren; 10 };

二叉树中两个结点的距离

问题 对于普通的二叉树,如何找到两个给定节点之间的距离?距离是指连接两个节点所需要的最小边的条数. 例如下面的二叉树: 这个问题很全面的考察了二叉树的相关的知识,建议大家先尝试自己解决 分析: 假设给定的节点为node1,node2,可以分为下面的两种情况: 1)node1是node2的祖先节点或孩子结点,可以理解为两个节点在一条线上.例如:Dist(2,4),Dist(6,1) 2)node1和node2没有直接或间接的父子关系.例如,Dist(4,3),他们需要一个共同的祖先结点1连接起来

二叉树中两个节点的最近公共父节点

这是京东周六的笔试题目   当时不在状态,现在想来肯定是笔试就被刷掉了,权当做个纪念吧.  这个问题可以分为三种情况来考虑: 情况一:root未知,但是每个节点都有parent指针此时可以分别从两个节点开始,沿着parent指针走向根节点,得到两个链表,然后求两个链表的第一个公共节点,这个方法很简单,不需要详细解释的. 情况二:节点只有左.右指针,没有parent指针,root已知思路:有两种情况,一是要找的这两个节点(a, b),在要遍历的节点(root)的两侧,那么这个节点就是这两个节点的最

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

必须通过遍历查找一个节点的祖先集合,然后比较两个节点的祖先集合就可以找到最低的那个.这里采用后序遍历,并传入一个栈记录该节点的祖先节点.在每次访问一个节点时,先把这个节点压入栈,然后判断该节点是不是要查找的那个节点,如果是返回.接着查找它的左子树和右子树,当要查找的节点在它的左右子树中则返回.然后判断该节点与栈顶节点是否相同,是则弹出栈顶元素.这是因为相同就代表了在访问它的左右子树时没有添加新的节点,也就是说要查找的那个节点不在它的左右子树中,则该节点也就是不是要查找的节点的祖先. #inclu