← Static tasks

236. Lowest Common Ancestor of a Binary Tree

leetcode medium

#csharp#leetcode#medium#recursion#search#tree#two-pointers

Task

Дано бинарное дерево. Найдите наименьший общий предок (LCA) двух заданных узлов в дереве.

Согласно определению LCA на Википедии: "Наименьший общий предок определяется между двумя узлами p и q как наименьший узел в дереве T, который имеет как p, так и q в качестве потомков (где мы допускаем, что узел может быть потомком самого себя)."

Пример

Input: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1

Output: 3

Explanation: The LCA of nodes 5 and 1 is 3.

C# solution

matched/original
public class Solution {
    private TreeNode ans;
    public Solution() {
        this.ans = null;
    }
    private bool RecurseTree(TreeNode currentNode, TreeNode p, TreeNode q) {
        if (currentNode == null) {
            return false;
        }
        int left = this.RecurseTree(currentNode.left, p, q) ? 1 : 0;
        int right = this.RecurseTree(currentNode.right, p, q) ? 1 : 0;
        int mid = (currentNode == p || currentNode == q) ? 1 : 0;
        if (mid + left + right >= 2) {
            this.ans = currentNode;
        }
        return (mid + left + right > 0);
    }
    public TreeNode LowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        this.RecurseTree(root, p, q);
        return this.ans;
    }
}

C++ solution

auto-draft, review before submit
#include <bits/stdc++.h>
using namespace std;

// Auto-generated C++ draft from the C# solution. Review containers, LINQ and helper types before submit.
class Solution {
public:
    private TreeNode ans;
    public Solution() {
        this.ans = null;
    }
    private bool RecurseTree(TreeNode currentNode, TreeNode p, TreeNode q) {
        if (currentNode == null) {
            return false;
        }
        int left = this.RecurseTree(currentNode.left, p, q) ? 1 : 0;
        int right = this.RecurseTree(currentNode.right, p, q) ? 1 : 0;
        int mid = (currentNode == p || currentNode == q) ? 1 : 0;
        if (mid + left + right >= 2) {
            this.ans = currentNode;
        }
        return (mid + left + right > 0);
    }
    public TreeNode LowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        this.RecurseTree(root, p, q);
        return this.ans;
    }
}

Java solution

matched/original
class Solution {
    private TreeNode ans;

    public Solution() {
        this.ans = null;
    }

    private boolean recurseTree(TreeNode currentNode, TreeNode p, TreeNode q) {
        if (currentNode == null) {
            return false;
        }

        int left = this.recurseTree(currentNode.left, p, q) ? 1 : 0;
        int right = this.recurseTree(currentNode.right, p, q) ? 1 : 0;
        int mid = (currentNode == p || currentNode == q) ? 1 : 0;

        if (mid + left + right >= 2) {
            this.ans = currentNode;
        }

        return (mid + left + right > 0);
    }

    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        this.recurseTree(root, p, q);
        return this.ans;
    }
}

JavaScript solution

matched/original
class Solution {
    constructor() {
        this.ans = null;
    }

    recurseTree(currentNode, p, q) {
        if (currentNode === null) {
            return false;
        }

        const left = this.recurseTree(currentNode.left, p, q) ? 1 : 0;
        const right = this.recurseTree(currentNode.right, p, q) ? 1 : 0;
        const mid = (currentNode === p || currentNode === q) ? 1 : 0;

        if (mid + left + right >= 2) {
            this.ans = currentNode;
        }

        return (mid + left + right > 0);
    }

    lowestCommonAncestor(root, p, q) {
        this.recurseTree(root, p, q);
        return this.ans;
    }
}

Python solution

matched/original
class Solution:
    def __init__(self):
        self.ans = None

    def recurseTree(self, currentNode, p, q):
        if not currentNode:
            return False

        left = self.recurseTree(currentNode.left, p, q) ? 1 : 0
        right = self.recurseTree(currentNode.right, p, q) ? 1 : 0
        mid = (currentNode == p or currentNode == q) ? 1 : 0

        if mid + left + right >= 2:
            self.ans = currentNode

        return mid + left + right > 0

    def lowestCommonAncestor(self, root, p, q):
        self.recurseTree(root, p, q)
        return self.ans

Go solution

matched/original
type TreeNode struct {
    Val   int
    Left  *TreeNode
    Right *TreeNode
}

type Solution struct {
    ans *TreeNode
}

func Constructor() Solution {
    return Solution{ans: nil}
}

func (this *Solution) recurseTree(currentNode, p, q *TreeNode) bool {
    if currentNode == nil {
        return false
    }

    left := 0
    if this.recurseTree(currentNode.Left, p, q) {
        left = 1
    }

    right := 0
    if this.recurseTree(currentNode.Right, p, q) {
        right = 1
    }

    mid := 0
    if currentNode == p || currentNode == q {
        mid = 1
    }

    if mid+left+right >= 2 {
        this.ans = currentNode
    }

    return mid+left+right > 0
}

func (this *Solution) LowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
    this.recurseTree(root, p, q)
    return this.ans
}

Explanation

Algorithm

Начало обхода дерева с корня: Начните обход дерева с корневого узла. Если текущий узел является одним из узлов p или q, установите переменную mid в значение True и продолжите поиск другого узла в левой и правой ветвях.

Проверка поддеревьев: Выполните рекурсивный обход левой и правой ветвей дерева. Если какая-либо из ветвей (левая или правая) возвращает True, это означает, что один из двух узлов найден ниже по дереву.

Определение LCA: Если в любой момент обхода дерева две из трех переменных (left, right или mid) становятся True, это означает, что найден наименьший общий предок (LCA) для узлов p и q.

😎