📌  相关文章
📜  二叉树中从一个节点到另一个节点的圈数(1)

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

二叉树中从一个节点到另一个节点的圈数

在二叉树中,一条路径可能会形成一个或多个圈。对于给定的两个节点,我们需要计算从一个节点到另一个节点所经过的圈的数量。本篇文章中,我们将讨论如何在二叉树中实现该算法。

算法思路

对于给定的两个节点 x 和 y,我们需要分别找到从根节点出发到达 x 和 y 的路径,并分别将路径上的节点存储在两个列表中。然后,我们可以比较这两个列表,并找到它们的最近公共祖先(LCA)。

假设 LCA 是节点 z,我们可以计算从 x 到 z 的圈数 p1,以及从 y 到 z 的圈数 p2。因此,从 x 到 y 的圈数就等于 p1 + p2。

下文中,我们将探讨如何实现找到 LCA 和计算圈数的算法。

找到 LCA

在二叉树中找到 LCA 的算法可以使用递归或迭代方式实现。此处,我们将演示递归的实现方式。对于给定的两个节点 x 和 y,执行以下步骤:

  1. 从根节点开始遍历二叉树,如果当前节点为 null,则返回 null。
  2. 如果当前节点为 x 或 y,则返回该节点。
  3. 递归搜索左子树,如果左子树中找到了一个节点(例如 z),则返回该节点。
  4. 递归搜索右子树,如果右子树中找到了一个节点(例如 z),则返回该节点。
  5. 如果左子树和右子树都找到了节点,则说明 x 和 y 分别在左右子树中,此时的当前节点为 LCA。

下面是该算法的代码:

public TreeNode findLCA(TreeNode root, TreeNode p, TreeNode q) {
    if (root == null || root == p || root == q) {
        return root;
    }
    TreeNode left = findLCA(root.left, p, q);
    TreeNode right = findLCA(root.right, p, q);
    if (left != null && right != null) {
        return root;
    }
    return left != null ? left : right;
}

其中,TreeNode 是一个二叉树节点类。

计算圈数

一旦我们找到了 LCA 节点,就可以计算从一个节点到另一个节点的圈数了。假设我们要计算从 x 到 y 的圈数。我们需要进行以下步骤:

  1. 从 x 开始向上遍历二叉树,直到找到 LCA 节点,计算经过的圈数 p1,将从 x 到 LCA 路径上的节点存储在一个列表中。
  2. 从 y 开始向上遍历二叉树,直到找到 LCA 节点,计算经过的圈数 p2,将从 y 到 LCA 路径上的节点存储在另一个列表中。
  3. 反转从 x 到 LCA 的路径列表,并将从 y 到 LCA 的路径列表与其合并。
  4. 对于合并后的列表,从前往后遍历,计算列表中相邻节点之间的圈数,并将其相加即可得到从 x 到 y 的圈数。

下面是该算法的代码:

public int findCircles(TreeNode root, TreeNode p, TreeNode q) {
    List<TreeNode> path1 = new ArrayList<>();
    List<TreeNode> path2 = new ArrayList<>();
    TreeNode lca = findLCA(root, p, q);
    int circles1 = findPath(lca, p, path1);
    int circles2 = findPath(lca, q, path2);
    Collections.reverse(path1);
    path1.addAll(path2);
    int circles = 0;
    for (int i = 0; i < path1.size() - 1; i++) {
        TreeNode node1 = path1.get(i);
        TreeNode node2 = path1.get(i + 1);
        if ((node1.left == node2 && node1.right == null)
                || (node1.right == node2 && node1.left == null)) {
            circles++;
        }
    }
    return circles + circles1 + circles2;
}

private int findPath(TreeNode root, TreeNode target, List<TreeNode> path) {
    if (root == null) {
        return 0;
    }
    if (root == target) {
        return 1;
    }
    int left = findPath(root.left, target, path);
    int right = findPath(root.right, target, path);
    if (left == 1 && right == 0 && ((root.left == target && root.right == null)
            || (root.right == target && root.left == null))) {
        path.add(root);
        return 1;
    }
    if (left == 0 && right == 1 && ((root.left == target && root.right == null)
            || (root.right == target && root.left == null))) {
        path.add(root);
        return 1;
    }
    if (left == 1 && right == 1) {
        path.add(root);
        return 0;
    }
    return left + right;
}
总结

本篇文章中,我们介绍了在二叉树中计算从一个节点到另一个节点的圈数的算法思路。我们首先利用递归算法找到 LCA 节点,然后计算从一个节点到 LCA 节点的圈数,并将路径上的节点存储在列表中。最后,我们可以将两个列表合并,并计算其中的圈数相加,从而得到从一个节点到另一个节点的圈数。