面试题50_树中两个节点的最低公共祖先

面试题50_树中两个节点的最低公共祖先

1、关于问题的转化流程:

树——二叉树(排序二叉树)——二叉树(普通二叉树,但是节点中含有指向父节点的指针)——普通的树。


2、如果是这课树是二叉树,并且是排序二叉树,是可以找到给定两个结点的最低公共祖先的。

直观思路:排序二叉树是排序过的,位于左子树的结点值都比父节点小,位于右子树的结点值都比父节点大。

那么,我们只需要从排序二叉树的根节点开始和输入的两个结点进行比较。

如果当前结点的值比两个结点的值都大,那么最低的公共祖先肯定在当前结点的左子树中,于是下一步遍历当前结点的左子树即可。如果当前结点的值比两个结点的值都小,那么最低的公共祖先肯定在当前结点的右子树中,于是下一步遍历当前结点的右子树即可。这样,在树中从上到下找到的第一个在两个给定结点的值之间的结点,就是我们寻求第一个公共最先结点。


3、如果这棵树不是排序二叉树,只是一棵普通的二叉树而已,但是每个结点都存在指向父结点的指针,也是可以找到给定两个结点的最低公共祖先的。

直观思路:如果每个结点都存在指向父节点的指针,那么这个问题可以转化为寻求两个单链表的第一个公共结点。

假设树节点中指向父节点的指针是pParent,那么从树的每一个叶子节点到树的根节点都存在一条由指针pParent 连接起来的单链表。

输入两个结点,那么这两个结点位于两个链表上,它们的最低公共祖先刚好就是这两个单链表的第一个公共结点。

比如输入的两个结点分别是:F 和 H。则F 结点位于单链表:F—D—B—A;H 结点位于单链表:H—E—B—A。

所有它们的第一个公共结点B 就是它们的最低公共祖先。


4、现在假设这棵树是普通的二叉树,没有指向父节点的指针,其实是可以找到给定两个结点的最低公共祖先的。

直观思路:我们首先得到一条从根节点到树中某一节点的路径,这就要求我们在遍历的时候,需要有一个辅助内存来保存路径。比如,我们用前序遍历的方式来得到从根节点到 H 结点的路径过程是这样的:

(1)先遍历根节点A,把A 存放到路径中去,现在路径中有一个节点A ;

(2)遍历到B,把B 存放到路径中去,此时路径为A——B;

(3)遍历到D,把D 存放到路径中去,此时路径为A——B——D;

(4)遍历到F,把F 存放到路径中去,此时路径为A——B——D——F;

(5)F 已经没有子节点了,因此这条路径不可能到达结点H。于是把F 从路径中删除掉,变成A——B——D;

(6)遍历D 的右孩子G,和节点F 一样,这条路径也不能到达H。遍历完G 之后,路径仍然是A——B——D;

(7)由于D 的所有子节点都遍历完了,不可能通过D 达到结点H,所有D 不在从A 到H 的路径中,所有删除D,变成A——B;

(8)遍历E,把E 加入到路径中去,此时路径变成A——B——E;

(9)遍历H,发现已经达到目标结点,A——B——E;就是根节点到H 结点必须经过的路径。

同样的,我们按照这种方法再得到另外一个条指定节点的路径A——B——D;接着,我们求出它们的最后一个公共结点B,也就是F 和H 的最低公共祖先。


时间复杂度:两次遍历树,每一次遍历的时间复杂度都是O(n)。

空间复杂度:得到的路径最差情况是O(n),普通情况两条路径的长度是O(logN)。


最难的是题4的代码,如下:

