C# Coding Test Course, Lowest Common Ancestor

Hello, coding test applicants! Today we will delve deep into the problem of Lowest Common Ancestor (LCA). This problem is related to tree structures and requires a deep understanding of algorithms and data structures. We will also explore how to solve this problem using C#.

Problem Definition

The problem is to find the lowest common ancestor of two nodes in a given binary tree. Given two nodes A and B, our goal is to find the deepest node that is an ancestor of both A and B.

Example

        For instance, let's assume there is a binary tree as follows. 

              3
             / \
            5   1
           / \ / \
          6  2 0  8
            / \
           7   4

        The lowest common ancestor of nodes 5 and 1 is 3.
        The lowest common ancestor of nodes 5 and 2 is 5.
        The lowest common ancestor of nodes 6 and 4 is 5.
    

Approach to the Problem

  1. Understanding Tree Structure

    First, it is essential to understand the structure of a binary tree. Each node can have at most two children, and it can be divided into a left subtree and a right subtree. You should know how to traverse the tree to find nodes.

  2. Recursive Approach

    One of the main approaches is to search recursively. If the current node is either A or B, return the current node and explore the left and right subtrees to find the other node. If both are found, then the current node is the lowest common ancestor.

  3. Writing Tree Traversal Algorithm

    Now, we need to write the code in C# to implement the algorithm. In this process, we will incorporate recursion to navigate and verify nodes through the code.

C# Code Implementation

        // Definition of binary tree node class
        public class TreeNode {
            public int Value;
            public TreeNode Left;
            public TreeNode Right;

            public TreeNode(int value) {
                Value = value;
                Left = null;
                Right = null;
            }
        }

        public class Solution {
            public TreeNode LowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
                // Base case: If root is null or root is p or q, return root
                if (root == null || root == p || root == q) {
                    return root;
                }

                // Search each node in the left and right subtrees
                TreeNode left = LowestCommonAncestor(root.Left, p, q);
                TreeNode right = LowestCommonAncestor(root.Right, p, q);

                // If p and q are in different subtrees, the current node is LCA
                if (left != null && right != null) {
                    return root;
                }

                // If only one is found, return that node
                return left ?? right;
            }
        }
    

Code Explanation

This code is written to find the lowest common ancestor of two nodes in a given binary tree. Below are the descriptions of the key parts of the code:

  1. TreeNode Class

    This class represents each node in the tree. It stores the value of each node, the left child node, and the right child node.

  2. LowestCommonAncestor Method

    This method is called recursively and checks if the current node is null or if it is p or q. It searches for p and q in the left and right subtrees, and if both are found in different subtrees, it returns the current node.

Complexity Analysis

The time complexity of this algorithm is O(N), where N represents the number of nodes in the tree. It is proportional to the need to traverse all nodes. The space complexity is O(H), where H represents the height of the tree. This corresponds to the depth of the recursion call stack.

Example Execution

        // Example tree creation and finding LCA
        TreeNode root = new TreeNode(3);
        root.Left = new TreeNode(5);
        root.Right = new TreeNode(1);
        root.Left.Left = new TreeNode(6);
        root.Left.Right = new TreeNode(2);
        root.Right.Left = new TreeNode(0);
        root.Right.Right = new TreeNode(8);
        root.Left.Right.Left = new TreeNode(7);
        root.Left.Right.Right = new TreeNode(4);

        Solution solution = new Solution();
        TreeNode p = root.Left; // Node 5
        TreeNode q = root.Left.Right; // Node 2
        TreeNode lca = solution.LowestCommonAncestor(root, p, q);
        Console.WriteLine($"Lowest Common Ancestor: {lca.Value}"); // Outputs 5
    

Conclusion

Today, we explored how to solve the lowest common ancestor problem using C#. This problem serves as a foundation for tackling various algorithmic challenges and requires an understanding of tree structure and recursive thinking. Through practice, I hope you will enhance your coding skills and increase your understanding of C# during this opportunity.

Thank you for visiting the blog! I hope this has been helpful for your coding test preparation.