[Likou] The nearest common ancestor of the binary tree


problem solving ideas

topic link

  1. First of all, we need to understand what is the nearest common ancestor (LCA). In a binary tree, if a node r is an ancestor of p and q, then both p and q are in a subtree of r. If r is the closest common ancestor of p and q, then r has a greater depth than other ancestor nodes, that is, r is closest to p and q. For example, in the binary tree in the figure below, the LCA of nodes 4 and 7 of instance 1 is 2, and the LCA of nodes 5 and 4 of instance 2 is 5 (note that it can also be an ancestor node).

insert image description here
insert image description here

  1. Second, we need to know how to find the path from the root node to the target node. Here we use a recursive method, that is, we start from the root node, visit the left and right child nodes in turn, and judge whether the current node is equal to the target node or whether its left and right subtrees contain the target node. If yes, push the current node into a stack and return true; if not, pop the current node and return false. This way, when the recursion ends, we have a path from the root node to the target node.

  2. Finally, we need to know how to use two paths to find the LCA. Here we use a simple idea,It is to compare whether the top elements of the two stacks are the same. If they are the same, it means that the LCA has been found; if they are not the same, it means that the LCA has not been found, and the top element of the stack needs to be popped. However, we need to ensure that the two stacks are the same size before comparing, since p and q may be at different depths. So we need to pop the redundant nodes on the longer path. For example, in the binary tree in the figure below, the paths from the root node to nodes 7 and 0 are [3,5,2,7] and [3,4,0] respectively. We first adjust the two stacks to the same size, and then compare whether the top elements of the two stacks are the same. If it is found that they are not the same, the two top elements of the stack are popped up, and the next top element of the stack is compared. If the same is found, it means that the LCA is found, that is, 3.

insert image description here

code example

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
    
    
public:
    // 定义一个函数,用于从根节点到目标节点的路径,并将路径上的节点压入栈中
    bool getPath(TreeNode* root ,TreeNode* x,stack<TreeNode*>& path)
    {
    
    
        if(root== nullptr) // 如果根节点为空,返回false
            return false;
        path.push(root); // 将根节点压入栈中
        if(root == x) // 如果根节点就是目标节点,返回true
            return true;
        if(getPath(root->left,x,path)) // 如果左子树中存在目标节点,返回true
            return true;
        if(getPath(root->right,x,path)) // 如果右子树中存在目标节点,返回true
            return true;
        
        path.pop(); // 如果左右子树都不存在目标节点,将根节点弹出栈,返回false
        return false;
    }
    // 定义一个函数,用于求解二叉树的最近公共祖先
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
    
    
        stack<TreeNode* > pPath,qPath; // 定义两个栈,分别存储从根节点到p和q的路径
        getPath(root,p,pPath); // 调用getPath函数,求出从根节点到p的路径
        getPath(root,q,qPath); // 调用getPath函数,求出从根节点到q的路径

        while(pPath.size() != qPath.size()) // 由于p和q可能在不同的深度,所以需要将两个栈的大小调整为相同
        {
    
    
            if(pPath.size() > qPath.size()) // 如果p的路径较长,弹出多余的节点
                pPath.pop();
            else // 如果q的路径较长,弹出多余的节点
                qPath.pop();
        }

        while(pPath.top() != qPath.top()) // 当两个栈顶元素不相同时,说明还没有找到最近公共祖先,继续弹出节点
        {
    
    
            pPath.pop();
            qPath.pop();
        }

        return pPath.top(); // 当两个栈顶元素相同时,说明找到了最近公共祖先,返回该节点


    }
};

DFS: depth-first search algorithm. This is an algorithm for traversing or searching a tree or graph data structure, starting at the root node (choose any node as the root in the case of a graph) and exploring as deeply as possible along each branch until it encounters a to the cul-de-sac, then backtrack. Such algorithms usually require additional memory, usually a stack, to record the nodes found along a given branch for use when backtracking.

Guess you like

Origin blog.csdn.net/weixin_62676865/article/details/130410987