//题目4
#include<iostream>
#include<list>
using namespace std;
struct BiTree
{
	int value;
	BiTree *pLeft;
	BiTree *pRight;
	BiTree(int x):value(x),pLeft(nullptr),pRight(nullptr) {}
};
//得到指定节点的路径
bool GetNodePath(BiTree *pRoot, BiTree *pNode, list<BiTree *> &path)
{
	if(pRoot==nullptr || pNode==nullptr)
		return false;
	path.push_back(pRoot);
	bool found=false;
	if(pRoot==pNode)
	{
		found=true;
		return found;
	}
	if(!found && pRoot->pLeft)
		found=GetNodePath(pRoot->pLeft,pNode,path);
	if(!found && pRoot->pRight)
		found=GetNodePath(pRoot->pRight,pNode,path);
	if(!found)
		path.pop_back();
	return found;
}
//得到两条路径的最后公共节点
BiTree *GetLastCommomNode(const list<BiTree *> path1, const list<BiTree *> path2)
{
	list<BiTree *>::const_iterator iterator1=path1.cbegin();
	list<BiTree *>::const_iterator iterator2=path2.cbegin();
	BiTree *pLast=nullptr;
	while(iterator1 != path1.cend() && iterator2 != path2.cend())
	{
		if(iterator1 == iterator2)
			pLast=*iterator1;
		++iterator1;
		++iterator2;
	}
}

