热门标签 | HotTags
当前位置:  开发笔记 > 后端 > 正文

二叉树的最近公共祖先并不简单

某一天中午吃饭的时候,一同事问我:怎么找二叉树的最近公共祖先。我起初以为这是一道青铜题,真正了解题意后,发现这是一道王者题。给一棵树,以及树上的两个节点指针。

一、背景

某一天中午吃饭的时候,一同事问我:怎么找二叉树的最近公共祖先。

我起初以为这是一道青铜题,真正了解题意后,发现这是一道王者题。

二、题意

给一棵树,以及树上的两个节点指针。

求这两个节点在树上的最近公共祖先。

如下图,

节点 7 和节点 0 的最近公共祖先是节点 3

节点 4 和节点 6 的最近公共祖先是节点 5

二叉树的最近公共祖先并不简单

那该如何实现一个算法,找到两个节点的最近公共祖先呢?

三、链表相交思想

同时问我这个问题的时候,我首先想到的是链表相交,求第一个交点的算法思想。

如果每个节点有指向父节点的指针的话,我们就可以把给的两个节点当做链表头,树的根是链表尾部。

这样问题就转化为了求两个相交链表的第一个交点。

对应的思想是先遍历两个链表分别求出两个链表的长度。

然后对其长度,使得两个节点处于树的同一层。

最后同时向上遍历,判断是不是同一个节点,试了就找到交点了。

但是题目给的是一个普通的二叉树,没有父节点指针,所以就需要想其他方法了。

四、初级递归

面对树的问题,很容易想到递归处理。

同样,这个题也可以使用递归处理。

思路大概是:

  1. 先判断公共祖先是否在左子树,是则找到
  2. 再判断公共祖先是否在右子树,是则找到
  3. 当前根是不是公共祖先,是则找到
  4. 当前树没有公共祖先

这里有一个关键问题:怎么判断当前根是不是公共祖先呢?

这个貌似又是一个递归题,可以拆解为根是不是节点 A 的祖先和根是不是节点 B 的祖先。

两个同时满足了,根就是这两个节点的公共祖先。

这样这道题我们就做出来了,但是复杂度貌似有点高。

对于每个子树,都进行了判断根是不是祖先,这样就相当于双层循环,复杂度是 O(n^2)

二叉树的最近公共祖先并不简单

所以我们需要继续思考,有没有更简单的方法。

五、高级递归

其实,在初级递归的时候,复杂度之所高,就是需要在每个子树里判断一个根是不是两个节点的祖先。

这个判断在每个子树里是独立的,但是实际上树与树之间是有关系的。

比如当前树的左儿子是节点 A 的祖先,那当前树的根肯定也是节点 A 的祖先。

递归的时候,如果能服用这个信息,则可以将复杂度降低到 O(n)

二叉树的最近公共祖先并不简单

上面的递归代码需要返回三个值。

最近公共祖先通过返回值返回,没找到则返回 NULL

两个节点是否找到使用参数引用的方式返回。

然后用下面的代码来判断,某个节点是否在当前子树里。

  1. 是否等于根
  2. 是否在左子树
  3. 是否在右子树
pCncestor = p == root || leftPCncestor || rightPCncestor; //if find p in root
qCncestor = q == root || leftQCncestor || rightQCncestor; //if find q in root

这样,这个道题我们就可以在 O(N) 内解决了。

当然,当时同事网上看的解题源码不是这种思想。

而是一种比较抽象的方法:只有一个返回值,含义是当前子树是否至少含一个节点。

这是一个返回值在不同的条件下含义是不同的。

如下图,如果根和某个节点相同,则返回根。

这里隐含两个含义:

1.如果两个节点都在这颗树里,根是其中一个节点,答案是根。

2.如果只有一个节点在这颗树里,那只能是根了,返回根代表找到了至少一个节点。

然后递归求出连个子树的状态,如果分别都找到一个节点,则代表根是节点。

否则说明这棵树只有一个节点,是谁就返回谁。

二叉树的最近公共祖先并不简单

六、最后

这道题其实还蛮有难度的,一个递归需要返回多种状态。

状态一多,很多人就弄不明白了。

