寻找最近公共祖先,示例如下:

1

/           \

2           3

/    \        /    \

4    5      6    7

/    \             \

8    9           10

LCA(8,9)=4; LCA(5,8)=2; LCA(10,4)=1

思路一:

递归法

1.如果有一个结点是树的根结点,则必定不存在公共祖先;遍历二叉树每个结点,检查其左右子树是否包含指定的两个结点;

2.遍历二叉树每个结点,检查其左右子树是否包含指定的两个结点;3.如果步骤一满足条件,则重新检查以该结点的孩子为根结点的子树是否同时包含指定的两个结点;如果包含则重复步骤2,否则该结点便是指定两个结点的最近公共祖先。

假设LCA(root, id1, id2)用于判断以root为根的树是否含有id1和id2的后代结点。

LCA(root, id1, id2, &ans)

ans=root

while(1)

if(ans->leftchild!=NULL)

if(find(ans->leftchild, id1)&&find(ans->leftchild, id2))   //均找到id1和id2

ans=ans->leftchild

continue

if(ans->rightchild!=NULL)

if(find(ans->rightchild, id1)&&find(ans->rightchild, id2))

ans=ans->rightchild

continue

break

显然这样做将重复遍历多个结点,因此,使用动态规划,可以降低时间复杂度。

思路二:

动态规划法--保存以前遍历过的已知结果,组成上层子问题的结果,从而提升效率,但会增加空间复杂度。

1.对树进行层遍历(详见之前的帖子),并将结点存入数组中;

2.从数组尾部开始,检查是否存在目标结点,假设m[i,1]和m[i,2]表示第i个结点拥有id1或id2的后代,有k<i且结点k是i的双亲, m[k,1]=m[i,1]+(n(i)==id1), m[k,2]=m[i,2]+(n(i)==id2)

3.当m[k,1]==1且m[k,2]==1时找到公共祖先,否则数组遍历完成,表示找不到公共祖先。

为方便起见,这里修改一下树结点结构

struct tree_node;
struct tree_node{
struct tree_node *lc;
struct tree_node *rc;
int id;
int index;
};
typedef struct tree_node treenode;

具体代码如下

