📌  相关文章
📜  有根树中一组节点的最低公共祖先(1)

📅  最后修改于: 2023-12-03 15:40:18.051000             🧑  作者: Mango

有根树中一组节点的最低公共祖先

在有根树中,给定两个节点,它们的最低公共祖先(LCA)是指这两个节点的最深父节点。LCA 是一个经常被使用到的算法,它在很多场景下都有很多的应用,比如计算树的直径、树状数组等。

算法介绍

LCA 算法通常分成两个步骤:

  1. 通过遍历产生节点深度信息
  2. 对于查询时,从低到高比较两个节点的深度信息,寻找它们的最低公共祖先
基础实现

最简单实现方法是用深度优先遍历,遍历整个树,对于每个节点,记录它的深度,当需要查询某两个节点的 LCA 时,从中选出深度最浅的节点作为 LCA。

这种实现方法的时间复杂度是 $O(n)$,其中 $n$ 是树中节点个数。

优化实现

通过对 LCA 问题进一步研究,我们可以发现一个重要的性质:对于树中任意两个节点 $u$ 和 $v$,它们的 LCA 的深度一定是 $u$ 和 $v$ 深度的某个公共前缀的深度。因此,我们可以通过二分答案的方式求解 LCA,这样可将时间复杂度优化为 $O(log(n))$。

在二分答案的实现中,我们需要将原问题拆分成两个子问题,通过对问题空间的二分来确定 LCA 的深度。对于每个节点,我们维护它到根节点的距离,并记录每个节点的深度。对于每次查询,我们可以分别查询两个节点的深度,然后通过二分来查找它们的最低公共祖先。具体实现过程可以参看下面的代码片段。

代码示例

下面的代码示例中,我们用 C++ 和深度优先遍历实现了一个求解 LCA 的函数 getLCA(node1, node2)。其中,node1node2 分别表示要查询 LCA 的两个节点。

struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

class Solution {
public:
    TreeNode* getLCA(TreeNode* root, TreeNode* node1, TreeNode* node2) {
        if (root == nullptr || root == node1 || root == node2) {
            return root;
        }
        TreeNode* left = getLCA(root->left, node1, node2);
        TreeNode* right = getLCA(root->right, node1, node2);
        if (left != nullptr && right != nullptr) {
            return root;
        }
        else if (left != nullptr) {
            return left;
        }
        else {
            return right;
        }
    }
};
总结

LCA 是很常见的算法问题,它可以帮助我们在树中快速地找到某两个节点的最低公共祖先。LCA 的实现方法有很多种,我们可以通过遍历、二分等方法来求解LCA。在实际应用中,需要根据具体情况选择合适的算法实现。