236. Lowest Common Ancestor of a Binary Tree - cocoder39/coco39_LC GitHub Wiki

236. Lowest Common Ancestor of a Binary Tree

note 2024

class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        return self.findNode(root, p, q)

    # traverse from root and find first node of p or q
    def findNode(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode'):
        if not root:
            return root
        
        if root == p or root == q: # return first node that is p/q
            return root
        
        left = self.findNode(root.left, p, q)
        right = self.findNode(root.right, p, q)
        if left and right: # p and q are in separate sides
            return root
        if left: # both p and q are in left side
            return left # left is first node of p/q
        return right

this can be consolidated to solution below

Notes 2022

class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        if not root:
            return None
        
        # root is candidate of LCA
        # further searching down is unnecessary
        if root == p or root == q:
            return root
        
        left = self.lowestCommonAncestor(root.left, p, q)
        right = self.lowestCommonAncestor(root.right, p, q)
        
        if left and right:
            return root
        return left if left else right

============================================================================ time complexity is O(n) and space complexity is O(h)

TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if (! root) {   
            return nullptr;
        }
        if (root == p || root == q) {  
            return root;
        }
            
        TreeNode* left = lowestCommonAncestor(root->left, p, q);
        TreeNode* right = lowestCommonAncestor(root->right, p, q);
        
        if(left && right) {   
            return root;
        }
        if(! left) {   
            return right;
        }
        return left;
    }

here we ensure p and q are presented in tree. if there is no this precondition, we can take a fewer codes to check if they are present.

class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if (find(root, p, q) != 2) { 
            return nullptr;
        }
        return helper(root, p, q);
    }
private:
    int find(TreeNode* root, TreeNode* p, TreeNode* q) {
        int res = 0;
        stack<TreeNode*> s;
        TreeNode* cur = root;
        while (cur || ! s.empty()) {
            if (cur) {
                res += (cur == p || cur == q);
                s.push(cur);
                cur = cur->left;
            } else {
                TreeNode* node = s.top();
                s.pop();
                cur = node->right;
            }
        }
        return res;
    }
    
    TreeNode* helper(TreeNode* root, TreeNode* p, TreeNode* q) {
        if (! root || root == p || root == q) { //find p or find q or find neither
            return root;
        }
        TreeNode* left = helper(root->left, p, q);
        TreeNode* right = helper(root->right, p, q);
        if (left && right) {
            return root;
        } else if (left) {
            return left;
        } else {
            return right;
        }
    }
};
⚠️ **GitHub.com Fallback** ⚠️