Skip to content

Commit 602421b

Browse files
committed
up coding excercise lowest common ansertor
1 parent e521d9c commit 602421b

File tree

3 files changed

+118
-1
lines changed

3 files changed

+118
-1
lines changed

src/algorithm/searching/bfs-dfs.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ export class BinarySearchTree {
246246
//1 6 15 170
247247
// InOrder - Left -> Root -> Right: [1, 4, 6, 9, 15, 20, 170]
248248
// PreOrder - Root -> Left -> Right: [9, 4, 1, 6, 20, 15, 170]
249-
// PostOrder - Left -> Right -> Root: [1, 4, 6, 9, 15, 20, 170]
249+
// PostOrder - Left -> Right -> Root: [1, 6, 4, 15, 170, 20, 9]
250250

251251
const tree = new BinarySearchTree();
252252
tree.insert(9);
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import { describe, test, expect } from 'bun:test'
2+
import { lowestCommonAncestor, TreeNode } from './lowest-common-ansertor';
3+
4+
describe('lowestCommonAncestor', () => {
5+
test('should return null for an empty tree', () => {
6+
expect(lowestCommonAncestor(null, null, null)).toBeNull();
7+
});
8+
9+
test('should return the root for the same node', () => {
10+
const root = new TreeNode(1);
11+
expect(lowestCommonAncestor(root, root, root)).toBe(root);
12+
});
13+
14+
test('should return the root as LCA when one node is the root', () => {
15+
const root = new TreeNode(1, new TreeNode(2), new TreeNode(3));
16+
expect(lowestCommonAncestor(root, root, root.left)).toBe(root);
17+
expect(lowestCommonAncestor(root, root, root.right)).toBe(root);
18+
});
19+
20+
test('should return the correct LCA for two nodes on the same level', () => {
21+
const root = new TreeNode(3, new TreeNode(2), new TreeNode(4));
22+
expect(lowestCommonAncestor(root, root.left, root.right)).toBe(root);
23+
});
24+
25+
test('should return the correct LCA for two nodes in the left subtree', () => {
26+
const root = new TreeNode(5,
27+
new TreeNode(3, new TreeNode(2), new TreeNode(4)),
28+
new TreeNode(8)
29+
);
30+
if (root.left && root.left.left && root.left.right) {
31+
expect(lowestCommonAncestor(root, root.left.left, root.left.right)).toBe(root.left);
32+
}
33+
});
34+
35+
test('should return the correct LCA for two nodes in the right subtree', () => {
36+
const root = new TreeNode(5,
37+
new TreeNode(3),
38+
new TreeNode(8, new TreeNode(7), new TreeNode(9))
39+
);
40+
if (root.right && root.right.left && root.right.right) {
41+
expect(lowestCommonAncestor(root, root.right.left, root.right.right)).toBe(root.right);
42+
}
43+
});
44+
45+
test('should return the correct LCA for nodes in different subtrees', () => {
46+
const root = new TreeNode(6,
47+
new TreeNode(2, new TreeNode(0), new TreeNode(4, new TreeNode(3), new TreeNode(5))),
48+
new TreeNode(8, new TreeNode(7), new TreeNode(9))
49+
);
50+
if (root.left && root.right) {
51+
expect(lowestCommonAncestor(root, root.left, root.right)).toBe(root);
52+
if (root.left.left) {
53+
expect(lowestCommonAncestor(root, root.left.left, root.right)).toBe(root);
54+
}
55+
}
56+
});
57+
58+
test('should return the correct LCA for nodes that are not direct children', () => {
59+
const root = new TreeNode(6,
60+
new TreeNode(2, new TreeNode(0), new TreeNode(4, new TreeNode(3), new TreeNode(5))),
61+
new TreeNode(8, new TreeNode(7), new TreeNode(9))
62+
);
63+
if (root.left && root.left.right && root.left.right.left && root.left.right.right) {
64+
expect(lowestCommonAncestor(root, root.left.right.left, root.left.right.right)).toBe(root.left.right);
65+
}
66+
});
67+
});
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/**
2+
* Definition for a binary tree node.
3+
* class TreeNode {
4+
* val: number
5+
* left: TreeNode | null
6+
* right: TreeNode | null
7+
* constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) {
8+
* this.val = (val===undefined ? 0 : val)
9+
* this.left = (left===undefined ? null : left)
10+
* this.right = (right===undefined ? null : right)
11+
* }
12+
* }
13+
*/
14+
15+
export class TreeNode {
16+
val: number
17+
left: TreeNode | null
18+
right: TreeNode | null
19+
constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) {
20+
this.val = (val === undefined ? 0 : val)
21+
this.left = (left === undefined ? null : left)
22+
this.right = (right === undefined ? null : right)
23+
}
24+
}
25+
26+
// Sử dụng trường hợp không đệ quy (độ phức tạp: Time complexity O(h) -> O(n) Trường hợp cây không cân bằng
27+
// Space complexity
28+
export function lowestCommonAncestor(root: TreeNode | null, p: TreeNode | null, q: TreeNode | null): TreeNode | null {
29+
if (!p || !q) return null
30+
31+
let currentNode = root;
32+
while (currentNode != null) {
33+
const currentVal = currentNode.val
34+
if (p.val < currentVal && q.val > currentVal || p.val > currentVal && q.val < currentVal) {
35+
return currentNode
36+
} else if (p.val < currentVal && q.val < currentVal) {
37+
currentNode = currentNode.left
38+
} else if (p.val > currentVal && q.val > currentVal) {
39+
currentNode = currentNode.right
40+
} else if (p.val == currentVal || q.val == currentVal) {
41+
return currentNode
42+
}
43+
}
44+
45+
return root;
46+
};
47+
48+
// console.log("lowestCommonAncestor", lowestCommonAncestor(new TreeNode(2, new TreeNode(1), null), new TreeNode(2), new TreeNode(1)));
49+
// console.log("lowestCommonAncestor", lowestCommonAncestor(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(8))), new TreeNode(2), new TreeNode(8)));
50+
console.log("lowestCommonAncestor", lowestCommonAncestor(new TreeNode(2, new TreeNode(1), new TreeNode(3)), new TreeNode(3), new TreeNode(1)));

0 commit comments

Comments
 (0)