热门标签 | HotTags
当前位置:  开发笔记 > 人工智能 > 正文

68剑指offer88.最近公共祖先

给定一棵二叉树,找到两个节点的最近公共父节点(LCA)。最近公共祖先是两个节点的公共的祖先节点且具有最大深度。样例对于下面这棵二叉树4\37
 

给定一棵二叉树,找到两个节点的最近公共父节点(LCA)。

最近公共祖先是两个节点的公共的祖先节点且具有最大深度。

样例

对于下面这棵二叉树

  4
 / \
3   7
   / \
  5   6

LCA(3, 5) = 4

LCA(5, 6) = 7

LCA(6, 7) = 7

一、树为二叉查找树

二叉查找树的创建: 

//创建二叉搜索树
struct TreeNode
{
	int val;
	TreeNode* left;
	TreeNode* right;
	TreeNode(val)
	{
		this->val = val;
		this->left = this->right = NULL;
	}
};
//插入
void Treeinsert(TreeNode* &root, int val)
{   
	TreeNode*node = new TreeNode(val);
	if (root == NULL)
	{
		root->val = val;
		return;
	}
	TreeNode*pre = NULL;
	TreeNode*p = root;
	while (p)
	{
		pre = p;
		if (val val)
			p = p->left;
		else
			p = p->right;
	}
	if (valval)
	 pre->left=node;
	else 
	 pre->right=node;
	}
}

思路:

1、二叉搜索树是排过序的,位于左子树的结点都比父节点小,位于右子树的结点都比父节点大。

2、从树的根结点开始和输入的两个结点比较。

如果当前结点比两个结点的值都大,则最低的共同父节点一定在当前结点的左子树中

如果当前结点比两个结点的值都小,则最低共同父节点一定在当前结点的右子树中。

这样,在树中从上到下找到的第一个在两个输入结点值之间的结点即最低公共祖先。

代码:

自己写的代码,非递归

TreeNode* LCA(TreeNode* root, TreeNode*A, TreeNode*B)
{
	if (root == NULL)
		return NULL;
	while (root != NULL)
	{
		if (root->val val&&root->val val)
			root = root->right;
		if (root->val > A->val&&root->val > B->val)
			root = root->left;
		if (root->val >= A->val&&root->val <= B->val || root->val <= A->val&&root->val >= B->val)
			return root;
	}
	return NULL;
}

参考他人的代码:

// 最近公共祖先  
	TreeNode *LCA(TreeNode *root, TreeNode *u, TreeNode *v) {
		// 空树  
		if (root == NULL || u == NULL || v == NULL) {
			return NULL;
		} 
		 // u val val && root->val val) ||
			(v->val val && root->val val)) {
			return root;
		} 
		 // u val val && v->val val) {
			// u是v祖先 or v是u的祖先  
			if (root->left == u || root->left == v) {
				return root;
			}/ 
			return LCA(root->left, u, v);
		} 
		 // u > root and v > root  right sub tree  
		if (u->val > root->val && v->val > root->val) {
			// u是v祖先 or v是u的祖先  
			if (root->right == u || root->right == v) {
				return root;
			} 
			return LCA(root->right, u, v);
		}  
		return  NULL;
	}

二叉树,但每个结点都有指向父节点的指针next.

思路:分别从给定的两个节点出发上溯到根节点,形成两条相交的链表,问题转化为求这两个相交链表的第一个交点。

即传统方法:求出linkedList A的长度lengthA, linkedList B的长度LengthB。然后让长的那个链表走过abs(lengthA-lengthB)步之后,齐头并进,就能解决了。

代码:

