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

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. hash_map和map的区别

    hash_map和map的区别 分类: STL2008-10-15 21:24 5444人阅读 评论(0) 收藏 举报 class数据结构编译器存储平台tree 这里列几个常见问题,应该对你理解和使用 ...

  2. Unique Binary Search Trees 解答

    Question Given n, how many structurally unique BST's (binary search trees) that store values 1...n? ...

  3. Pros and Cons of T4 in Visual Studio 2008

    Oleg Sych - » Pros and Cons of T4 in Visual Studio 2008 Pros and Cons of T4 in Visual Studio 2008 Po ...

  4. ios常用的几个动画代码

      #import "MianViewController.h" #import <QuartzCore/QuartzCore.h> @interface MianVi ...

  5. 实现一次请求加载多个js或者css

    http://tengine.taobao.org/   相当牛x

  6. squid服务搭建

    Squid配置1. 什么是squidsquid可以做代理也可以做缓存squid缓存不仅可以节省宝贵的带宽资源,也可以大大降低服务器的I/O.  squid不仅可以做正向代理,又可以做反向代理. 正向代 ...

  7. oracle 数据库学习

    1.更改数据库用户名密码: alter user '用户名' identified by ’password'. 2.查看数据库有哪些用户:sqlplus system/password ;selec ...

  8. Core Bluetooth 概述 【官方文档翻译】

    Core Bluetooth 框架在Mac和iOS平台,为配备了低功耗蓝牙无线技术的设备提供了进行通信所需要的类.例如,您的应用程序可以发现,探索,和低功耗的外围设备进行交互,如心率监视器.数字温控器 ...

  9. 世界国家名与英文名【json】

    英文版 var geolocation= [   ["AO", "Angola"],   ["AF", "Afghanistan& ...

  10. css模板之 web模板一

    效果 <html><head><style type="text/css">div.container{width:100%;margin:0p ...