-EOF-


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 我们


推荐阅读
  • Google排名优化-面向Google(Search Engine Friendly)的URL设计 ... [详细]
  • 深入理解OAuth认证机制
    本文介绍了OAuth认证协议的核心概念及其工作原理。OAuth是一种开放标准,旨在为第三方应用提供安全的用户资源访问授权,同时确保用户的账户信息(如用户名和密码)不会暴露给第三方。 ... [详细]
  • 深入解析TCP/IP五层协议
    本文详细介绍了TCP/IP五层协议模型,包括物理层、数据链路层、网络层、传输层和应用层。每层的功能及其相互关系将被逐一解释,帮助读者理解互联网通信的原理。此外,还特别讨论了UDP和TCP协议的特点以及三次握手、四次挥手的过程。 ... [详细]
  • 本文介绍了一种适用于小型创业公司的小规模每日数据备份及健康检查的自动化解决方案。通过简单的Shell脚本实现本地数据库的每日全量备份,并将备份文件上传至中心备份服务器。同时,编写了自动检测脚本来确保备份的完整性和及时性,一旦发现异常,会通过邮件和短信通知相关人员。 ... [详细]
  • 本文深入探讨了传输层的另一个重要协议——用户数据报协议(UDP)。在了解了TCP协议的基础上,我们将详细解析UDP的工作原理、应用场景及其优缺点,帮助读者全面理解为什么需要UDP。 ... [详细]
  • 中科院学位论文排版指南
    随着毕业季的到来,许多即将毕业的学生开始撰写学位论文。本文介绍了使用LaTeX排版学位论文的方法,特别是针对中国科学院大学研究生学位论文撰写规范指导意见的最新要求。LaTeX以其精确的控制和美观的排版效果成为许多学者的首选。 ... [详细]
  • 嵌入式开发环境搭建与文件传输指南
    本文详细介绍了如何为嵌入式应用开发搭建必要的软硬件环境,并提供了通过串口和网线两种方式将文件传输到开发板的具体步骤。适合Linux开发初学者参考。 ... [详细]
  • 本文详细介绍了如何下载并安装 Python,包括选择合适的版本、执行安装程序以及设置环境变量的步骤。此外,还提供了测试安装是否成功的简单方法。 ... [详细]
  • 为了解决不同服务器间共享图片的需求,我们最初考虑建立一个FTP图片服务器。然而,考虑到项目是一个简单的CMS系统,为了简化流程,团队决定探索七牛云存储的解决方案。本文将详细介绍使用七牛云存储的过程和心得。 ... [详细]
  • 本文详细介绍了 phpMyAdmin 的安装与配置方法,适用于多个版本的 phpMyAdmin。通过本教程,您将掌握从下载到部署的完整流程,并了解如何根据不同的环境进行必要的配置调整。 ... [详细]
  • 在编译BSP包过程中,遇到了一个与 'gets' 函数相关的编译错误。该问题通常发生在较新的编译环境中,由于 'gets' 函数已被弃用并视为安全漏洞。本文将详细介绍如何通过修改源代码和配置文件来解决这一问题。 ... [详细]
  • 优化后的摘要:本文详细分析了当前面临的挑战和机遇,结合具体实例探讨了如何通过创新和改革来推动长期可持续发展。文中还介绍了多种可行的解决方案,并强调了在不同阶段实施这些方案的重要性。 ... [详细]
  • 本文介绍如何配置SecureCRT以正确显示Linux终端的颜色,并解决中文显示问题。通过简单的步骤设置,可以显著提升使用体验。 ... [详细]
  • CentOS 7.2 配置防火墙端口开放
    本文介绍如何在 CentOS 7.2 系统上配置防火墙以开放特定的服务端口,包括 FTP 服务的临时与永久开放方法,以及如何验证配置是否生效。 ... [详细]
  • 在Windows Server 2008 R2上配置IIS FTP服务
    本文详细介绍了如何在Windows Server 2008 R2操作系统上通过IIS配置FTP服务的过程,包括服务器角色的选择与安装、FTP站点的创建以及必要的服务和防火墙设置检查。 ... [详细]
author-avatar
葉_沛峰
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有