From c401e280445a61dd5ccba513bc492efaff5fb465 Mon Sep 17 00:00:00 2001 From: Nishant Kaushal <101548649+nishant0708@users.noreply.github.com> Date: Tue, 11 Jun 2024 01:57:04 +0530 Subject: [PATCH] added Q235-236 --- ...t-common-Ancestor-of-binary-search-tree.md | 165 ++++++++++++++++++ ...Lowest-Common-Ancestor-of-a-Binary-Tree.md | 146 ++++++++++++++++ 2 files changed, 311 insertions(+) create mode 100644 dsa-solutions/lc-solutions/0200-0299/0235-lowest-common-Ancestor-of-binary-search-tree.md create mode 100644 dsa-solutions/lc-solutions/0200-0299/0236-Lowest-Common-Ancestor-of-a-Binary-Tree.md diff --git a/dsa-solutions/lc-solutions/0200-0299/0235-lowest-common-Ancestor-of-binary-search-tree.md b/dsa-solutions/lc-solutions/0200-0299/0235-lowest-common-Ancestor-of-binary-search-tree.md new file mode 100644 index 000000000..a83c28717 --- /dev/null +++ b/dsa-solutions/lc-solutions/0200-0299/0235-lowest-common-Ancestor-of-binary-search-tree.md @@ -0,0 +1,165 @@ +--- +id: lowest-common-ancestor-of-a-binary-search-tree. +title: Lowest Common Ancestor of a Binary Search Tree. +sidebar_label: 235-Lowest-Common-Ancestor-of-a-Binary-Search-Tree +tags: +- Binary Search Tree +- Tree +- Depth-First Search +- Binary Tree +description: "Given a binary search tree (BST), find the lowest common ancestor (LCA) node of two given nodes in the BST." +--- + +## Problem + +Given a binary search tree (BST), find the lowest common ancestor (LCA) node of two given nodes in the BST. + +According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes p and q as the lowest node in T that has both p and q as descendants (where we allow a node to be a descendant of itself).” + +### Examples + +**Example 1:** + +![image](https://assets.leetcode.com/uploads/2018/12/14/binarysearchtree_improved.png) + +**Input:** `root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8` +**Output:** `6` +**Explanation:** The LCA of nodes 2 and 8 is 6. + +**Example 2:** + +![image](https://assets.leetcode.com/uploads/2018/12/14/binarysearchtree_improved.png) + +**Input:** `root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4` +**Output:** `2` +**Explanation:** The LCA of nodes 2 and 4 is 2, since a node can be a descendant of itself according to the LCA definition. + +**Example 3:** + +**Input:** `root = [2,1], p = 2, q = 1` +**Output:** `2` + +### Constraints + +- The number of nodes in the tree is in the range `[2, 10^5]`. +- `-10^9 <= Node.val <= 10^9` +- All `Node.val` are unique. +- `p != q` +- `p` and `q` will exist in the BST. + +--- + +## Approach + +To find the lowest common ancestor in a Binary Search Tree (BST), we can utilize the properties of the BST. The left subtree of a node contains only nodes with values less than the node's value, and the right subtree contains only nodes with values greater than the node's value. + +### Steps: + +1. **Start from the Root:** Begin the search from the root node of the BST. +2. **Value Comparison:** + - If both `p` and `q` are smaller than the current node's value, move to the left child. + - If both `p` and `q` are greater than the current node's value, move to the right child. + - If `p` and `q` lie on either side of the current node, or one of them is the current node, then the current node is their LCA. + +### Solution + +#### Java + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +class Solution { + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + while (root != null) { + // If both p and q are lesser than root, LCA must be in the left subtree + if (p.val < root.val && q.val < root.val) { + root = root.left; + } + // If both p and q are greater than root, LCA must be in the right subtree + else if (p.val > root.val && q.val > root.val) { + root = root.right; + } + // If p and q lie on either side of root, or one of them is the root, then root is the LCA + else { + return root; + } + } + return null; + } +} +``` +#### CPP +```cpp +/** + * 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: + TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) { + while (root != nullptr) { + // If both p and q are lesser than root, LCA must be in the left subtree + if (p->val < root->val && q->val < root->val) { + root = root->left; + } + // If both p and q are greater than root, LCA must be in the right subtree + else if (p->val > root->val && q->val > root->val) { + root = root->right; + } + // If p and q lie on either side of root, or one of them is the root, then root is the LCA + else { + return root; + } + } + return nullptr; + } +}; +``` +### Python +```python +# Definition for a binary tree node. +class TreeNode: + def __init__(self, x): + self.val = x + self.left = None + self.right = None + +class Solution: + def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode': + while root: + # If both p and q are lesser than root, LCA must be in the left subtree + if p.val < root.val and q.val < root.val: + root = root.left + # If both p and q are greater than root, LCA must be in the right subtree + elif p.val > root.val and q.val > root.val: + root = root.right + # If p and q lie on either side of root, or one of them is the root, then root is the LCA + else: + return root + return None +``` + +### Complexity Analysis +#### Time Complexity: O(h) + +**Reason**: The algorithm may traverse the height h of the tree. In the worst case, this is O(log n) for a balanced BST and O(n) for a skewed BST. +Space Complexity: O(1) + +**Reason**: The algorithm uses constant space. +#### References +**LeetCode Problem** : Lowest Common Ancestor of a Binary Search Tree +**Solution Link**: LCA Solution on LeetCode + +**Wikipedia Definition**: Lowest Common Ancestor diff --git a/dsa-solutions/lc-solutions/0200-0299/0236-Lowest-Common-Ancestor-of-a-Binary-Tree.md b/dsa-solutions/lc-solutions/0200-0299/0236-Lowest-Common-Ancestor-of-a-Binary-Tree.md new file mode 100644 index 000000000..51280ffbd --- /dev/null +++ b/dsa-solutions/lc-solutions/0200-0299/0236-Lowest-Common-Ancestor-of-a-Binary-Tree.md @@ -0,0 +1,146 @@ +--- +id: lowest-common-ancestor-of-a-binary-tree +title: Lowest Common Ancestor of a Binary Tree +sidebar_label: 0236-Lowest-Common-Ancestor-of-a-Binary-Tree +tags: +- Tree +- Depth-First Search +- Binary Tree +description: "Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree." +--- + +## Problem + +Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree. + +According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes p and q as the lowest node in T that has both p and q as descendants (where we allow a node to be a descendant of itself).” + +### Examples + +**Example 1:** + +**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. + +**Example 2:** + +**Input:** `root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4` +**Output:** `5` +**Explanation:** The LCA of nodes 5 and 4 is 5, since a node can be a descendant of itself according to the LCA definition. + +**Example 3:** + +**Input:** `root = [1,2], p = 1, q = 2` +**Output:** `1` + +### Constraints + +- The number of nodes in the tree is in the range `[2, 10^5]`. +- `-10^9 <= Node.val <= 10^9` +- All `Node.val` are unique. +- `p != q` +- `p` and `q` will exist in the tree. + +--- + +## Approach + +To find the lowest common ancestor in a binary tree, we can use a recursive depth-first search (DFS) approach. The idea is to traverse the tree starting from the root. If we find either of the nodes `p` or `q`, we return that node. If both nodes are found in different subtrees of a node, then that node is their lowest common ancestor. + +### Steps: + +1. **Base Case:** If the current node is `null` or matches `p` or `q`, return the current node. +2. **Recursive Search:** + - Recursively search the left subtree for `p` and `q`. + - Recursively search the right subtree for `p` and `q`. +3. **Determine LCA:** + - If both left and right recursive calls return non-null, the current node is the LCA. + - If only one of the recursive calls returns non-null, that means both nodes are located in the same subtree, so return the non-null result. + +### Solution + +#### Java + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +class Solution { + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + if (root == null || root == p || root == q) { + return root; + } + TreeNode left = lowestCommonAncestor(root.left, p, q); + TreeNode right = lowestCommonAncestor(root.right, p, q); + if (left != null && right != null) { + return root; + } + return left != null ? left : right; + } +} +``` +### C++ +```cpp +/** + * 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: + TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) { + if (root == nullptr || root == p || root == q) { + return root; + } + TreeNode* left = lowestCommonAncestor(root->left, p, q); + TreeNode* right = lowestCommonAncestor(root->right, p, q); + if (left != nullptr && right != nullptr) { + return root; + } + return left != nullptr ? left : right; + } +}; +``` +### Python +``` +# Definition for a binary tree node. +class TreeNode: + def __init__(self, x): + self.val = x + self.left = None + self.right = None + +class Solution: + def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode': + if not root or 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 +``` +### Complexity Analysis +#### Time Complexity: O(n) + +**Reason:** The algorithm visits each node in the tree once, where n is the number of nodes in the tree. +Space Complexity: O(h) + +**Reason:** The space complexity is determined by the height h of the tree due to the recursion stack. In the worst case, the height of the tree is O(n) for a skewed tree, but O(log n) for a balanced tree. + +### References +**LeetCode Problem:** Lowest Common Ancestor of a Binary Tree + +**Solution Link:** LCA Solution on LeetCode +**Wikipedia Definition:** Lowest Common Ancestor