二叉树中两个结点最近的公共祖先汇总
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表在查找到结点值存在的。
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/
个人水平优先,各位看官若是发现不对的地方,欢迎留言指出。谢谢~~
以上是关于二叉树中两个结点最近的公共祖先汇总的主要内容,如果未能解决你的问题,请参考以下文章