寻找快速算法在二叉树中找到两个节点之间的距离

时间:2010-01-25 18:29:00

标签: algorithm binary-tree

如何在二叉树中找到两个节点之间的距离?同样,有哪些算法可以找到两个节点的最新共同祖先(最低共同祖先)?

7 个答案:

答案 0 :(得分:5)

  1. 计算每个节点的祖先列表
  2. 找到公共前缀
  3. 公共前缀中的最后一个元素是最低共同祖先
  4. 从两个祖先列表中删除公共前缀
  5. 距离是剩余列表的长度总和+1

答案 1 :(得分:4)

找到共同的祖先几乎肯定是更容易的任务。这是一个非常简单的方法:从树的根开始,然后下降树,直到到达一个节点,在这个节点上你必须下降到不同的子节点才能到达有问题的两个节点。该节点是公共父节点(假设树当然包含两个节点)。

答案 2 :(得分:3)

正如这里的每个人似乎都知道的那样,如果你记下每个节点距离根的距离,那么一旦你找到了两个节点的最低共同祖先,你就可以计算出它们彼此之间的距离。恒定时间。

如果你做一次只在树的大小上工作,那么你可以在恒定的时间内找到任何两个节点的最低共同祖先(无论树有多深)。见http://en.wikipedia.org/wiki/Lowest_common_ancestor

最低共同祖先的Baruch Schieber和Uzi Vishkin算法完全可以使用和编程。

答案 3 :(得分:1)

创建两个由每个祖先组成的集合:当集合的联合为空时,将每个节点的下一个祖先添加到适当的列表中。一旦有了一个共同的节点,那就是共同的祖先。

答案 4 :(得分:1)

首先, 搜索第一个元素的高度。 此外,返回使用链接列表到达那里的路径。 您可以在O(logN)时间内执行此操作。假设树是平衡的,其中高度是logN。 设H1 =第一个元素的高度。

然后, 寻找第二个元素的高度。 此外,返回使用链接列表到达那里的路径。 您可以在O(logN)时间内执行此操作。 设H2 =第二元素的高度。

跟踪收集的两个链表,直到值不再相等(路径发散) 在它们发散之前的点,调用该节点H3的高度。

因此,最长的路径是 H1 + H2 - 2 * H3(因为你需要H1进入H1,H2进入H2。但是真的, 你可以追溯到H1直到H1-H3。然后从H3移到H2。 所以它是(H1-H3)+(H2-H3)= H1 + H2-2 * H3。

实施细节应该是直截了当的

search(Tree* Head, Node* Value, LinkedList path, int distance); 

因此,

search(Head, Value1, path1, height1); 
search(Head, Value2, path2, height2); 

i = 0; 
while (path1[i] == path2[i])
{
    i++; 
}
height3 = i-1; 
return height1+height2- 2*height3; 

时间复杂度:O(logN)+ O(logN)+ O(logN)= O(logN) 空间复杂度:O(logN)(用于存储两个链接的距离列表)

答案 5 :(得分:1)

这是BT距离的DP实现。不是最佳的,但很有趣。 它创建了第一个树,带有一个输入数组。

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by juanmf on 05/02/17.
 */
public class Main2 {
    /**
     * {50, 60, 30, 10, 20, 40} will form a Node Structure as follows
     * 5
     * ├─L─ 3
     * │   ├─L─ 1
     * │   │   └─R─ 2
     * │   └─R─ 4
     * └─R─ 6
     * L: left
     * R: Right
     * Path should be: [4, 3, 1, 2]
     * steps: 3 <- output
     *
     * @param args
     */
    public static void main(String[] args) {
        int i = pathSteps(new int[] {50, 60, 30, 10, 20, 40}, 6, 20, 60);
        System.out.println(i);
    }

    private static int pathSteps(int[] ints, int n, int from, int to) {
        Node root = null;
        Map<Node, Node> allNodes = new HashMap<>();

        for (int i: ints) {
            if (root == null) {
                root = new Node(i);
                allNodes.put(root, root);
            }
            root.addNode(i, allNodes);
        }
        Map<Node, List<Node>> cache = new HashMap<>();

        Node fromN = new Node(from);
        Node toN = new Node(to);

        if (! allNodes.containsKey(fromN) || ! allNodes.containsKey(toN)) {
            return -1;
        }
        fromN = allNodes.get(fromN);
        toN = allNodes.get(toN);

        List<Node> path = traverse(fromN, toN, cache);
        return path.size() - 1;
    }

    private static List<Node> traverse(Node fromN, Node toN, Map<Node, List<Node>> cache) {

        if(cache.containsKey(fromN)) {
            System.out.println("cache Hit: " + fromN);

            return cache.get(fromN);
        }
        System.out.println("visiting: " + fromN);
        if (fromN == null || fromN.visited) {
            return new ArrayList<>();
        }
        if (fromN.equals(toN)) {
            List<Node> target = new ArrayList<>();
            target.add(toN);
            return target;
        }
        fromN.visited = true;

        List<Node> parentWay = new ArrayList<>();
        List<Node> lchildWay = new ArrayList<>();
        List<Node> rchildWay = new ArrayList<>();

        parentWay.addAll(traverse(fromN.parent, toN, cache));
        lchildWay.addAll(traverse(fromN.lchild, toN, cache));
        rchildWay.addAll(traverse(fromN.rchild, toN, cache));

        List<Node> shortest = getShortestList(getShortestList(parentWay, lchildWay), rchildWay);

        cache.put(fromN, shortest);
        if (! shortest.isEmpty()) {
            shortest.add(fromN);
        }
        fromN.visited = false;
        System.out.println(shortest);
        return shortest;
    }

    private static List<Node> getShortestList(List<Node> l1, List<Node> l2 ) {
        List<Node> shortest = null;
        if (l1 != null & l2 != null) {
            if (l1.isEmpty()) {
                shortest = l2;
            } else if (l2.isEmpty()) {
                shortest = l1;
            } else {
                shortest = l1.size() < l2.size() ? l1 : l2;
            }
        } else if (l1 == null) {
            shortest = l2;
        } else if (l2 == null) {
            shortest = l1;
        }
        return shortest;
    }

    private static class Node {
        Node parent;
        Node lchild;
        Node rchild;

        final int value;
        public boolean visited;

        private Node(int value) {
            this.value = value;
        }

        public void addNode(int i, Map<Node, Node> allNodes) {
            if (i > value) {
                if (null == rchild) {
                    rchild = new Node(i);
                    rchild.parent = this;
                    allNodes.put(rchild, rchild);
                } else {
                    rchild.addNode(i, allNodes);
                }
            }
            if (i < value) {
                if (null == lchild) {
                    lchild = new Node(i);
                    lchild.parent = this;
                    allNodes.put(lchild, lchild);
                } else {
                    lchild.addNode(i, allNodes);
                }
            }
        }

        @Override
        public boolean equals(Object obj) {
            return ((Node) obj).value == value;
        }

        @Override
        public int hashCode() {
            return value;
        }

        @Override
        public String toString() {
            return String.valueOf(value);
        }
    }
}

答案 6 :(得分:0)

  1. 像我们在Q56中所做的那样找到最少的共同祖先(LCA)。见both approaches to find LCA。我更喜欢第一种方法,因为它存储了每个节点的路径,我们可以使用它来查找距离b / w节点到LCA
  2. 现在计算路径1和路径2中的节点数。总的distnace / vertices将是(Path 1 Nodes -1)+(Path2 Nodes -1)