Advertisement

LCA(最近公共祖先)算法:Tarjan与倍增方法

  •  5星
  •     浏览量: 0
  •     大小:None
  •      文件类型:PDF


简介:
本文介绍了两种求解树上节点最近公共祖先问题的经典算法——Tarjan离线算法和倍增在线算法,深入探讨其原理及应用。 LCA Tarjan实现原理 理解:这是一种离线算法,在构建好树之后进行查询,并通过一次DFS解决所有询问。 时间复杂度为O(n+q);其中n表示节点数,q表示询问次数。 补充内容包括链式向前星、并查集和Tarjan算法的具体应用。以下是代码示例: ```cpp #include #include #include using namespace std; const int MAXN = 5e5 + 10; int fa[MAXN], head[MAXN], head_ask[MAXN]; bool vis[MAXN]; struct Edge { // 边的结构体定义 }; ``` 这里省略了具体的Edge结构体和其他部分代码细节,主要展示了引入所需库文件和定义常量及变量的部分。

全部评论 (0)

还没有任何评论哟~
客服
客服
  • LCATarjan
    优质
    本文介绍了两种求解树上节点最近公共祖先问题的经典算法——Tarjan离线算法和倍增在线算法,深入探讨其原理及应用。 LCA Tarjan实现原理 理解:这是一种离线算法,在构建好树之后进行查询,并通过一次DFS解决所有询问。 时间复杂度为O(n+q);其中n表示节点数,q表示询问次数。 补充内容包括链式向前星、并查集和Tarjan算法的具体应用。以下是代码示例: ```cpp #include #include #include using namespace std; const int MAXN = 5e5 + 10; int fa[MAXN], head[MAXN], head_ask[MAXN]; bool vis[MAXN]; struct Edge { // 边的结构体定义 }; ``` 这里省略了具体的Edge结构体和其他部分代码细节,主要展示了引入所需库文件和定义常量及变量的部分。
  • 二叉树的
    优质
    简介:在二叉树中寻找两个节点的最低共同父节点问题,即最近公共祖先。此算法广泛应用于计算机科学与数据结构研究中。 使用Java语言通过栈的方法建立二叉树,并利用递归求解最近共同祖先节点。
  • 二叉树中两个节点
    优质
    本文章介绍了如何在二叉树中寻找任意两个节点的最近公共祖先的高效算法。通过递归方法深入探讨了问题解决策略和实现细节。 需要拟定合适的二叉树输入形式;构造求共同祖先的算法;以直观的形式展示所建立的二叉树;使用Microsoft Visual C++ 6.0 编译环境进行调试运行。
  • 用C语言查找二叉树节点的
    优质
    本篇技术文章深入探讨了使用C语言实现寻找二叉树中两个指定节点的最近公共祖先的方法。文中详细解析了算法逻辑,并提供了代码示例,旨在帮助开发者理解与优化相关数据结构操作技巧。 在二叉树中,最低公共祖先(Lowest Common Ancestor, LCA)是指同时是两个给定节点的最近共同祖先。本篇主要介绍如何使用C语言求解二叉树节点的最低公共祖先,并结合ACM题目进行深入解析。 我们考虑最通用的情况:即树不一定是二叉排序树,也不一定有指向父节点的指针。在这种情况下,求解LCA的基本思路是先分别找到两个给定节点到根节点的路径,然后找到这两条路径上的最后一个相同节点,这个节点就是最低公共祖先。 以下是具体实现代码片段: ```c typedef struct BinaryNode { int value; struct BinaryNode *left; struct BinaryNode *right; } BinaryNode; bool GetNodePath(BinaryNode *pRoot, BinaryNode *pNode, vector &v) { if (pRoot == NULL) return false; v.push_back(pRoot); if (pRoot == pNode) return true; bool found = GetNodePath(pRoot->left, pNode, v); if (!found) found = GetNodePath(pRoot->right, pNode, v); if (!found) v.pop_back(); } BinaryNode* GetCommonParent(BinaryNode *pRoot, BinaryNode *pNode1, BinaryNode *pNode2) { if (pRoot == NULL || pNode1 == NULL || pNode2 == NULL) return NULL; vector v1, v2; GetNodePath(pRoot, pNode1, v1); GetNodePath(pRoot, pNode2, v2); BinaryNode *pLast = pRoot; vector::iterator ite1 = v1.begin(), ite2 = v2.begin(); while (ite1 != v1.end() && ite2 != v2.end()) { if (*ite1 == *ite2) pLast = *ite1; ite1++; ite2++; } return pLast; } ``` 在ACM题目中,给定一颗树的先序遍历序列和两个节点值,我们需要找出这两个节点的最低公共祖先。这个问题可以通过后序遍历的思想解决,利用栈来保存路径,然后找到两个路径的第一个公共节点。 这里给出一个基于后序遍历思路的C代码示例: ```c #include #include #define N 7000 typedef struct btree { int val; struct btree *left; struct btree *right; } BTree; BTree* buildTree(int* preorder, int preStart, int preEnd, int* inorder, int inStart, int inEnd) { if (preStart > preEnd) return NULL; BTree* node = (BTree*)malloc(sizeof(BTree)); node->val = preorder[preStart]; if (preStart == preEnd) return node; int inIndex = search(inorder, inStart, inEnd, node->val); node->left = buildTree(preorder, preStart + 1, preStart + inIndex - inStart, inorder, inStart, inIndex - 1); node->right = buildTree(preorder, preStart + inIndex - inStart + 1, preEnd, inorder, inIndex + 1, inEnd); return node; } int search(int* inorder, int start, int end, int val) { for (int i = start; i <= end; i++) { if (inorder[i] == val) return i; } return -1; } BTree* LCA(BTree* root, BTree* n1, BTree* n2) { stack st; BTree* lastNode = NULL; while (root || !st.empty()) { while (root) { st.push(root); root = root->left; } root = st.top(); st.pop(); if (root == n1 || root == n2) { lastNode = root; } else if (lastNode && (root->left == lastNode || root->right == lastNode)) { return lastNode; } root = root->right; } return NULL; } int main() { // 输入处理和调用函数求解LCA } ``` 在样例输入中,我们有两个测试案例。第一个案例中给定的树先序遍历序列是`1 2 4 6 0 0 7 0 0 5 8 0 0 9 0 0 3 0 0`,查询两个节点值分别为`6`和`8`,其
  • 寻找二叉树的
    优质
    本题要求在给定的一棵二叉树中寻找两个节点的最近公共祖先。通过递归遍历二叉树,确定目标节点与当前节点的关系,从而找到它们的最近共同祖先。 面试题68 – II. 二叉树的最近公共祖先 【简单题】【递归】 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 对于有根树 T 的两个结点 p、q,定义它们的最近公共祖先是满足以下条件的一个结点 x:x 是 p 和 q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。 例如,给定如下二叉树: root = [3,5,1,6,2,0,8,null,null,7,4] 输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5 , q = 1 输出:3 解释:节点 5 和节点 1 的最近公共祖先是节点 3。
  • 关于树的直径和的PPT演示文稿
    优质
    本PPT探讨了树数据结构中的两个关键概念:树的直径(最长路径)与最近公共祖先问题。通过实例解析及算法讲解,深入浅出地介绍了这两种重要特性及其应用价值。 在计算机科学领域,树作为一种关键的数据结构,在算法设计与问题求解方面发挥着重要作用。本讲座主要讨论的是树的两个核心概念——直径和最近公共祖先(LCA),这两个主题尤其受到图论及竞赛编程社区的关注。 首先来解释一下“树的直径”这一术语。“树的直径”,指的是在给定的一棵树中,任意两点间距离最长的一条路径。这条路径可以穿过其他节点。求解这个值时,我们通常会使用动态规划的方法:定义`dp[u]`为从顶点u出发向下延伸的最大长度,并通过递推公式 `dp[u] = max(dp[u], dp[v] + edge[i])` 来更新状态,这里`edge[i]`代表边长(即节点u到子节点v的距离)。 然而直接应用上述方法可能会导致大量的重复计算。为了提高效率,我们可以采用差分技术来优化:对于路径x至y上的每个点v, 我们增加到达z的计数值 `c[v][z]++`;进一步改进为对树上每一点的操作进行差分解构化处理——即执行 `c[x][z]++`, `c[y][z]++`, `c[lca][z]++` 以及 `c[fa[lca]][z]++`,其中lca代表x和y的最近公共祖先节点,而`fa[lca]`则是该点的父亲。这样的处理可以有效减少重复计算。 更进一步地,我们还可以利用线段树来优化路径上的更新操作。线段树能够在O(logn)的时间复杂度内完成区间查询与更新操作,从而显著提升算法效率。 接下来讨论的是“最近公共祖先”(LCA),它定义为在给定的树中两个节点共享的最深共同父节点。计算LCA的方法多样,包括Morris-Pratt算法和RMQ配合二进制索引树等技术,在解决直径问题时经常与动态规划结合使用以确定最长路径中的关键点。 总之,理解和掌握求解“树的直径”及“最近公共祖先”的方法不仅有助于解决具体编程挑战,还能加深对数据结构特别是树形结构的理解,并提高整体算法能力。在实际练习中灵活运用这些技巧,则可以显著提升问题解决速度和代码质量。
  • C++中计约数数,通过约数求解
    优质
    本文探讨了在C++编程语言环境下如何高效地计算两个整数的最大公约数(GCD)和最小公倍数(LCM)。特别强调了一种基于GCD的方法来快速准确地求得两数的LCM,为程序员提供了一种优化算法实现的有效途径。 在C++中求两个数的最大公因数(GCD)和最小公倍数(LCM),可以利用最大公因数法来计算最小公倍数。这种方法基于数学公式:两数的乘积等于它们的最大公约数与最小公倍数的乘积,即 a*b = GCD(a, b) * LCM(a, b),从而可以根据已知条件求出另一值。
  • K邻(KNN):
    优质
    K近邻(K-Nearest Neighbors, KNN)算法是一种基本的数据分类与回归方法,通过计算待分类样本与训练集中各点的距离,选取距离最近的K个邻居投票决定该样本的类别。 KNN(K近邻)算法是指每个样本由其最接近的k个邻居来代表。 用一句古语来说就是“物以类聚,人以群分”。例如一个人的朋友圈中有马云、王健林、李嘉诚等知名人士,那么这个人很可能也是这个圈子中的一员。同样地,一个爱好游戏的人的朋友圈里大部分也应该是玩游戏的;爱喝酒的人的朋友圈则多为爱喝酒之人。正如那句话所说,“臭味相投”。 最近邻算法是一种分类方法,在1968年由Cover和Hart提出,适用于字符识别、文本分类以及图像识别等领域。 该算法的基本思想是:一个样本如果与数据集中k个最相似的样本大多数属于同一类别,则认为这个样本也属于这一类。
  • 求解约数数的常用
    优质
    本文探讨了用于计算两个或多个整数的最大公约数(GCD)和最小公倍数(LCM)的各种经典算法。涵盖了辗转相除法、穷举法及更相减损术等方法,旨在为编程与数学爱好者提供实用指南。 计算最大公约数和最小公倍数的常见算法包括多种方法。其中最常用的是辗转相除法(也称为欧几里得算法)来求解两个整数的最大公约数,然后通过已知两数及其最大公约数的关系推算出它们的最小公倍数。此外还有更直接的方法如穷举法、分解质因数等用于特定场景下的计算需求。每种方法都有其适用范围和优缺点,在实际应用中可以根据具体情况选择最合适的算法进行求解。
  • 训练题:求数(Python)
    优质
    本文章提供了一个用Python编写的算法练习实例,旨在帮助读者理解和实现计算两个整数最小公倍数的方法。通过代码示例详细解释了算法原理及应用技巧。 思路:取两数中的较大者作为起点至这两数的乘积进行for循环比较。 问题描述: 编写一个函数lcm来求两个正整数的最小公倍数。 样例输入: 3 5 样例输出: 15 数据规模和约定: 输入的数据中每一个数值范围为:两个数都小于65536。 代码实现如下: ```python def lcm(x, y): temp = max(x, y) for i in range(temp, x * y + 1): if i % x == 0 and i % y == 0: return i ``` 这段代码定义了一个名为lcm的函数,它接受两个参数x和y,并返回这两个数的最小公倍数。