int  getlength(TreeNode*node)
{
	int length = 0;
	TreeNode*temp = node;
	while (temp)
	{
		length++;
		temp = temp->next;
	}
	return length;
}
TreeNode* LCA(TreeNode*node1, TreeNode* node2)
	{
	int length1 = getlength(node1);
	int length2 = getlength(node2);
	TreeNode* pt1 = NULL;
	TreeNode* pt2 = NULL;
	int k = 0;
	if (length1 >= length2)
	{
		TreeNode*temp = node1;
		while (k++ <(length1 - length2))
		{
			temp = temp->next;
		}
		pt1 = temp;
		pt2 = node2;
	}
	else
		if (length1 next;
			}
			pt1 = temp;
			pt2 = node1;
		}
	while(pt1&&pt2&&pt1 != pt2)
	{
	pt1 = pt1->next;
	pt2 = pt2->next;
    }
	return pt1;

普通二叉树:无父节点指针

思路:


记录从根找到node1和node2的路径,然后再把它们的路径用类似的情况一来做分析,比如还是node1=3,node2=8这个case.我们肯定可以从根节点开始找到3这个节点,同时记录下路径3,4,6,10,类似的我们也可以找到8,6,10。我们把这样的信息存储到两个vector里面,把长的vector开始的多余节点3扔掉,从相同剩余长度开始比较,4!=8, 6==6,我们找到了我们的答案。

