简体   繁体   中英

find lowest common ancestor of two Tree nodes, without reference to root?

class TreeNode {
    TreeNode parent;
    TreeNode left;
    TreeNode right;

    // other data fields omitted - not relevant
}

You are given two nodes p , and q , how do you find the lowest common ancestor? (Assume they both belong in a very large tree)

You do NOT have reference to the root of the tree.

What is the most efficient way to do this? So far, the only idea I have was to

(1) pick a node p (doesn't matter which)

(2) search left sub tree of p, if see q, return p

(3) else search right sub tree of p, if see q, return p

(4) else go one level to parent and search the sub-tree that doesn't contain p, if found q, return parent

(5) else, go up one level again, repeat (4) (search the sub tree that doesnt contain this parent)

This seems extremely inefficient. Any better algorithm?

Do you have extreme restrictions on the amount of RAM you're allowed to use? If not, I'd propose something like this:

visited_nodes = {}    // something like a HashMap, with O(1) insert and retrieval
node1 = p
node2 = q

while True:
    if node1 == null and node2 == null:    // the nodes don't seem to be in same tree
        return null    // or failure or anything like that

    if node1 is not null:
        if node1 in visited_nodes:    // node1 must be lowest common ancestor
            return node1
        else:
            visited_nodes.insert(node1)    // remember that we've seen this node
            node1 = node1.getParent()

    if node2 is not null:
        if node2 in visited_nodes:    // node2 must be lowest common ancestor
            return node2
        else:
            visited_nodes.insert(node2)    // remember that we've seen this node
            node2 = node2.getParent()

The intuitive idea is as follows. We start at both nodes at the same time. In every iteration of the loop, we take one step up from both of the nodes. Whenever we see a node, we put it in our map (which should have O(1) insertion and retrievals / checking if it's already in there). When we encounter a node that we've already put in the map, that must be our solution.

This code should never run for more than max(d_p, d_q) iterations, where d_p and d_q denote the depth levels in the tree that p and q are at, respectively. This will especially be a large advantage if both nodes happen to be rather close to the root. It also means that the code even works for an infinite tree (whereas your solution would get stuck in an infinite loop).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM