最近公共祖先(least common ancestors algorithm)
lca问题是最近公共祖先问题,一般是针对树结构的。
现在有两种方法来解决这样的问题
1. On-line algorithm
用比较长的时间做预处理。然后对每次询问进行回答。
思路:对于一棵树中的两个节点,假设是u和v。我们要找到他们的最近的一个祖先,那么我们可以这样找,首先判断他们是不是一辈儿的人,也就是说他们的深度是不是一样的,如果一个较深(u),一个较浅(v)。我们可以不断的找较深的节点的祖先,直到u和v的深度一致。如果此时u和v重合了,那么u(v)就是他们的最近公共最先,如果不重合,这时,就可以同时找u和v的祖先,直到找到为止(最坏的情况是根节点)。
这个思路比较好理解,处理也很方便,在求lca之前,可以通过dfs找到所有节点的father信息和depth信息。然后就可以按照思路进行求解了。
这个问题和编程之美中的一个题目非常的类似:判断两个链表是否相交。
扩展问题是,找他们的第一个交点(假设他们相交的话)。
思路:首先能够找到两条链表的长度,这个其实是两个链表首指针的depth信息。然后判断他们的depth是否一样,如果一个深,一个浅,那么首先让他们depth相同(对于指针,只需要next就可以了),然后判断当前的两个指针是否重合,如果不重合,那么两个指针,一起next,直到找到第一个交点。
发现,这两问题惊人的相似。感叹算法的灵活性~
2. off-line algorithm
离线算法,就是把所有的询问都读取进来,在算法执行的过程中,就把所有的询问回答了。
tarjan 算法是经典的离线lca算法。
tarjan算法利用了一个用于集合操作的数据结构-并查集(union-find set or disjoint set). 不过这里这个数据结构只是辅助性的,对于理解算法并无影响,理解了算法可以在去了解并查集是怎么一回事。
tarjan算法基于这样一个规律:假设当前节点为root,root节点肯定有很多子树了(每个儿子带领一个),那么我们从最左边的子树开始研究,如果要查询的两个节点u,v都在最左子树,那么这变成了一个更小规模的问题了。如果u在最左子树,而v在其他的子树,那么lca(v,u)=father(u)了。那么如果u在最左子树的一个子树里边,那么lca(v,u) = father(father(u)). 看到这里,熟悉并查集的同学,可能就知道了这就有点象查找集合的father信息。没错,这就是tarjan算法核心思想。
再用简单的语言描述一下:当我们dfs完一个节点v的时候,可以想象,以v为根的所有节点的father全是v了,此时我们从询问中查找,有没有和v相关的询问。如果有,那么查看u是否已经访问过了,如果访问过,肯定有father信息。试想,如果u和v在一棵子树里,那么v和u的lca就是v了。如果u在之前的子树里,lca(v,u) = father(u) 或者 lca(v,u)=father(father(u)),总之就是找u所在集合的根元素了。此时此刻,基本就把算法的思想搞的很明白了。
最近公共祖先(least common ancestors algorithm)的更多相关文章
- 最近公共祖先 Lowest Common Ancestors
基于深度的LCA算法: 对于两个结点u.v,它们的深度分别为depth(u).depth(v),对于其公共祖先w,深度为depth(w),u需要向上回溯depth(u)-depth(w)步,v需要d ...
- 最近公共祖先 Least Common Ancestors(LCA)算法 --- 与RMQ问题的转换
[简介] LCA(T,u,v):在有根树T中,询问一个距离根最远的结点x,使得x同时为结点u.v的祖先. RMQ(A,i,j):对于线性序列A中,询问区间[i,j]上的最值.见我的博客---RMQ - ...
- [Swift]LeetCode235. 二叉搜索树的最近公共祖先 | Lowest Common Ancestor of a Binary Search Tree
Given a binary search tree (BST), find the lowest common ancestor (LCA) of two given nodes in the BS ...
- [Swift]LeetCode236. 二叉树的最近公共祖先 | Lowest Common Ancestor of a Binary Tree
Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree. According ...
- 最近公共祖先 · Lowest Common Ancestor
[抄题]: Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree. “Th ...
- 学习笔记--最近公共祖先(LCA)的几种求法
前言: 给定一个有根树,若节点\(z\)是两节点\(x,y\)所有公共祖先深度最大的那一个,则称\(z\)是\(x,y\)的最近公共祖先(\(Least Common Ancestors\)),简称\ ...
- 最近公共祖先 LCA 倍增算法
树上倍增求LCA LCA指的是最近公共祖先(Least Common Ancestors),如下图所示: 4和5的LCA就是2 那怎么求呢?最粗暴的方法就是先dfs一次,处理出每个点的深度 ...
- [总结]最近公共祖先(倍增求LCA)
目录 一.定义 二.LCA的实现流程 1. 预处理 2. 计算LCA 三.例题 例1:P3379 [模板]最近公共祖先(LCA) 四.树上差分 1. 边差分 2. 点差分 3. 例题 一.定义 给定一 ...
- 编程算法 - 二叉树的最低公共祖先 代码(C)
二叉树的最低公共祖先 代码(C) 本文地址: http://blog.csdn.net/caroline_wendy 二叉树的最低公共祖先(lowest common ancestor), 首先先序遍 ...
随机推荐
- 【14.94%】【codeforces 611E】New Year and Three Musketeers
time limit per test2 seconds memory limit per test256 megabytes inputstandard input outputstandard o ...
- 从Client应用场景介绍IdentityServer4(二)
原文:从Client应用场景介绍IdentityServer4(二) 本节介绍Client的ClientCredentials客户端模式,先看下画的草图: 一.在Server上添加动态新增Client ...
- 实现在 .net 中使用 HttpClient 下载文件时显示进度
在 .net framework 中,要实现下载文件并显示进度的话,最简单的做法是使用 WebClient 类.订阅 DownloadProgressChanged 事件就行了. 但是很可惜,WebC ...
- TCP 和 UDP 的区别
参考:http://blog.csdn.net/li_ning_/article/details/52117463 TCP与UDP区别总结: 1.TCP面向连接(如打电话要先拨号建立连接);UDP是无 ...
- 关于java中继承抽象类和实现接口的区别
简单来说,继承就是“是不是”,实现就是“有没有”.(一个大神说的,我觉得很生动很形象 海子大神链接http://www.cnblogs.com/dolphin0520/p/3811437.html)
- DDD实战4 实现产品仓储
a.要实现仓储,首先要定义仓储接口.在领域层定义仓储接口,IProductRepository.cs. public interface IProductRepository { void Creat ...
- 从JDBC到commons-dbutils
1.前言 玩过Java web的人应该都接触过JDBC,正是有了它,Java程序才能轻松地访问数据库.JDBC很多人都会,但是为什么我还要写它呢?我曾经一度用烂了JDBC,一度认为JDBC不过如此,后 ...
- ASP.NET Core Razor 视图导入 - ASP.NET Core 基础教程 - 简单教程,简单编程
原文:ASP.NET Core Razor 视图导入 - ASP.NET Core 基础教程 - 简单教程,简单编程 ASP.NET Core Razor 视图导入 上一章节我们介绍了视图起始页,学习 ...
- 【Android先进】如何使用数据文件来保存程序
在程序,有许多方法来存储和检索数据,本文,它描述了如何使用文件系统来保存数据编程和读取操作 我直接写了一个帮助类,进行文件的写入和读取操作 /** * 用于在文件里保存程序数据 * * @author ...
- 关于Hibernate中hbm2java和hbm2ddl工具
hbm2java:根据映射文件自动生成java源文件 hbm2ddl:根据映射文件自动生成数据库的schema XDoclet:根据带有XDoclet标记的java源文件生成映射文件 Middlege ...