代码:

 //找到root到结点n的路径path
   bool nodepath(TreeNode*root, TreeNode* value, vector&path)
	{
		if (root == NULL)
			return false;
		if (root==value)
		{
		    path.push_back(root);
			return true;
		}
		if (nodepath(root->left, value, path))
			{
			    path.push_back(root);
                return true;}
		 else  if (nodepath(root->right, value, path))
		    {
			    path.push_back(root);
			 	return true;}
	     else
		    	return false;
	}
	//LCA函数寻找最近公共祖先
		TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* A,TreeNode* B)
		{
			vectorpath1;
			vectorpath2;
			bool find = false;
			find|= nodepath(root, A, path1);
			find&= nodepath(root, B, path2);
			TreeNode*p = NULL;
		if(find)
		{
		int minsize = path1.size() > path2.size() ? path2.size() : path1.size();
		int it1 = path1.size() - minsize;
		int it2 = path2.size() - minsize;
		for (; it1  
 



 




推荐阅读
  • 显卡驱动对游戏的影响及其提升效果的研究
    本文研究了显卡驱动对游戏体验的提升效果,通过比较新旧驱动加持下的RTX 2080Ti显卡在游戏体验上的差异。测试平台选择了i9-9900K处理器和索泰RTX 2080Ti玩家力量至尊显卡,以保证数据的准确性。研究结果表明,显卡驱动的更新确实能够带来近乎50%的性能提升,对于提升游戏体验具有重要意义。 ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • 词袋模型的通俗介绍
    词,袋, ... [详细]
  • 本文介绍了使用哈夫曼树实现文件压缩和解压的方法。首先对数据结构课程设计中的代码进行了分析,包括使用时间调用、常量定义和统计文件中各个字符时相关的结构体。然后讨论了哈夫曼树的实现原理和算法。最后介绍了文件压缩和解压的具体步骤,包括字符统计、构建哈夫曼树、生成编码表、编码和解码过程。通过实例演示了文件压缩和解压的效果。本文的内容对于理解哈夫曼树的实现原理和应用具有一定的参考价值。 ... [详细]
  • 在2022年,随着信息化时代的发展,手机市场上出现了越来越多的机型选择。如何挑选一部适合自己的手机成为了许多人的困扰。本文提供了一些配置及性价比较高的手机推荐,并总结了选择手机时需要考虑的因素,如性能、屏幕素质、拍照水平、充电续航、颜值质感等。不同人的需求不同,因此在预算范围内找到适合自己的手机才是最重要的。通过本文的指南和技巧,希望能够帮助读者节省选购手机的时间。 ... [详细]
  • 从高级程序员到CTO的4次能力跃迁!如何选择适合的技术负责人?
    本文讲解了从高级程序员到CTO的4次能力跃迁,以及如何选择适合的技术负责人。在初创期、发展期、成熟期的每个阶段,创业公司需要不同级别的技术负责人来实现复杂功能、解决技术难题、提高交付效率和质量。高级程序员的职责是实现复杂功能、编写核心代码、处理线上bug、解决技术难题。而技术经理则需要提高交付效率和质量。 ... [详细]
  • Learning to Paint with Model-based Deep Reinforcement Learning
    本文介绍了一种基于模型的深度强化学习方法,通过结合神经渲染器,教机器像人类画家一样进行绘画。该方法能够生成笔画的坐标点、半径、透明度、颜色值等,以生成类似于给定目标图像的绘画。文章还讨论了该方法面临的挑战,包括绘制纹理丰富的图像等。通过对比实验的结果,作者证明了基于模型的深度强化学习方法相对于基于模型的DDPG和模型无关的DDPG方法的优势。该研究对于深度强化学习在绘画领域的应用具有重要意义。 ... [详细]
  • 背景应用安全领域,各类攻击长久以来都危害着互联网上的应用,在web应用安全风险中,各类注入、跨站等攻击仍然占据着较前的位置。WAF(Web应用防火墙)正是为防御和阻断这类攻击而存在 ... [详细]
  • macOS Big Sur全新设计大版本更新,10+个值得关注的新功能
    本文介绍了Apple发布的新一代操作系统macOS Big Sur,该系统采用全新的界面设计,包括图标、应用界面、程序坞和菜单栏等方面的变化。新系统还增加了通知中心、桌面小组件、强化的Safari浏览器以及隐私保护等多项功能。文章指出,macOS Big Sur的设计与iPadOS越来越接近,结合了去年iPadOS对鼠标的完善等功能。 ... [详细]
  • 2016 linux发行版排行_灵越7590 安装 linux (manjarognome)
    RT之前做了一次灵越7590黑苹果炒作业的文章,希望能够分享给更多不想折腾的人。kawauso:教你如何给灵越7590黑苹果抄作业​zhuanlan.z ... [详细]
  • 北京景点排行榜 北京最好玩的旅游景点
    2019北京最好玩的旅游景点有哪些?下文为大家整理了2019北京景点排行榜,希望可以帮到您哦!  2019北京景点排行榜:  1、故宫  帝都必打卡的地点之一。  北京故宫是中国明 ... [详细]
  • 本文介绍了互联网思维中的三个段子,涵盖了餐饮行业、淘品牌和创业企业的案例。通过这些案例,探讨了互联网思维的九大分类和十九条法则。其中包括雕爷牛腩餐厅的成功经验,三只松鼠淘品牌的包装策略以及一家创业企业的销售额增长情况。这些案例展示了互联网思维在不同领域的应用和成功之道。 ... [详细]
  • 本文整理了315道Python基础题目及答案,帮助读者检验学习成果。文章介绍了学习Python的途径、Python与其他编程语言的对比、解释型和编译型编程语言的简述、Python解释器的种类和特点、位和字节的关系、以及至少5个PEP8规范。对于想要检验自己学习成果的读者,这些题目将是一个不错的选择。请注意,答案在视频中,本文不提供答案。 ... [详细]
  • 深入解析Linux下的I/O多路转接epoll技术
    本文深入解析了Linux下的I/O多路转接epoll技术,介绍了select和poll函数的问题,以及epoll函数的设计和优点。同时讲解了epoll函数的使用方法,包括epoll_create和epoll_ctl两个系统调用。 ... [详细]
  • SEEBURGER SAP GTS解决方案:数字化助力企业实现海关流程数字化
    SEEBURGER作为SAP的合作伙伴,在2019 SAP GTS信息交流会上分享了SEEBURGER SAP GTS解决方案的应用案例,介绍了如何利用数字化助力企业实现海关流程数字化。SEEBURGER的集成技术和解决方案支持SAP GTS产品和服务的推广及应用,通过数据通讯和报文格式转换满足与海关当局的电子数据交换需求。该解决方案能够帮助企业管理全球贸易,保证贸易规范,优化跨境供应链,提升企业合规性。 ... [详细]
author-avatar
孜雪颖2000
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有