The nearest common ancestor of a binary tree (two ideas) - interview questions

Idea 1: First assume that the tree is a binary search tree

First of all, let's explain what a binary search tree is:
in a binary search tree, for each node, the value in its left subtree is smaller than him, and the value in the right subtree is larger than him . So an in-order traversal of a binary search tree is an ordered set of data.
insert image description here

For the tree above, assume that the most recent common ancestor of pq is required.
Then it has the following situations:
insert image description here
insert image description here
For ordinary binary trees, there are nothing more than these situations: pq are all on the left, pq are all on the right, pq is one left and one right, and one of pq is the root node.
Therefore, we recursively go to the left subtree and the right subtree to find the common ancestor of the pq node. If it is found, it will return the node, and if it is not found, it will return empty.

insert image description hereinsert image description here

insert image description here

According to the above ideas, we can easily write the code

public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
    
    
    if(root == null) return null;

    // p 为当前树的根节点
    if(p == root) return p;
    // q 为当前树的根节点
    if(q == root) return q;
    
    // 去左子树中找
    TreeNode left = lowestCommonAncestor(root.left,p,q);
    // 去右子树中找
    TreeNode right = lowestCommonAncestor(root.right,p,q);

    // 左边右边都找到了
    if(left != null && right != null) {
    
    
        return root;
    }
    // 左边找到了,右边没找到
    if(left != null) {
    
    
        return left;
    }
    if(right != null) {
    
    
        return right;
    }
    return null;
}

Idea 2: Assume that the tree is represented by children's parents

Each node will save the address of its parent node, which can be searched online layer by layer until it finds the first intersection of the two linked lists, which is their common ancestor.

For a common binary tree, it can only be searched down layer by layer, not up, so the path of two nodes should be reserved until the last identical node of the two paths. Here we use a stack to keep the path of two nodes.
insert image description here
The elements in the stack with more elements are popped first, and then the two stacks are popped together until the nodes to be popped are equal, which is their nearest common ancestor.
insert image description here
So the biggest difficulty here is the storage path.

Here, the stack is used to store the path. When a node is traversed, the node is put into the stack, and then the left and right trees of the node are searched recursively. If it is found, the path is retained, and if it is not found, it is popped up.
Suppose to find p in the figure below:
insert image description here
first put the root node on the stack, recursively search the left subtree of the root node, if not found, pop it up and search in the right subtree.
insert image description here

When root goes to 6, it is found that the left and right sides of the node are empty, indicating that the target node is not found in the subtree, 6 is popped up, and the search continues in the right subtree of 5.
insert image description here
Similarly, it cannot be found in the right subtree of 5, and it will pop up until it goes to the right subtree of 3 to find it, and it comes to 1 and finds it.
insert image description here

// 用于找节点的路径
public boolean getPath(TreeNode root, TreeNode node, Stack<TreeNode> stack) {
    
    
    if(root == null || node == null) {
    
    
        return false;
    }
    // 将当前节点放入栈中
    stack.push(root);
    
    if(root.val == node.val) {
    
    
        return true;// 找到了
    }
    // 当前节点没找到,去左子树找
    boolean flag = getPath(root.left,node,stack);
    // 左子树中找到了,直接返回
    if(flag) {
    
    
        return true;
    }
    // 左子树没找到,去右子树找
    flag = getPath(root.right,node,stack);
    // 右子树中找到了,直接返回
    if(flag) {
    
    
        return true;
    }
    
    // 左右子树都没找到,弹出节点
    stack.pop();
    return false;

}
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
    
    
    if(root == null) {
    
    
        return null;
    }
    Stack<TreeNode> stackp = new Stack<>();
    Stack<TreeNode> stackq = new Stack<>();

    // 分别得到  p q 的路径
    getPath(root,p,stackp);
    getPath(root,q,stackq);

    int sizep = stackp.size();
    int sizeq = stackq.size();

    if(sizep > sizeq) {
    
    
        int size = sizep - sizeq;
        // 弹出元素直至两栈中元素个数相等
        while(size > 0) {
    
    
            stackp.pop();
            size--;
        }
    }else {
    
    
        int size = sizeq - sizep;
        // 弹出元素直至两栈中元素个数相等
        while(size > 0) {
    
    
            stackq.pop();
            size--;
        }
    }

    // 一起弹出,直到找到第一个相同的元素
    while(!stackp.isEmpty() && !stackq.isEmpty()) {
    
    
        if(stackp.peek() == stackq.peek()) {
    
    
        	// 找到了,就返回该节点
            return stackq.pop();
        }else {
    
    
            stackp.pop();
            stackq.pop();
        }
    }
    // 没找到,返回 null
    return null;
}

Guess you like

Origin blog.csdn.net/qq_45792749/article/details/123938092