#include <stdio.h>
#include <stdlib.h>
#include <string.h> struct tree_node;
struct tree_node{
struct tree_node *lc;
struct tree_node *rc;
int id;
int index;
};
typedef struct tree_node treenode;
//*先序为DLR(D:根节点,L:左子树,R:右子树)
// a
// / \
// b c
// / \ / \
// d * * e
//*/
//先序序列为abdce,输入为abd***c*e**(*表示空格,代表空树),输入按满二叉树输入
//每一个节点都是一个子树的根节点
void pre_create_tree(treenode **T){ //递归法
int datatemp; fflush(stdin);
scanf("%d", &datatemp); if(datatemp==-1){
*T=NULL;
}
else{
if((*T=(treenode*)malloc(sizeof(treenode)))==NULL){
exit(0);
}
else{
(*T)->id=datatemp;
(*T)->lc = (*T)->rc = NULL;
pre_create_tree(&(*T)->lc);
pre_create_tree(&(*T)->rc);
}
}
} void pre_visit_tree(treenode *T, int *n){ //递归法
if(T!=NULL){
(*n)++;
printf("%d ", T->id);
pre_visit_tree(T->lc, n);
pre_visit_tree(T->rc, n);
}
else{
return;
}
} typedef struct info{
treenode *node;
int have_id1;
int have_id2;
}info; void level_visit_tree(treenode *T, int n, int id1, int id2){
info *myinfo, *tt, *temp;
treenode *ptemp, *nodetemp;// **temp;
int k=1, levelcnt=0, cnt, levelcnttemp, prelevelcnt=1;
int index=0;
//levelcnt:当前层元素个数,levelcnttemp:下一层元素个数 //初始化循环记录
myinfo = (info*)malloc(sizeof(info)*n); //记录用数组
myinfo->node = T;
if(T->lc!=NULL)
levelcnt++;
if(T->rc!=NULL)
levelcnt++;
temp = myinfo;
tt = temp+1;
printf("%d ", temp->node->id);
T->index = index++;
while(levelcnt){
//本层没有元素,可以结束循环了
for(cnt=0, levelcnttemp=0; cnt<levelcnt; ){ //tt:从数组myinfo中指向本层元素,遍历本层元素,有cnt计数,不用怕访问到其它层的元素
if(temp->node->lc!=NULL){ //打印本层元素的孩子,有则输出孩子值,没有就输出#
printf("%d ", temp->node->lc->id);
(tt+cnt)->node = temp->node->lc;
temp->node->lc->index = index++;
if((tt+cnt)->node->lc!=NULL)
levelcnttemp++;
if((tt+cnt)->node->rc!=NULL)
levelcnttemp++;
cnt++;
}
else
printf("# ");
if(temp->node->rc!=NULL){
printf("%d ", temp->node->rc->id);
(tt+cnt)->node = temp->node->rc;
temp->node->rc->index = index++;
if((tt+cnt)->node->lc!=NULL)
levelcnttemp++;
if((tt+cnt)->node->rc!=NULL)
levelcnttemp++;
cnt++;
}
else
printf("# ");
temp++;
}
//k=k+levelcnt; //k木有用
tt = tt+cnt;
levelcnt=levelcnttemp;
}
printf("\n"); for(k=n-1; k>=0; k--){
nodetemp = (myinfo+k)->node;
(myinfo+k)->have_id1 = 0;
(myinfo+k)->have_id2 = 0;
if(nodetemp->lc==NULL&&nodetemp->rc==NULL){
//这个结点是叶子结点,肯定不是他们两的祖先
(myinfo+k)->have_id1 = 0;
(myinfo+k)->have_id2 = 0;
}
else{
if(nodetemp->lc!=NULL){
if((myinfo+nodetemp->lc->index)->have_id1||nodetemp->lc->id==id1)
(myinfo+k)->have_id1 = 1;
if((myinfo+nodetemp->lc->index)->have_id2||nodetemp->lc->id==id2){
(myinfo+k)->have_id2 = 1;
}
}
if(nodetemp->rc!=NULL){
if((myinfo+nodetemp->rc->index)->have_id1||nodetemp->rc->id==id1)
(myinfo+k)->have_id1 = 1;
if((myinfo+nodetemp->rc->index)->have_id2||nodetemp->rc->id==id2){
(myinfo+k)->have_id2 = 1;
}
}
}
if((myinfo+k)->have_id1&&(myinfo+k)->have_id2){
printf("They have a common an ancestor:%d", (myinfo+k)->node->id);
break;
}
}
if(k<0)
printf("They have no common ancestors");
} int main(){
treenode *mytree;
int n=0;
int id1, id2; printf("输入需要查找公共祖先的id号:"); scanf("%d %d", &id1, &id2);
pre_create_tree(&mytree);
pre_visit_tree(mytree, &n); printf("\n");
level_visit_tree(mytree, n, id1, id2); printf("\n"); system("pause");
return 0;
}

测试用例:

1 2 3 -1 -1 4 10 -1 -1 11 -1 -1 5 6 -1 9 -1 -1 7 8 13 -1 -1 14 -1 -1 12 -1 -1

【Leetcode】查找二叉树中任意结点的最近公共祖先(LCA问题)的更多相关文章

  1. 二叉树中两节点的最近公共父节点(360的c++一面问题)

    面试官的问题:写一个函数  TreeNode* Find(TreeNode* root, TreeNode* p, TreeNode* q) ,返回二叉树中p和q的最近公共父节点. 本人反应:当时有点 ...

  2. 查找最近公共祖先(LCA)

    一.问题 求有根树的任意两个节点的最近公共祖先(一般来说都是指二叉树).最近公共祖先简称LCA(Lowest Common Ancestor).例如,如下图一棵普通的二叉树. 结点3和结点4的最近公共 ...

  3. 【Java】 剑指offer(68) 树中两个结点的最低公共祖先

      本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集   题目 输入两个树结点,求它们的最低公共祖先. 思路 该题首先要和面试 ...

  4. 剑指Offer - 九度1509 - 树中两个结点的最低公共祖先

    剑指Offer - 九度1509 - 树中两个结点的最低公共祖先2014-02-07 01:04 题目描述: 给定一棵树,同时给出树中的两个结点,求它们的最低公共祖先. 输入: 输入可能包含多个测试样 ...

  5. 树中两个结点的最低公共祖先--java

    题目:对于任意一个树,不仅仅限于二叉树,求树中两个结点的最低公共祖先结点. 解析:对于任意一棵树,显然并不局限于二叉树,也就是说树的非叶子结点可能存在多个子节点.所以,我们可以定义两个链表结构,存储这 ...

  6. 【剑指Offer面试编程题】题目1509:树中两个结点的最低公共祖先--九度OJ

    题目描述: 给定一棵树,同时给出树中的两个结点,求它们的最低公共祖先. 输入: 输入可能包含多个测试样例. 对于每个测试案例,输入的第一行为一个数n(0<n<1000),代表测试样例的个数 ...

  7. 【剑指Offer学习】【面试题50:树中两个结点的最低公共祖先】

    题目:求树中两个结点的最低公共祖先,此树不是二叉树,而且没有指向父节点的指针. 树的结点定义 private static class TreeNode { int val; List<Tree ...

  8. 【IT笔试面试题整理】寻找二叉树两节点的最近的公共祖先

    [试题描述] 求二叉树中任意两个节点的最近公共祖先也称为LCA问题(Lowest Common Ancestor). 二叉查找树 如果该二叉树是二叉查找树,那么求解LCA十分简单. 基本思想为:从树根 ...

  9. (剑指Offer)面试题50:树中两个结点的最低公共祖先

    题目: 求树中两个结点的最低公共祖先 思路: 考虑一下几种情况: 1.该树为二叉搜索树 二叉搜索树是排序树,位于左子树点的结点都比父结点小,而位于右子树的结点都比父结点大,只需要从树的根结点开始和两个 ...

随机推荐

  1. C# 将字节流转换为图片的实例方法

    usingSystem;  usingSystem.Collections.Generic;  usingSystem.Linq;  usingSystem.Text;  usingSystem.Dr ...

  2. C语言的本质(37)——makefile之隐含规则和模式规则

    Makefile有很多灵活的写法,可以写得更简洁,同时减少出错的可能.本节我们来看看这样一个例子还有哪些改进的余地. 一个目标依赖的所有条件不一定非得写在一条规则中,也可以拆开写,例如: main.o ...

  3. UESTC_邱老师选妹子 2015 UESTC Training for Dynamic Programming<Problem H>

    H - 邱老师选妹子 Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others) Submi ...

  4. 二十六、Jcreator使用初步

    摘自http://blog.csdn.net/liujun13579/article/details/7751464 二十六.Jcreator使用初步 Jcreator是一个小巧灵活的Java开发工具 ...

  5. 在web应用程序中使用MemcachedClient

    本文来自:http://www.cnblogs.com/yukaizhao/archive/2008/11/10/memcached_client_usage.html 一. 背景: 在大访问量的we ...

  6. myeclipse集成weblogicserver

    今天为了学一下JMS的东东, 不得不安装个weblogicserver, 下面是详细的安装步骤: 1. 首先去官网下载一个weblogic: 下载地址: http://download.oracle. ...

  7. hdu 4750 Count The Pairs (2013南京网络赛)

    n个点m条无向边的图,对于q个询问,每次查询点对间最小瓶颈路 >=f 的点对有多少. 最小瓶颈路显然在kruskal求得的MST上.而输入保证所有边权唯一,也就是说f[i][j]肯定唯一了. 拿 ...

  8. 【贪心】【HDU3177】 搬家问题

    </pre><pre name="code" class="cpp">#include <iostream> #includ ...

  9. LAMP的安装

    一,LAMP的安装流程:mysql.apache.php或者apache.mysql.php.php放到最后的原因是,php在编译安装的时候是依赖于前2者的. 二,Mysql的安装: 1.下载mysq ...

  10. drupal 7.23 上传中文命名文件bug

    $file->filename = trim(drupal_basename($_FILES['files']['name'][$source]), '.'); //在此行下 添加以下代码即可( ...