Repository navigation
Add solution for the "Lowest Common Ancestor of a Binary Search Tree" problem with unit tests. - #26
Conversation
… problem with unit tests.
There was a problem hiding this comment.
Pull Request Overview
This PR implements a solution for the LeetCode problem 235 "Lowest Common Ancestor of a Binary Search Tree" along with comprehensive unit tests. The solution leverages the properties of Binary Search Trees to efficiently find the lowest common ancestor of two nodes.
- Adds a recursive solution that uses BST properties to traverse only the necessary path
- Includes comprehensive test coverage with three test cases covering different scenarios
- Provides time and space complexity analysis in code comments
Reviewed Changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 6 comments.
| File | Description |
|---|---|
| src/main/java/com/leetcode/easy/LowestCommonAncestorOfABinarySearchTree235.java | Implements the main solution using recursive BST traversal |
| src/test/java/com/leetcode/easy/LowestCommonAncestorOfABinarySearchTree235Test.java | Provides unit tests covering edge cases and example scenarios |
| src/LowestCommonAncestorOfaBinarySearchTree235.java | Empty file that should be removed |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
| TreeNode p = new TreeNode(2); | ||
| TreeNode q = new TreeNode(8); | ||
| TreeNode result = solution.lowestCommonAncestor(root, p, q); | ||
| assert result.val == 6; |
There was a problem hiding this comment.
Use JUnit assertions instead of Java assert statements. Replace with assertEquals(6, result.val) for better test failure messages and IDE integration.
| TreeNode p = new TreeNode(2); | ||
| TreeNode q = new TreeNode(4); | ||
| TreeNode result = solution.lowestCommonAncestor(root, p, q); | ||
| assert result.val == 2; |
There was a problem hiding this comment.
Use JUnit assertions instead of Java assert statements. Replace with assertEquals(2, result.val) for better test failure messages and IDE integration.
| TreeNode p = new TreeNode(2); | ||
| TreeNode q = new TreeNode(1); | ||
| TreeNode result = solution.lowestCommonAncestor(root, p, q); | ||
| assert result.val == 2; |
There was a problem hiding this comment.
Use JUnit assertions instead of Java assert statements. Replace with assertEquals(2, result.val) for better test failure messages and IDE integration.
| TreeNode root = new TreeNode(6, | ||
| new TreeNode(2, new TreeNode(0), new TreeNode(4, new TreeNode(3), new TreeNode(5))), | ||
| new TreeNode(8, new TreeNode(7), new TreeNode(9))); | ||
| TreeNode p = new TreeNode(2); | ||
| TreeNode q = new TreeNode(8); | ||
| TreeNode result = solution.lowestCommonAncestor(root, p, q); | ||
| assert result.val == 6; | ||
| } | ||
|
|
||
| @Test | ||
| void testLowestCommonAncestor_Example2() { | ||
| TreeNode root = new TreeNode(6, | ||
| new TreeNode(2, new TreeNode(0), new TreeNode(4, new TreeNode(3), new TreeNode(5))), | ||
| new TreeNode(8, new TreeNode(7), new TreeNode(9))); | ||
| TreeNode p = new TreeNode(2); | ||
| TreeNode q = new TreeNode(4); | ||
| TreeNode result = solution.lowestCommonAncestor(root, p, q); | ||
| assert result.val == 2; | ||
| } | ||
|
|
||
| @Test | ||
| void testLowestCommonAncestor_Example3() { | ||
| TreeNode root = new TreeNode(2, new TreeNode(1), null); | ||
| TreeNode p = new TreeNode(2); | ||
| TreeNode q = new TreeNode(1); |
There was a problem hiding this comment.
The test creates new TreeNode instances with only values, but the algorithm needs to work with actual nodes from the tree. The p and q nodes should reference the existing nodes in the tree structure, not new instances with the same values.
| TreeNode root = new TreeNode(6, | |
| new TreeNode(2, new TreeNode(0), new TreeNode(4, new TreeNode(3), new TreeNode(5))), | |
| new TreeNode(8, new TreeNode(7), new TreeNode(9))); | |
| TreeNode p = new TreeNode(2); | |
| TreeNode q = new TreeNode(8); | |
| TreeNode result = solution.lowestCommonAncestor(root, p, q); | |
| assert result.val == 6; | |
| } | |
| @Test | |
| void testLowestCommonAncestor_Example2() { | |
| TreeNode root = new TreeNode(6, | |
| new TreeNode(2, new TreeNode(0), new TreeNode(4, new TreeNode(3), new TreeNode(5))), | |
| new TreeNode(8, new TreeNode(7), new TreeNode(9))); | |
| TreeNode p = new TreeNode(2); | |
| TreeNode q = new TreeNode(4); | |
| TreeNode result = solution.lowestCommonAncestor(root, p, q); | |
| assert result.val == 2; | |
| } | |
| @Test | |
| void testLowestCommonAncestor_Example3() { | |
| TreeNode root = new TreeNode(2, new TreeNode(1), null); | |
| TreeNode p = new TreeNode(2); | |
| TreeNode q = new TreeNode(1); | |
| TreeNode node0 = new TreeNode(0); | |
| TreeNode node3 = new TreeNode(3); | |
| TreeNode node5 = new TreeNode(5); | |
| TreeNode node4 = new TreeNode(4, node3, node5); | |
| TreeNode node2 = new TreeNode(2, node0, node4); | |
| TreeNode node7 = new TreeNode(7); | |
| TreeNode node9 = new TreeNode(9); | |
| TreeNode node8 = new TreeNode(8, node7, node9); | |
| TreeNode root = new TreeNode(6, node2, node8); | |
| TreeNode p = node2; | |
| TreeNode q = node8; | |
| TreeNode result = solution.lowestCommonAncestor(root, p, q); | |
| assert result.val == 6; | |
| } | |
| @Test | |
| void testLowestCommonAncestor_Example2() { | |
| TreeNode node0 = new TreeNode(0); | |
| TreeNode node3 = new TreeNode(3); | |
| TreeNode node5 = new TreeNode(5); | |
| TreeNode node4 = new TreeNode(4, node3, node5); | |
| TreeNode node2 = new TreeNode(2, node0, node4); | |
| TreeNode node7 = new TreeNode(7); | |
| TreeNode node9 = new TreeNode(9); | |
| TreeNode node8 = new TreeNode(8, node7, node9); | |
| TreeNode root = new TreeNode(6, node2, node8); | |
| TreeNode p = node2; | |
| TreeNode q = node4; | |
| TreeNode result = solution.lowestCommonAncestor(root, p, q); | |
| assert result.val == 2; | |
| } | |
| @Test | |
| void testLowestCommonAncestor_Example3() { | |
| TreeNode node1 = new TreeNode(1); | |
| TreeNode root = new TreeNode(2, node1, null); | |
| TreeNode p = root; | |
| TreeNode q = node1; |
| TreeNode p = new TreeNode(2); | ||
| TreeNode q = new TreeNode(4); |
There was a problem hiding this comment.
The test creates new TreeNode instances with only values, but the algorithm needs to work with actual nodes from the tree. The p and q nodes should reference the existing nodes in the tree structure, not new instances with the same values.
| TreeNode p = new TreeNode(2); | ||
| TreeNode q = new TreeNode(1); |
There was a problem hiding this comment.
The test creates new TreeNode instances with only values, but the algorithm needs to work with actual nodes from the tree. The p and q nodes should reference the existing nodes in the tree structure, not new instances with the same values.
… to use assertEquals and direct node references.
There was a problem hiding this comment.
Pull Request Overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
| public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { | ||
| if (p.val > root.val && q.val > root.val) { | ||
| return this.lowestCommonAncestor(root.right, p, q); | ||
| } | ||
| if (p.val < root.val && q.val < root.val) { | ||
| return this.lowestCommonAncestor(root.left, p, q); | ||
| } | ||
| return root; | ||
| } |
There was a problem hiding this comment.
The method doesn't handle null values for root, p, or q parameters. If any of these are null, accessing .val will throw a NullPointerException. Consider adding null checks at the beginning of the method.
| return this.lowestCommonAncestor(root.right, p, q); | ||
| } | ||
| if (p.val < root.val && q.val < root.val) { | ||
| return this.lowestCommonAncestor(root.left, p, q); |
There was a problem hiding this comment.
Potential NullPointerException if root.right is null. The method should check if root.right exists before making the recursive call.
| return this.lowestCommonAncestor(root.right, p, q); | |
| } | |
| if (p.val < root.val && q.val < root.val) { | |
| return this.lowestCommonAncestor(root.left, p, q); | |
| if (root.right != null) { | |
| return this.lowestCommonAncestor(root.right, p, q); | |
| } else { | |
| return null; | |
| } | |
| } | |
| if (p.val < root.val && q.val < root.val) { | |
| if (root.left != null) { | |
| return this.lowestCommonAncestor(root.left, p, q); | |
| } else { | |
| return null; | |
| } |
| return this.lowestCommonAncestor(root.right, p, q); | ||
| } | ||
| if (p.val < root.val && q.val < root.val) { | ||
| return this.lowestCommonAncestor(root.left, p, q); |
There was a problem hiding this comment.
Potential NullPointerException if root.left is null. The method should check if root.left exists before making the recursive call.
| return this.lowestCommonAncestor(root.right, p, q); | |
| } | |
| if (p.val < root.val && q.val < root.val) { | |
| return this.lowestCommonAncestor(root.left, p, q); | |
| if (root.right != null) { | |
| return this.lowestCommonAncestor(root.right, p, q); | |
| } else { | |
| return null; | |
| } | |
| } | |
| if (p.val < root.val && q.val < root.val) { | |
| if (root.left != null) { | |
| return this.lowestCommonAncestor(root.left, p, q); | |
| } else { | |
| return null; | |
| } |
No description provided.