二叉树公共祖先问题

1. 问题描述1:

  有如下图的二叉树:

  ------------------1---------------------

  -------------/---------\-----------------

  --------2-----------------3-------------

  -----/------\------------/-----\---------

  ---4---------5--------6---------7------

  -/---\------/---\-----/---\------/---\---

  -8----9---10---11--12--13---14---15-

  两条到根节点的路径,例如:(4, 2, 1)和(11,5,2,1),从2处开始相交。

  现给定起始点x和y,求第一个相交点。

 

思路:

  1. 子节点与父节点的关系:children/2 = parent

  2. 递归:给定初始点,如果两者不同,则大的除以2(往上遍历路径),递归后直到第一个相交处即使所求解。

 

代码:

1 int first_cross(int x, int y)
2 {
3      if( x == y )  return x;
4      else if( x > y )  return first_cross(x/2, y);
5      else return first_cross(x, y/2);
6 }

 

2. 问题描述2:

  二叉树是一颗二叉查找树,即左边小于当前,右边大于当前。

 

思路:

  1. 利用查找树的性质以及最近公共祖先的特性(最近公共祖先一定将两个节点分隔在左右两边),所以可以从根节点开始往下递归

  2. 判断两节点是否在当前节点的左右两侧,如果不是继续递归,直到是则找到了要求的节点

 

代码:

 1 //n1->data <= n2->data
 2 BNode_t* firstCommonAncestor(BNode_t* cur, BNode_t* n1, BNode_t* n2)
 3 {
 4     if( cur == NULL ) 
 5     {
 6          return NULL;
 7     }
 8     if( n1->data <= cur->data && n2->data >= cur->data)
 9     {
10          return cur;   
11     }
12     if( n1->data <= cur->data )
13     {
14          return firstCommonAncestor(cur->left, n1, n2);
15     }
16     return firstCommonAncestor(cur->right, n1, n2);
17 }
18 
19 BNode_t* solution()
20 {
21     if( node1->data <= node2->data )
22         return firstCommonAncestor(root, node1, node2);
23     return firstCommonAncestor(root, node2, node1);
24 }

 

 

3. 问题描述3:

  如果节点内容是随机存放的,给定两个节点的指针,如何找到最近的公共祖先?

  第一种情况没有指向父节点的指针。

  第二种情况存在指向父节点的指针。

 

思路(第一种情况):

  1. 最近公共祖先意味着两个节点是该祖先的孩子节点,并且是第一个

  2. 用递归求解思路非常简便,从根开始判断是否包括这两个子节点,一直往下,直到找到为止

 

代码:

 1 BNode_t* firstCommonAncestor(BNode_t* cur, BNode_t* n1, BNode_t* n2)
 2 {
 3     if( cur == NULL )
 4     {
 5         return NULL;
 6     }
 7     if( n1 == NULL && n2 == NULL ) 
 8     {
 9         return NULL;
10     }
11     if( cur->left == n1 || cur->right == n1 )  
12     {
13         n1 = NULL;
14     }
15     if( cur->left == n2 || cur->right == n2 )
16     {
17         n2 = NULL;
18     }
19     BNode_t* left = firstCommonAncestor(cur->left, n1, n2);
20     if( left != NULL ) 
21     {
22         return left;
23     }
24     BNode_t* right = firstCommonAncestor(cur->right, n1, n2);
25     if( right != NULL ) 
26     {
27         return right;
28     }
29     return cur;
30 }

 

思路(第二种情况,有父节点):

      这种情况下又可以变形,比如节点内可以得到当前高度,这样就可以做类似本文最开始的递归操作。

  1. 先遍历一个节点的父节点,一直往上直到根节点,并用set存储路径上的节点O(h)空间和时间

  2. 再遍历另一个节点的父节点,直到遇到set中已有的节点,则该节点就是要找的公共节点

 

代码:略

 

转载请注明引用自:

  http://www.cnblogs.com/breakthings/p/4061762.html 

  

posted @ 2014-10-30 09:30  breakthings  阅读(499)  评论(0编辑  收藏  举报