The sword refers to Offer68-II. The nearest common ancestor of the binary tree

  • Topic: Sword refers to Offer68-II. The nearest common ancestor of
    binary tree Given a binary tree and two target nodes p, q, find the nearest common ancestor of p, q;
    and refers to Offer68-I. The nearest common ancestor of binary search tree Compared with ancestors , ordering cannot be used, so we can only search to find p and q, then find the nearest common ancestor, and then return to the root layer by layer;

  • Ideas:
    1. dfs: Time O(n): Traverse all nodes, the only node that does not need to be searched is the descendants of p and q, because our goal is to find the ancestors of p and q. As for the descendants of p and q, it doesn’t matter what kind of descendants they look like. , So if you find p or q, you go back directly to the upper level without recursively left and right children. The space is O(n): the worst case is when it degenerates to a singly linked list, the recursion depth is n
    ①In general, we must first find p, q, to ​​find the ancestors back, so it must be a post-order traversal;
    ②The return value of the recursive function: you need to use bool to indicate whether the nearest common ancestor is found, and only p and q are from the left and right subtrees to record res, so this way of writing It is not possible to include the case where p itself is an ancestor of q or q is an ancestor of p; if you have to write this way, since only one of p or q will be encountered in this case, you can only set a global variable for flags This situation

//不能覆盖p,q其中一个是另一个的祖先的情况
class Solution {
    
    
public:
    TreeNode* res;
    bool dfs(TreeNode* root, TreeNode* p, TreeNode* q) {
    
    
        if (!root) return false;
        if (root == p || root == q) return true;//如果非要这么写

        bool l = dfs(root->left, p, q);
        bool r = dfs(root->right, p, q);
        if (l && r) {
    
    //找到了最近公共祖先
            res = root;//记录下来
            return true;
        }
        else if (l || r) return true;//其中一棵子树找到了p或q,往上层传递
        else return false;//两棵废物子树,都找不到p,q
    }
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
    
    
        dfs(root, p, q);

        return res;
    }
};

//强行这么写,太麻烦了
class Solution {
    
    
public:
    TreeNode* res, *res2;//true对应res,false对应res2
    bool flag;//true表示p,q分别来自左右子树,false表示p,q其中一个是另一个的祖先这种情况
    bool dfs(TreeNode* root, TreeNode* p, TreeNode* q) {
    
    
        if (!root) return false;
        if (root == p || root == q) {
    
    
            res2 = root;
            return true;
        }

        bool l = dfs(root->left, p, q);
        bool r = dfs(root->right, p, q);
        if (l && r) {
    
    //找到了最近公共祖先
            flag = true;
            res = root;//记录下来
            return true;
        }
        else if (l || r) return true;//其中一棵子树找到了p或q,往上层传递
        else return false;//两棵废物子树,都找不到p,q
    }
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
    
    
        flag = false;
        dfs(root, p, q);
        if (flag == true) return res; 
        else return res2;
        
    }
};

Therefore, try to use TreeNode* as the return value, return empty to indicate that the current subtree is empty, or the current subtree cannot find the target p or q; return non-empty to indicate that the current subtree has found the target p or q: including itself root is p or q, and the left and right subtrees found p or q;
③In the process of backtracking, the entire binary tree must be traversed. Even if the result has been found, other nodes must be traversed, because the return value of the recursive function is used for logic deal with:

//遍历整棵树
auto l = dfs(root->left);
auto r = dfs(root->right);
使用l和r作逻辑处理,

//遍历某条边
if (dfs(root->left)) return ...
if (dfs(root->right)) return ...

④ When l and r are both non-empty (node ​​7 in the figure below), it is easy to understand, indicating that each of the left and right subtrees has found a target; if one of them is empty (nodes 6, 10, 8), the other should be returned, yes Because you have to pass p and q up layer by layer (node ​​6), or find the nearest common ancestor, pass the ancestor up layer by layer (nodes 10, 8);
Insert picture description here

class Solution {
    
    
public:
    //返回nullptr表示:当前节点为空,或当前子树找不到p或q这两个目标节点
    //返回非空,说明当前节点就是目标节点,或当前子树找到了目标节点,或目标节点的祖先(甚至祖先的祖先。。一直传回根节点)
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
    
    
        if (!root || root == p || root == q) return root;//本身root为空 或 root自己就是目标节点
        
        //否则就要尝试去自己的左右子树中找p,q
        auto l = lowestCommonAncestor(root->left, p, q);
        auto r = lowestCommonAncestor(root->right, p, q);
        if (l == nullptr && r == nullptr) return nullptr;//说明左右子树都是废物
        else if (l == nullptr) return r;//左子树找到了p或q:此时的r可能直接是p,q,或pq的祖先,或祖先的祖先。。。一直往上传
        else if (r == nullptr) return l;//右子树找到了p或q,同上
        else return root;//左右子树都找到了(各找到一个p,q),说明当前节点就是最近公共祖先,随后在往根回退的途中,肯定只能进入两个else if分支,因为已经找到最近公共祖先了,其它子树必定return nullptr,就这样一路返回根节点
       
    }
};
  • Summary: There
    are a lot of details and need to be brushed

Guess you like

Origin blog.csdn.net/jiuri1005/article/details/114500409