//综合起来的函数
BiTree *GetLastCommomNodeParent(BiTree *pRoot, BiTree *pNode1, BiTree *pNode2)
{
	if(pRoot==nullptr || pNode1==nullptr || pNode2==nullptr)
		return nullptr;
	list<BiTree *> path1;
	list<BiTree *> path2;
	GetNodePath(pRoot,pNode1,path1);
	GetNodePath(pRoot,pNode2,path2);
	return GetLastCommomNode(path1,path2);
}


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 2021年,软件测试面试大全提供了很多有关软件测试的面试,这些面试不仅包含了基础知识,还涵盖了软件测试进阶的一些问。对于想要进入软件测试行业的人来说,这些问是必须要掌握的。 在软件测试面试中,常常会被问到软件测试的定义、测试的重要性、测试方案、测试时间、缺陷管理等等问。此外,还会遇到许多关于测试工具、测试流程、测试技术等的问。这些问都需要我们具备一定的基础知识和实践经验。 如果想要进阶,我们则需要了解自动化测试、性能测试、安全测试和接口测试等测试技术。需要具备技术储备,掌握相关测试工具和测试技术。同时,也要能够理解测试报告和测试数据分析。只有掌握了这些,我们才能更好地开展软件测试工作。 总之,软件测试面试大全为我们提供了很多关于软件测试的常见问和进阶问,学习这些问对于我们进入软件测试行业并提高自身的软件测试技能有着重要的作用。 ### 回答2: 软件测试是软件开发过程中重要的一环,它是保障软件质量和稳定性的重要手段。在软件测试领域,面试是评估测试人员技能能力的重要手段,因此掌握一些常见的软件测试面试目是非常必要的。下面就来回答一下2021年软件测试面试大全这个主。 首先,需要明确的是,不同公司在软件测试方面的需求和侧重点是不同的。因此,不同公司的软件测试面试目也可能有所不同。但是,基本的软件测试知识和基本技能是需要掌握的。在具体的软件测试面试目中,可能会涉及到测试策略、测试用例设计、测试工具使用、缺陷管理、QTP/Selenium等工具的使用、性能和安全测试、自动化测试等方面的问。 测试策略是软件测试的重要组成部分,测试人员需要了解不同的测试方法和级别,选择适合项目的测试策略。在面试中,可能会考察测试用例设计能力,例如如何设计一份高质量的测试用例,如何覆盖完整的功能需求和非功能需求,如何有效地管理测试用例。在测试工具使用方面,可能会考察测试人员对一些比较常用的测试工具的掌握程度,例如JMeter、LoadRunner、TestLink、Bugzilla等工具的使用。 在实际的软件测试过程中,缺陷管理是必不可少的,测试人员需要学会如何有效地管理软件中的缺陷。在面试中,可能会考察测试人员对缺陷管理流程的了解程度,如何有效地分析和处理缺陷。QTP和Selenium是两个比较常用的自动化测试工具,可能会出现这两个工具的相关面试目。 性能和安全测试也是软件测试过程中重要的组成部分,测试人员需要掌握对应的测试技能和测试工具。在面试中,可能会考察测试人员对Web应用的性能和安全测试的了解程度,如何使用性能测试工具进行效能测试和负载测试,如何对Web应用进行安全测试。 总之,2021年软件测试面试大全主要涉及了软件测试中的一些关键点,测试人员需要在这些方面有较强的技能和实践经验。而为了更好地应对面试,测试人员要不断学习和提升自己的能力,掌握常见的测试知识和技术,增强自己的实践经验,才能在面试中取得好的成绩。 ### 回答3: 2021年软件测试面试大全 面试是我们获取工作机会的重要途径之一,对于软件测试工程师来说也是一样。在面试前,掌握一些相关的软件测试知识和面试目就显得尤为重要了。接下来,本文将为大家整理出一些2021年软件测试面试大全,希望对大家有所帮助。 一、软件测试基础知识 1.什么是软件质量? 答:软件质量是指软件能够满足用户的需求和期望,包括正确性、可靠性、可用性、易用性、可维护性、可移植性等方面的属性。 2.什么是软件测试? 答:软件测试是为了判断和评估软件产品是否满足相关需求和设计要求的过程。测试中包括评估测试结果并对测试结果提出建议的过程。 3.软件测试过程包括哪些步骤? 答:软件测试过程包括测试计划、测试设计、测试执行、测试评估和测试状态报告等步骤。 4.软件测试中常见的测试层次有哪些? 答:软件测试中常见的测试层次包括单元测试、集成测试、系统测试和验收测试。 二、测试方法和技术 1.什么是黑盒测试? 答:黑盒测试又被称为功能测试,是一种只关心软件输入和输出的测试方法,测试人员只需关注输入和输出数据,而不需要关心程序的内部实现。 2.什么是白盒测试? 答:白盒测试也被称为结构测试,它是一种测试人员以程序的内部结构为基础的测试方法,它的目的是通过对程序代码的覆盖率达到发掘潜在缺陷的目的。 3.什么是灰盒测试? 答:灰盒测试是介于黑盒测试和白盒测试之间的测试方法,既关注输入和输出数据,也关注程序的内部实现。 4.什么是自动化测试? 答:自动化测试是通过自动化脚本、工具或程序来执行测试的方式,它能够提高测试效率、降低测试成本和提高测试质量等方面的优点。 三、测试工具和框架 1.什么是Selenium? 答:Selenium是一个流行的自动化测试框架,可以用来测试Web应用程序,支持多种编程语言和多种浏览器。 2.什么是JMeter? 答:JMeter是一个流行的性能测试工具,可以测试Web应用程序、Web服务、FTP、数据库、JMS、LDAP等多种应用程序。 3.什么是LoadRunner? 答:LoadRunner是一套性能测试软件,用于模拟并发用户访问服务器的行为,通过观察系统响应时间、效率和性能瓶颈等指标,来评估软件系统的性能,以及确定系统背负的最大负载。 四、其他测试相关问 1.在测试中,什么是测试用例? 答:测试用例是为了测试特定的产品功能、模块、系统或软件应用程序而创建的一组输入、执行条件和预期结果。 2.什么是缺陷跟踪系统? 答:缺陷跟踪系统是一种用来记录软件缺陷的系统,能够对缺陷信息进行记录、追踪和管理,以便于开发人员进行修复、测试人员进行验证以及管理人员进行缺陷跟踪和分析。 3.什么是Bug Priority 和 Bug Severity? 答:Bug Priority是指缺陷的优先级,用来表明缺陷修复的重要性;而Bug Severity是指缺陷的严重程度,用来表明缺陷对应用程序的影响程度。 总结 软件测试在软件开发过程中具有重要的地位和作用,掌握基础知识、测试方法和技术以及测试工具和框架等相关知识能够帮助测试人员更好的面对工作中的问和挑战。同时,了解测试相关问也能够帮助测试人员更好的与其他相关岗位的工作进行协作,达到更好的工作效果和成果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值