diff --git a/articles/as-far-from-land-as-possible.md b/articles/as-far-from-land-as-possible.md
new file mode 100644
index 000000000..15382ba80
--- /dev/null
+++ b/articles/as-far-from-land-as-possible.md
@@ -0,0 +1,757 @@
+## 1. Brute Force (BFS)
+
+::tabs-start
+
+```python
+class Solution:
+    def maxDistance(self, grid: list[list[int]]) -> int:
+        N = len(grid)
+        direct = [[0, 1], [0, -1], [1, 0], [-1, 0]]
+
+        def bfs(row, col):
+            q = deque([(row, col)])
+            visit = [[False] * N for _ in range(N)]
+            dist, visit[row][col] = 0, True
+
+            while q:
+                dist += 1
+                for _ in range(len(q)):
+                    r, c = q.popleft()
+                    for dx, dy in direct:
+                        newR, newC = r + dx, c + dy
+                        if min(newR, newC) < 0 or max(newR, newC) >= N or visit[newR][newC]:
+                            continue
+                        if grid[newR][newC] == 1:
+                            return dist
+                        visit[newR][newC] = True
+                        q.append((newR, newC))
+            return -1
+
+        res = -1
+        for r in range(N):
+            for c in range(N):
+                if grid[r][c] == 0:
+                    res = max(res, bfs(r, c))
+                    if res == -1:
+                        return res
+
+        return res
+```
+
+```java
+public class Solution {
+    private static final int[][] direct = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
+
+    public int maxDistance(int[][] grid) {
+        int N = grid.length;
+        int res = -1;
+
+        for (int r = 0; r < N; r++) {
+            for (int c = 0; c < N; c++) {
+                if (grid[r][c] == 0) {
+                    res = Math.max(res, bfs(grid, r, c, N));
+                    if (res == -1) return res;
+                }
+            }
+        }
+        return res;
+    }
+
+    private int bfs(int[][] grid, int row, int col, int N) {
+        Queue<int[]> q = new LinkedList<>();
+        boolean[][] visit = new boolean[N][N];
+        q.offer(new int[]{row, col});
+        visit[row][col] = true;
+        int dist = 0;
+
+        while (!q.isEmpty()) {
+            dist++;
+            for (int i = q.size(); i > 0; i--) {
+                int[] cell = q.poll();
+                int r = cell[0], c = cell[1];
+
+                for (int[] d : direct) {
+                    int newR = r + d[0], newC = c + d[1];
+                    if (newR < 0 || newC < 0 || newR >= N || newC >= N || visit[newR][newC])
+                        continue;
+                    if (grid[newR][newC] == 1)
+                        return dist;
+
+                    visit[newR][newC] = true;
+                    q.offer(new int[]{newR, newC});
+                }
+            }
+        }
+        return -1;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int maxDistance(vector<vector<int>>& grid) {
+        int N = grid.size();
+        int res = -1;
+
+        for (int r = 0; r < N; r++) {
+            for (int c = 0; c < N; c++) {
+                if (grid[r][c] == 0) {
+                    res = max(res, bfs(grid, r, c, N));
+                    if (res == -1) return res;
+                }
+            }
+        }
+        return res;
+    }
+
+private:
+    const int direct[4][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
+
+    int bfs(vector<vector<int>>& grid, int row, int col, int N) {
+        queue<pair<int, int>> q;
+        vector<vector<bool>> visit(N, vector<bool>(N, false));
+        q.push({row, col});
+        visit[row][col] = true;
+        int dist = 0;
+
+        while (!q.empty()) {
+            dist++;
+            for (int i = q.size(); i > 0; i--) {
+                auto [r, c] = q.front();q.pop();
+
+                for (auto& d : direct) {
+                    int newR = r + d[0], newC = c + d[1];
+                    if (newR < 0 || newC < 0 || newR >= N || newC >= N || visit[newR][newC])
+                        continue;
+                    if (grid[newR][newC] == 1)
+                        return dist;
+
+                    visit[newR][newC] = true;
+                    q.push({newR, newC});
+                }
+            }
+        }
+        return -1;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} grid
+     * @return {number}
+     */
+    maxDistance(grid) {
+        const N = grid.length;
+        const direct = [[0, 1], [0, -1], [1, 0], [-1, 0]];
+
+        const bfs = (row, col) => {
+            const q = new Queue([[row, col]]);
+            const visit = Array.from({ length: N }, () => Array(N).fill(false));
+            visit[row][col] = true;
+            let dist = 0;
+
+            while (!q.isEmpty()) {
+                dist++;
+                for (let i = q.size(); i > 0; i--) {
+                    const [r, c] = q.pop();
+                    for (let d = 0; d < 4; d++) {
+                        let newR = r + direct[d][0], newC = c + direct[d][1];
+                        if (newR < 0 || newC < 0 || newR >= N || newC >= N || visit[newR][newC]) 
+                            continue;
+                        if (grid[newR][newC] === 1) 
+                            return dist;
+
+                        visit[newR][newC] = true;
+                        q.push([newR, newC]);
+                    }
+                }
+            }
+            return -1;
+        };
+
+        let res = -1;
+        for (let r = 0; r < N; r++) {
+            for (let c = 0; c < N; c++) {
+                if (grid[r][c] === 0) {
+                    res = Math.max(res, bfs(r, c));
+                    if (res === -1) return res;
+                }
+            }
+        }
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n ^ 4)$
+* Space complexity: $O(n ^ 2)$
+
+---
+
+## 2. Multi Source BFS (Overwriting Input)
+
+::tabs-start
+
+```python
+class Solution:
+    def maxDistance(self, grid: List[List[int]]) -> int:
+        N = len(grid)
+        q = deque()
+        
+        for r in range(N):
+            for c in range(N):
+                if grid[r][c]:
+                    q.append([r, c])
+
+        res = -1
+        direct = [[0, 1], [1, 0], [0, -1], [-1, 0]]
+
+        while q:
+            r, c = q.popleft()
+            res = grid[r][c]
+            
+            for dr, dc in direct:
+                newR, newC = r + dr, c + dc
+                if min(newR, newC) >= 0 and max(newR, newC) < N and grid[newR][newC] == 0:
+                    q.append([newR, newC])
+                    grid[newR][newC] = grid[r][c] + 1
+
+        return res - 1 if res > 1 else -1
+```
+
+```java
+public class Solution {
+    private static final int[][] direct = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
+
+    public int maxDistance(int[][] grid) {
+        int N = grid.length;
+        Queue<int[]> q = new LinkedList<>();
+        for (int r = 0; r < N; r++) {
+            for (int c = 0; c < N; c++) {
+                if (grid[r][c] == 1) {
+                    q.offer(new int[]{r, c});
+                }
+            }
+        }
+
+        int res = -1;
+        while (!q.isEmpty()) {
+            int[] cell = q.poll();
+            int r = cell[0], c = cell[1];
+            res = grid[r][c];
+            for (int d = 0; d < 4; d++) {
+                int newR = r + direct[d][0], newC = c + direct[d][1];
+                if (newR >= 0 && newC >= 0 && newR < N && newC < N && grid[newR][newC] == 0) {
+                    q.offer(new int[]{newR, newC});
+                    grid[newR][newC] = grid[r][c] + 1;
+                }
+            }
+        }
+        return res > 1 ? res - 1 : -1;
+    }
+}
+```
+
+```cpp
+class Solution {
+    const int direct[4][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
+
+public:
+    int maxDistance(vector<vector<int>>& grid) {
+        int N = grid.size();
+        queue<pair<int, int>> q;
+        for (int r = 0; r < N; r++) {
+            for (int c = 0; c < N; c++) {
+                if (grid[r][c] == 1) {
+                    q.push({r, c});
+                }
+            }
+        }
+
+        int res = -1;
+        while (!q.empty()) {
+            auto [r, c] = q.front();q.pop();
+            res = grid[r][c];
+            for (int d = 0; d < 4; d++) {
+                int newR = r + direct[d][0], newC = c + direct[d][1];
+                if (newR >= 0 && newC >= 0 && newR < N && newC < N && grid[newR][newC] == 0) {
+                    q.push({newR, newC});
+                    grid[newR][newC] = grid[r][c] + 1;
+                }
+            }
+        }
+        return res > 1 ? res - 1 : -1;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} grid
+     * @return {number}
+     */
+    maxDistance(grid) {
+        const N = grid.length;
+        const q = new Queue();
+        for (let r = 0; r < N; r++) {
+            for (let c = 0; c < N; c++) {
+                if (grid[r][c] === 1) {
+                    q.push([r, c]);
+                }
+            }
+        }
+
+        let res = -1;
+        const direct = [[0, 1], [0, -1], [1, 0], [-1, 0]];
+        while (!q.isEmpty()) {
+            const [r, c] = q.pop();
+            res = grid[r][c];
+            for (let d = 0; d < 4; d++) {
+                let newR = r + direct[d][0], newC = c + direct[d][1];
+                if (newR >= 0 && newC >= 0 && newR < N && newC < N && grid[newR][newC] === 0) {
+                    q.push([newR, newC]);
+                    grid[newR][newC] = grid[r][c] + 1;
+                }
+            }
+        }
+        return res > 1 ? res - 1 : -1;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n ^ 2)$
+* Space complexity: $O(n ^ 2)$
+
+---
+
+## 3. Multi Source BFS
+
+::tabs-start
+
+```python
+class Solution:
+    def maxDistance(self, grid: List[List[int]]) -> int:
+        N = len(grid)
+        direct = [0, 1, 0, -1, 0]
+        visit = [[False] * N for _ in range(N)]
+        q = deque()
+
+        for r in range(N):
+            for c in range(N):
+                if grid[r][c] == 1:
+                    visit[r][c] = True
+                    q.append((r, c))
+
+        res = 0
+        while q:
+            res += 1
+            for _ in range(len(q)):
+                r, c = q.popleft()
+                for d in range(4):
+                    newR, newC = r + direct[d], c + direct[d + 1]
+                    if 0 <= newR < N and 0 <= newC < N and not visit[newR][newC]:
+                        q.append((newR, newC))
+                        visit[newR][newC] = True
+
+        return res - 1 if res > 1 else -1
+```
+
+```java
+public class Solution {
+    public int maxDistance(int[][] grid) {
+        int N = grid.length;
+        int[] direct = {0, 1, 0, -1, 0};
+        boolean[][] visit = new boolean[N][N];
+        Queue<int[]> q = new LinkedList<>();
+        for (int r = 0; r < N; r++) {
+            for (int c = 0; c < N; c++) {
+                if (grid[r][c] == 1) {
+                    visit[r][c] = true;
+                    q.offer(new int[]{r, c});
+                }
+            }
+        }
+
+        int res = 0;
+        while (!q.isEmpty()) {
+            res++;
+            for (int i = q.size(); i > 0; i--) {
+                int[] cur = q.poll();
+                int r = cur[0], c = cur[1];
+                for (int d = 0; d < 4; d++) {
+                    int newR = r + direct[d], newC = c + direct[d + 1];
+                    if (newR >= 0 && newC >= 0 && newR < N && newC < N && !visit[newR][newC]) {
+                        q.offer(new int[]{newR, newC});
+                        visit[newR][newC] = true;
+                    }
+                }
+            }
+        }
+        return res > 1 ? res - 1 : -1;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int maxDistance(vector<vector<int>>& grid) {
+        int N = grid.size();
+        vector<int> direct = {0, 1, 0, -1, 0};
+        vector<vector<bool>> visit(N, vector<bool>(N, false));
+        queue<pair<int, int>> q;
+        for (int r = 0; r < N; r++) {
+            for (int c = 0; c < N; c++) {
+                if (grid[r][c] == 1) {
+                    visit[r][c] = true;
+                    q.push({r, c});
+                }
+            }
+        }
+
+        int res = 0;
+        while (!q.empty()) {
+            res++;
+            for (int i = q.size(); i > 0; i--) {
+                auto [r, c] = q.front();q.pop();
+                for (int d = 0; d < 4; d++) {
+                    int newR = r + direct[d], newC = c + direct[d + 1];
+                    if (newR >= 0 && newC >= 0 && newR < N && newC < N && !visit[newR][newC]) {
+                        q.push({newR, newC});
+                        visit[newR][newC] = true;
+                    }
+                }
+            }
+        }
+        return res > 1 ? res - 1 : -1;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} grid
+     * @return {number}
+     */
+    maxDistance(grid) {
+        const N = grid.length;
+        const direct = [0, 1, 0, -1, 0];
+        const visit = Array.from({ length: N }, () => Array(N).fill(false));
+        const q = new Queue();
+        for (let r = 0; r < N; r++) {
+            for (let c = 0; c < N; c++) {
+                if (grid[r][c] === 1) {
+                    visit[r][c] = true;
+                    q.push([r, c]);
+                }
+            }
+        }
+
+        let res = 0;
+        while (!q.isEmpty()) {
+            res++;
+            for (let i = q.size(); i > 0; i--) {
+                const [r, c] = q.pop();
+                for (let d = 0; d < 4; d++) {
+                    let newR = r + direct[d], newC = c + direct[d + 1];
+                    if (newR >= 0 && newC >= 0 && newR < N && newC < N && !visit[newR][newC]) {
+                        q.push([newR, newC]);
+                        visit[newR][newC] = true;
+                    }
+                }
+            }
+        }
+        return res > 1 ? res - 1 : -1;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n ^ 2)$
+* Space complexity: $O(n ^ 2)$
+
+---
+
+## 4. Dynamic Programming (Overwrting the Input)
+
+::tabs-start
+
+```python
+class Solution:
+    def maxDistance(self, grid: List[List[int]]) -> int:
+        N, INF = len(grid), 10**6
+
+        for r in range(N):
+            for c in range(N):
+                if grid[r][c] == 1:
+                    continue
+                grid[r][c] = INF
+                if r > 0:
+                    grid[r][c] = min(grid[r][c], grid[r - 1][c] + 1)
+                if c > 0:
+                    grid[r][c] = min(grid[r][c], grid[r][c - 1] + 1)
+
+        res = 0
+        for r in range(N - 1, -1, -1):
+            for c in range(N - 1, -1, -1):
+                if grid[r][c] == 1:
+                    continue
+                if r < N - 1:
+                    grid[r][c] = min(grid[r][c], grid[r + 1][c] + 1)
+                if c < N - 1:
+                    grid[r][c] = min(grid[r][c], grid[r][c + 1] + 1)
+                res = max(res, grid[r][c])
+
+        return res - 1 if res < INF else -1
+```
+
+```java
+public class Solution {
+    public int maxDistance(int[][] grid) {
+        int N = grid.length, INF = 1000000;
+
+        for (int r = 0; r < N; r++) {
+            for (int c = 0; c < N; c++) {
+                if (grid[r][c] == 1) continue;
+                grid[r][c] = INF;
+                if (r > 0) grid[r][c] = Math.min(grid[r][c], grid[r - 1][c] + 1);
+                if (c > 0) grid[r][c] = Math.min(grid[r][c], grid[r][c - 1] + 1);
+            }
+        }
+
+        int res = 0;
+        for (int r = N - 1; r >= 0; r--) {
+            for (int c = N - 1; c >= 0; c--) {
+                if (grid[r][c] == 1) continue;
+                if (r < N - 1) grid[r][c] = Math.min(grid[r][c], grid[r + 1][c] + 1);
+                if (c < N - 1) grid[r][c] = Math.min(grid[r][c], grid[r][c + 1] + 1);
+                res = Math.max(res, grid[r][c]);
+            }
+        }
+
+        return res < INF ? res - 1 : -1;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int maxDistance(vector<vector<int>>& grid) {
+        int N = grid.size(), INF = 1000000;
+
+        for (int r = 0; r < N; r++) {
+            for (int c = 0; c < N; c++) {
+                if (grid[r][c] == 1) continue;
+                grid[r][c] = INF;
+                if (r > 0) grid[r][c] = min(grid[r][c], grid[r - 1][c] + 1);
+                if (c > 0) grid[r][c] = min(grid[r][c], grid[r][c - 1] + 1);
+            }
+        }
+
+        int res = 0;
+        for (int r = N - 1; r >= 0; r--) {
+            for (int c = N - 1; c >= 0; c--) {
+                if (grid[r][c] == 1) continue;
+                if (r < N - 1) grid[r][c] = min(grid[r][c], grid[r + 1][c] + 1);
+                if (c < N - 1) grid[r][c] = min(grid[r][c], grid[r][c + 1] + 1);
+                res = max(res, grid[r][c]);
+            }
+        }
+
+        return res < INF ? res - 1 : -1;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} grid
+     * @return {number}
+     */
+    maxDistance(grid) {
+        const N = grid.length, INF = 1000000;
+
+        for (let r = 0; r < N; r++) {
+            for (let c = 0; c < N; c++) {
+                if (grid[r][c] === 1) continue;
+                grid[r][c] = INF;
+                if (r > 0) grid[r][c] = Math.min(grid[r][c], grid[r - 1][c] + 1);
+                if (c > 0) grid[r][c] = Math.min(grid[r][c], grid[r][c - 1] + 1);
+            }
+        }
+
+        let res = 0;
+        for (let r = N - 1; r >= 0; r--) {
+            for (let c = N - 1; c >= 0; c--) {
+                if (grid[r][c] === 1) continue;
+                if (r < N - 1) grid[r][c] = Math.min(grid[r][c], grid[r + 1][c] + 1);
+                if (c < N - 1) grid[r][c] = Math.min(grid[r][c], grid[r][c + 1] + 1);
+                res = Math.max(res, grid[r][c]);
+            }
+        }
+
+        return res < INF ? res - 1 : -1;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n ^ 2)$
+* Space complexity: $O(1)$ extra space.
+
+---
+
+## 5. Dynamic Programming
+
+::tabs-start
+
+```python
+class Solution:
+    def maxDistance(self, grid: List[List[int]]) -> int:
+        N = len(grid)
+        res, INF = -1, 10**6
+        dp = [[INF] * (N + 2) for _ in range(N + 2)]
+
+        for r in range(1, N + 1):
+            for c in range(1, N + 1):
+                if grid[r - 1][c - 1] == 1:
+                    dp[r][c] = 0
+                else:
+                    dp[r][c] = min(dp[r - 1][c], dp[r][c - 1]) + 1
+
+        for r in range(N, 0, -1):
+            for c in range(N, 0, -1):
+                if grid[r - 1][c - 1] == 0:
+                    dp[r][c] = min(dp[r][c], min(dp[r + 1][c], dp[r][c + 1]) + 1)
+                    res = max(res, dp[r][c])
+
+        return res if res < INF else -1
+```
+
+```java
+public class Solution {
+    public int maxDistance(int[][] grid) {
+        int N = grid.length;
+        int INF = 1000000;
+        int[][] dp = new int[N + 2][N + 2];
+        for (int[] row : dp) {
+            Arrays.fill(row, INF);
+        }
+
+        for (int r = 1; r <= N; r++) {
+            for (int c = 1; c <= N; c++) {
+                if (grid[r - 1][c - 1] == 1) {
+                    dp[r][c] = 0;
+                } else {
+                    dp[r][c] = Math.min(dp[r - 1][c], dp[r][c - 1]) + 1;
+                }
+            }
+        }
+
+        int res = -1;
+        for (int r = N; r > 0; r--) {
+            for (int c = N; c > 0; c--) {
+                if (grid[r - 1][c - 1] == 0) {
+                    dp[r][c] = Math.min(dp[r][c], Math.min(dp[r + 1][c], dp[r][c + 1]) + 1);
+                    res = Math.max(res, dp[r][c]);
+                }
+            }
+        }
+        return res < INF ? res : -1;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int maxDistance(vector<vector<int>>& grid) {
+        int N = grid.size();
+        int INF = 1000000, res = -1;
+        vector<vector<int>> dp(N + 2, vector<int>(N + 2, INF));
+
+        for (int r = 1; r <= N; r++) {
+            for (int c = 1; c <= N; c++) {
+                if (grid[r - 1][c - 1] == 1) {
+                    dp[r][c] = 0;
+                } else {
+                    dp[r][c] = min(dp[r - 1][c], dp[r][c - 1]) + 1;
+                }
+            }
+        }
+
+        for (int r = N; r > 0; r--) {
+            for (int c = N; c > 0; c--) {
+                if (grid[r - 1][c - 1] == 0) {
+                    dp[r][c] = min(dp[r][c], min(dp[r + 1][c], dp[r][c + 1]) + 1);
+                    res = max(res, dp[r][c]);
+                }
+            }
+        }
+        return res < INF ? res : -1;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} grid
+     * @return {number}
+     */
+    maxDistance(grid) {
+        const N = grid.length;
+        const INF = 1000000;
+        let res = -1;
+        let dp = Array.from({ length: N + 2 }, () => Array(N + 2).fill(INF));
+
+        for (let r = 1; r <= N; r++) {
+            for (let c = 1; c <= N; c++) {
+                if (grid[r - 1][c - 1] === 1) {
+                    dp[r][c] = 0;
+                } else {
+                    dp[r][c] = Math.min(dp[r - 1][c], dp[r][c - 1]) + 1;
+                }
+            }
+        }
+
+        for (let r = N; r > 0; r--) {
+            for (let c = N; c > 0; c--) {
+                if (grid[r - 1][c - 1] === 0) {
+                    dp[r][c] = Math.min(dp[r][c], Math.min(dp[r + 1][c], dp[r][c + 1]) + 1);
+                    res = Math.max(res, dp[r][c]);
+                }
+            }
+        }
+        return res < INF ? res : -1;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n ^ 2)$
+* Space complexity: $O(n ^ 2)$
\ No newline at end of file
diff --git a/articles/convert-bst-to-greater-tree.md b/articles/convert-bst-to-greater-tree.md
new file mode 100644
index 000000000..9e01d51be
--- /dev/null
+++ b/articles/convert-bst-to-greater-tree.md
@@ -0,0 +1,643 @@
+## 1. Depth First Search (Two Pass)
+
+::tabs-start
+
+```python
+# Definition for a binary tree node.
+# class TreeNode:
+#     def __init__(self, val=0, left=None, right=None):
+#         self.val = val
+#         self.left = left
+#         self.right = right
+class Solution:
+    def convertBST(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
+        def getSum(node):
+            if not node:
+                return 0
+            return node.val + getSum(node.left) + getSum(node.right)
+
+        totalSum = getSum(root)
+
+        def dfs(node):
+            nonlocal totalSum
+            if not node:
+                return
+
+            dfs(node.left)
+            tmp = node.val
+            node.val = totalSum
+            totalSum -= tmp
+            dfs(node.right)
+
+        dfs(root)
+        return root
+```
+
+```java
+/**
+ * Definition for a binary tree node.
+ * public class TreeNode {
+ *     int val;
+ *     TreeNode left;
+ *     TreeNode right;
+ *     TreeNode() {}
+ *     TreeNode(int val) { this.val = val; }
+ *     TreeNode(int val, TreeNode left, TreeNode right) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+public class Solution {
+    private int totalSum;
+
+    public TreeNode convertBST(TreeNode root) {
+        totalSum = getSum(root);
+        dfs(root);
+        return root;
+    }
+
+    private int getSum(TreeNode node) {
+        if (node == null) return 0;
+        return node.val + getSum(node.left) + getSum(node.right);
+    }
+
+    private void dfs(TreeNode node) {
+        if (node == null) return;
+
+        dfs(node.left);
+        int tmp = node.val;
+        node.val = totalSum;
+        totalSum -= tmp;
+        dfs(node.right);
+    }
+}
+```
+
+```cpp
+/**
+ * Definition for a binary tree node.
+ * struct TreeNode {
+ *     int val;
+ *     TreeNode *left;
+ *     TreeNode *right;
+ *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
+ * };
+ */
+class Solution {
+public:
+    int totalSum;
+
+    TreeNode* convertBST(TreeNode* root) {
+        totalSum = getSum(root);
+        dfs(root);
+        return root;
+    }
+
+private:
+    int getSum(TreeNode* node) {
+        if (!node) return 0;
+        return node->val + getSum(node->left) + getSum(node->right);
+    }
+
+    void dfs(TreeNode* node) {
+        if (!node) return;
+
+        dfs(node->left);
+        int tmp = node->val;
+        node->val = totalSum;
+        totalSum -= tmp;
+        dfs(node->right);
+    }
+};
+```
+
+```javascript
+/**
+ * Definition for a binary tree node.
+ * class TreeNode {
+ *     constructor(val = 0, left = null, right = null) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+class Solution {
+    /**
+     * @param {TreeNode} root
+     * @return {TreeNode}
+     */
+    convertBST(root) {
+        const getSum = (node) => {
+            if (!node) return 0;
+            return node.val + getSum(node.left) + getSum(node.right);
+        };
+
+        let totalSum = getSum(root);
+
+        const dfs = (node) => {
+            if (!node) return;
+
+            dfs(node.left);
+            let tmp = node.val;
+            node.val = totalSum;
+            totalSum -= tmp;
+            dfs(node.right);
+        };
+
+        dfs(root);
+        return root;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(n)$ for recursion stack.
+
+---
+
+## 2. Depth First Search (One Pass)
+
+::tabs-start
+
+```python
+# Definition for a binary tree node.
+# class TreeNode:
+#     def __init__(self, val=0, left=None, right=None):
+#         self.val = val
+#         self.left = left
+#         self.right = right
+class Solution:
+    def convertBST(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
+        curSum = 0
+
+        def dfs(node):
+            nonlocal curSum
+            if not node:
+                return
+
+            dfs(node.right)
+            tmp = node.val
+            node.val += curSum
+            curSum += tmp
+            dfs(node.left)
+
+        dfs(root)
+        return root
+```
+
+```java
+/**
+ * Definition for a binary tree node.
+ * public class TreeNode {
+ *     int val;
+ *     TreeNode left;
+ *     TreeNode right;
+ *     TreeNode() {}
+ *     TreeNode(int val) { this.val = val; }
+ *     TreeNode(int val, TreeNode left, TreeNode right) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+public class Solution {
+    private int curSum = 0;
+
+    public TreeNode convertBST(TreeNode root) {
+        dfs(root);
+        return root;
+    }
+
+    private void dfs(TreeNode node) {
+        if (node == null) return;
+
+        dfs(node.right);
+        int tmp = node.val;
+        node.val += curSum;
+        curSum += tmp;
+        dfs(node.left);
+    }
+}
+```
+
+```cpp
+/**
+ * Definition for a binary tree node.
+ * struct TreeNode {
+ *     int val;
+ *     TreeNode *left;
+ *     TreeNode *right;
+ *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
+ * };
+ */
+class Solution {
+public:
+    int curSum = 0;
+
+    TreeNode* convertBST(TreeNode* root) {
+        dfs(root);
+        return root;
+    }
+
+private:
+    void dfs(TreeNode* node) {
+        if (!node) return;
+
+        dfs(node->right);
+        int tmp = node->val;
+        node->val += curSum;
+        curSum += tmp;
+        dfs(node->left);
+    }
+};
+```
+
+```javascript
+/**
+ * Definition for a binary tree node.
+ * class TreeNode {
+ *     constructor(val = 0, left = null, right = null) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+class Solution {
+    /**
+     * @param {TreeNode} root
+     * @return {TreeNode}
+     */
+    convertBST(root) {
+        let curSum = 0;
+
+        const dfs = (node) => {
+            if (!node) return;
+
+            dfs(node.right);
+            let tmp = node.val;
+            node.val += curSum;
+            curSum += tmp;
+            dfs(node.left);
+        };
+
+        dfs(root);
+        return root;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(n)$ for recursion stack.
+
+---
+
+## 3. Iterative DFS
+
+::tabs-start
+
+```python
+# Definition for a binary tree node.
+# class TreeNode:
+#     def __init__(self, val=0, left=None, right=None):
+#         self.val = val
+#         self.left = left
+#         self.right = right
+class Solution:
+    def convertBST(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
+        curSum = 0
+        stack = []
+        node = root
+
+        while stack or node:
+            while node:
+                stack.append(node)
+                node = node.right
+            
+            node = stack.pop()
+            curSum += node.val
+            node.val = curSum
+            node = node.left
+
+        return root
+```
+
+```java
+/**
+ * Definition for a binary tree node.
+ * public class TreeNode {
+ *     int val;
+ *     TreeNode left;
+ *     TreeNode right;
+ *     TreeNode() {}
+ *     TreeNode(int val) { this.val = val; }
+ *     TreeNode(int val, TreeNode left, TreeNode right) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+public class Solution {
+    public TreeNode convertBST(TreeNode root) {
+        int curSum = 0;
+        Stack<TreeNode> stack = new Stack<>();
+        TreeNode node = root;
+
+        while (!stack.isEmpty() || node != null) {
+            while (node != null) {
+                stack.push(node);
+                node = node.right;
+            }
+
+            node = stack.pop();
+            curSum += node.val;
+            node.val = curSum;
+            node = node.left;
+        }
+        return root;
+    }
+}
+```
+
+```cpp
+/**
+ * Definition for a binary tree node.
+ * struct TreeNode {
+ *     int val;
+ *     TreeNode *left;
+ *     TreeNode *right;
+ *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
+ * };
+ */
+class Solution {
+public:
+    TreeNode* convertBST(TreeNode* root) {
+        int curSum = 0;
+        stack<TreeNode*> st;
+        TreeNode* node = root;
+
+        while (!st.empty() || node) {
+            while (node) {
+                st.push(node);
+                node = node->right;
+            }
+
+            node = st.top(); st.pop();
+            curSum += node->val;
+            node->val = curSum;
+            node = node->left;
+        }
+        return root;
+    }
+};
+```
+
+```javascript
+/**
+ * Definition for a binary tree node.
+ * class TreeNode {
+ *     constructor(val = 0, left = null, right = null) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+class Solution {
+    /**
+     * @param {TreeNode} root
+     * @return {TreeNode}
+     */
+    convertBST(root) {
+        let curSum = 0;
+        const stack = [];
+        let node = root;
+
+        while (stack.length || node) {
+            while (node) {
+                stack.push(node);
+                node = node.right;
+            }
+
+            node = stack.pop();
+            curSum += node.val;
+            node.val = curSum;
+            node = node.left;
+        }
+        return root;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(n)$
+
+---
+
+## 4. Morris Traversal
+
+::tabs-start
+
+```python
+# Definition for a binary tree node.
+# class TreeNode:
+#     def __init__(self, val=0, left=None, right=None):
+#         self.val = val
+#         self.left = left
+#         self.right = right
+class Solution:
+    def convertBST(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
+        curSum = 0
+        cur = root
+
+        while cur:
+            if cur.right:
+                prev = cur.right
+                while prev.left and prev.left != cur:
+                    prev = prev.left
+
+                if not prev.left:
+                    prev.left = cur
+                    cur = cur.right
+                else:
+                    prev.left = None
+                    curSum += cur.val
+                    cur.val = curSum
+                    cur = cur.left
+            else:
+                curSum += cur.val
+                cur.val = curSum
+                cur = cur.left
+        
+        return root
+```
+
+```java
+/**
+ * Definition for a binary tree node.
+ * public class TreeNode {
+ *     int val;
+ *     TreeNode left;
+ *     TreeNode right;
+ *     TreeNode() {}
+ *     TreeNode(int val) { this.val = val; }
+ *     TreeNode(int val, TreeNode left, TreeNode right) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+public class Solution {
+    public TreeNode convertBST(TreeNode root) {
+        int curSum = 0;
+        TreeNode cur = root;
+
+        while (cur != null) {
+            if (cur.right != null) {
+                TreeNode prev = cur.right;
+                while (prev.left != null && prev.left != cur) {
+                    prev = prev.left;
+                }
+
+                if (prev.left == null) {
+                    prev.left = cur;
+                    cur = cur.right;
+                } else {
+                    prev.left = null;
+                    curSum += cur.val;
+                    cur.val = curSum;
+                    cur = cur.left;
+                }
+            } else {
+                curSum += cur.val;
+                cur.val = curSum;
+                cur = cur.left;
+            }
+        }
+        return root;
+    }
+}
+```
+
+```cpp
+/**
+ * Definition for a binary tree node.
+ * struct TreeNode {
+ *     int val;
+ *     TreeNode *left;
+ *     TreeNode *right;
+ *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
+ * };
+ */
+class Solution {
+public:
+    TreeNode* convertBST(TreeNode* root) {
+        int curSum = 0;
+        TreeNode* cur = root;
+
+        while (cur) {
+            if (cur->right) {
+                TreeNode* prev = cur->right;
+                while (prev->left && prev->left != cur) {
+                    prev = prev->left;
+                }
+
+                if (!prev->left) {
+                    prev->left = cur;
+                    cur = cur->right;
+                } else {
+                    prev->left = nullptr;
+                    curSum += cur->val;
+                    cur->val = curSum;
+                    cur = cur->left;
+                }
+            } else {
+                curSum += cur->val;
+                cur->val = curSum;
+                cur = cur->left;
+            }
+        }
+        return root;
+    }
+};
+```
+
+```javascript
+/**
+ * Definition for a binary tree node.
+ * class TreeNode {
+ *     constructor(val = 0, left = null, right = null) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+class Solution {
+    /**
+     * @param {TreeNode} root
+     * @return {TreeNode}
+     */
+    convertBST(root) {
+        let curSum = 0;
+        let cur = root;
+
+        while (cur) {
+            if (cur.right) {
+                let prev = cur.right;
+                while (prev.left && prev.left !== cur) {
+                    prev = prev.left;
+                }
+
+                if (!prev.left) {
+                    prev.left = cur;
+                    cur = cur.right;
+                } else {
+                    prev.left = null;
+                    curSum += cur.val;
+                    cur.val = curSum;
+                    cur = cur.left;
+                }
+            } else {
+                curSum += cur.val;
+                cur.val = curSum;
+                cur = cur.left;
+            }
+        }
+        return root;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(1)$
\ No newline at end of file
diff --git a/articles/design-linked-list.md b/articles/design-linked-list.md
new file mode 100644
index 000000000..618c2335c
--- /dev/null
+++ b/articles/design-linked-list.md
@@ -0,0 +1,1262 @@
+## 1. Singly Linked List
+
+::tabs-start
+
+```python
+class ListNode:
+    def __init__(self, val: int):
+        self.val = val
+        self.next = None
+
+class MyLinkedList:
+    def __init__(self):
+        self.head = ListNode(0)
+        self.size = 0
+
+    def get(self, index: int) -> int:
+        if index >= self.size:
+            return -1
+        cur = self.head.next
+        for _ in range(index):
+            cur = cur.next
+        return cur.val
+
+    def addAtHead(self, val: int) -> None:
+        node = ListNode(val)
+        node.next = self.head.next
+        self.head.next = node
+        self.size += 1
+
+    def addAtTail(self, val: int) -> None:
+        node = ListNode(val)
+        cur = self.head
+        while cur.next:
+            cur = cur.next
+        cur.next = node
+        self.size += 1
+
+    def addAtIndex(self, index: int, val: int) -> None:
+        if index > self.size:
+            return
+        cur = self.head
+        for _ in range(index):
+            cur = cur.next
+        node = ListNode(val)
+        node.next = cur.next
+        cur.next = node
+        self.size += 1
+
+    def deleteAtIndex(self, index: int) -> None:
+        if index >= self.size:
+            return
+        cur = self.head
+        for _ in range(index):
+            cur = cur.next
+        cur.next = cur.next.next
+        self.size -= 1
+```
+
+```java
+class ListNode {
+    int val;
+    ListNode next;
+    ListNode(int val) {
+        this.val = val;
+        this.next = null;
+    }
+}
+
+public class MyLinkedList {
+    private ListNode head;
+    private int size;
+    MyLinkedList() {
+        head = new ListNode(0);
+        size = 0;
+    }
+    public int get(int index) {
+        if (index >= size) return -1;
+        ListNode cur = head.next;
+        for (int i = 0; i < index; i++) {
+            cur = cur.next;
+        }
+        return cur.val;
+    }
+    public void addAtHead(int val) {
+        ListNode node = new ListNode(val);
+        node.next = head.next;
+        head.next = node;
+        size++;
+    }
+    public void addAtTail(int val) {
+        ListNode node = new ListNode(val);
+        ListNode cur = head;
+        while (cur.next != null) {
+            cur = cur.next;
+        }
+        cur.next = node;
+        size++;
+    }
+    public void addAtIndex(int index, int val) {
+        if (index > size) return;
+        ListNode cur = head;
+        for (int i = 0; i < index; i++) {
+            cur = cur.next;
+        }
+        ListNode node = new ListNode(val);
+        node.next = cur.next;
+        cur.next = node;
+        size++;
+    }
+    public void deleteAtIndex(int index) {
+        if (index >= size) return;
+        ListNode cur = head;
+        for (int i = 0; i < index; i++) {
+            cur = cur.next;
+        }
+        cur.next = cur.next.next;
+        size--;
+    }
+}
+```
+
+```cpp
+class MyLinkedList {
+    struct ListNode {
+        int val;
+        ListNode* next;
+        ListNode(int val) : val(val), next(nullptr) {}
+    };
+
+public:
+    ListNode* head;
+    int size;
+    MyLinkedList() {
+        head = new ListNode(0);
+        size = 0;
+    }
+    int get(int index) {
+        if (index >= size) return -1;
+        ListNode* cur = head->next;
+        for (int i = 0; i < index; i++) {
+            cur = cur->next;
+        }
+        return cur->val;
+    }
+    void addAtHead(int val) {
+        ListNode* node = new ListNode(val);
+        node->next = head->next;
+        head->next = node;
+        size++;
+    }
+    void addAtTail(int val) {
+        ListNode* node = new ListNode(val);
+        ListNode* cur = head;
+        while (cur->next != nullptr) {
+            cur = cur->next;
+        }
+        cur->next = node;
+        size++;
+    }
+    void addAtIndex(int index, int val) {
+        if (index > size) return;
+        ListNode* cur = head;
+        for (int i = 0; i < index; i++) {
+            cur = cur->next;
+        }
+        ListNode* node = new ListNode(val);
+        node->next = cur->next;
+        cur->next = node;
+        size++;
+    }
+    void deleteAtIndex(int index) {
+        if (index >= size) return;
+        ListNode* cur = head;
+        for (int i = 0; i < index; i++) {
+            cur = cur->next;
+        }
+        ListNode* temp = cur->next;
+        cur->next = cur->next->next;
+        delete temp;
+        size--;
+    }
+};
+```
+
+```javascript
+class ListNode {
+    /**
+     * @constructor
+     * @param {number} val
+     */
+    constructor(val) {
+        this.val = val;
+        this.next = null;
+    }
+}
+
+class MyLinkedList {
+    constructor() {
+        this.head = new ListNode(0);
+        this.size = 0;
+    }
+
+    /**
+     * @param {number} index
+     * @return {number}
+     */
+    get(index) {
+        if (index >= this.size) return -1;
+        let cur = this.head.next;
+        for (let i = 0; i < index; i++) {
+            cur = cur.next;
+        }
+        return cur.val;
+    }
+
+    /**
+     * @param {number} val
+     * @return {void}
+     */
+    addAtHead(val) {
+        const node = new ListNode(val);
+        node.next = this.head.next;
+        this.head.next = node;
+        this.size++;
+    }
+
+    /**
+     * @param {number} val
+     * @return {void}
+     */
+    addAtTail(val) {
+        const node = new ListNode(val);
+        let cur = this.head;
+        while (cur.next !== null) {
+            cur = cur.next;
+        }
+        cur.next = node;
+        this.size++;
+    }
+
+    /**
+     * @param {number} index
+     * @param {number} val
+     * @return {void}
+     */
+    addAtIndex(index, val) {
+        if (index > this.size) return;
+        let cur = this.head;
+        for (let i = 0; i < index; i++) {
+            cur = cur.next;
+        }
+        const node = new ListNode(val);
+        node.next = cur.next;
+        cur.next = node;
+        this.size++;
+    }
+
+    /**
+     * @param {number} index
+     * @return {void}
+     */
+    deleteAtIndex(index) {
+        if (index >= this.size) return;
+        let cur = this.head;
+        for (let i = 0; i < index; i++) {
+            cur = cur.next;
+        }
+        cur.next = cur.next.next;
+        this.size--;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity:
+    * $O(1)$ time for initialization.
+    * $O(1)$ time for $addAtHead()$.
+    * $O(n)$ time for $get()$, $addAtTail()$, $addAtIndex()$, $deleteAtIndex()$.
+* Space complexity: $O(n)$
+
+---
+
+## 2. Singly Linked List (Optimal)
+
+::tabs-start
+
+```python
+class ListNode:
+    def __init__(self, val=0, next=None):
+        self.val = val
+        self.next = next
+
+class MyLinkedList:
+    def __init__(self):
+        self.head = ListNode(0)
+        self.size = 0
+
+    def getPrev(self, index: int) -> ListNode:
+        cur = self.head
+        for _ in range(index):
+            cur = cur.next
+        return cur
+
+    def get(self, index: int) -> int:
+        if index >= self.size:
+            return -1
+        return self.getPrev(index).next.val
+
+    def addAtHead(self, val: int) -> None:
+        self.addAtIndex(0, val)
+
+    def addAtTail(self, val: int) -> None:
+        self.addAtIndex(self.size, val)
+
+    def addAtIndex(self, index: int, val: int) -> None:
+        if index > self.size:
+            return
+        prev = self.getPrev(index)
+        node = ListNode(val, prev.next)
+        prev.next = node
+        self.size += 1
+
+    def deleteAtIndex(self, index: int) -> None:
+        if index >= self.size:
+            return
+        prev = self.getPrev(index)
+        prev.next = prev.next.next
+        self.size -= 1
+```
+
+```java
+class ListNode {
+    int val;
+    ListNode next;
+    ListNode(int val, ListNode next) {
+        this.val = val;
+        this.next = next;
+    }
+    ListNode(int val) {
+        this(val, null);
+    }
+}
+
+public class MyLinkedList {
+    ListNode head;
+    int size;
+    
+    public MyLinkedList() {
+        head = new ListNode(0, null);
+        size = 0;
+    }
+    
+    private ListNode getPrev(int index) {
+        ListNode cur = head;
+        for (int i = 0; i < index; i++) {
+            cur = cur.next;
+        }
+        return cur;
+    }
+    
+    public int get(int index) {
+        if (index >= size) {
+            return -1;
+        }
+        return getPrev(index).next.val;
+    }
+    
+    public void addAtHead(int val) {
+        addAtIndex(0, val);
+    }
+    
+    public void addAtTail(int val) {
+        addAtIndex(size, val);
+    }
+    
+    public void addAtIndex(int index, int val) {
+        if (index > size) {
+            return;
+        }
+        ListNode prev = getPrev(index);
+        ListNode node = new ListNode(val, prev.next);
+        prev.next = node;
+        size++;
+    }
+    
+    public void deleteAtIndex(int index) {
+        if (index >= size) {
+            return;
+        }
+        ListNode prev = getPrev(index);
+        prev.next = prev.next.next;
+        size--;
+    }
+}
+```
+
+```cpp
+
+class MyLinkedList {
+    struct ListNode {
+        int val;
+        ListNode* next;
+        ListNode(int val, ListNode* next) : val(val), next(next) {}
+        ListNode(int val) : val(val), next(nullptr) {}
+    };
+
+public:
+    MyLinkedList() {
+        head = new ListNode(0, nullptr);
+        size = 0;
+    }
+    
+    int get(int index) {
+        if (index >= size) return -1;
+        return getPrev(index)->next->val;
+    }
+    
+    void addAtHead(int val) {
+        addAtIndex(0, val);
+    }
+    
+    void addAtTail(int val) {
+        addAtIndex(size, val);
+    }
+    
+    void addAtIndex(int index, int val) {
+        if (index > size) return;
+        ListNode* prev = getPrev(index);
+        ListNode* node = new ListNode(val, prev->next);
+        prev->next = node;
+        size++;
+    }
+    
+    void deleteAtIndex(int index) {
+        if (index >= size) return;
+        ListNode* prev = getPrev(index);
+        ListNode* toDelete = prev->next;
+        prev->next = prev->next->next;
+        delete toDelete;
+        size--;
+    }
+    
+private:
+    ListNode* head;
+    int size;
+    
+    ListNode* getPrev(int index) {
+        ListNode* cur = head;
+        for (int i = 0; i < index; i++) {
+            cur = cur->next;
+        }
+        return cur;
+    }
+};
+```
+
+```javascript
+class ListNode {
+	/**
+     * @constructor
+	 * @param {number}
+	 * @param {ListNode|null}
+	 */
+	constructor(val = 0, next = null) {
+		this.val = val;
+		this.next = next;
+	}
+}
+
+class MyLinkedList {
+	constructor() {
+		this.head = new ListNode(0);
+		this.size = 0;
+	}
+
+	/**
+	 * @param {number} index
+	 * @return {ListNode}
+	 */
+	getPrev(index) {
+		let cur = this.head;
+		for (let i = 0; i < index; i++) {
+			cur = cur.next;
+		}
+		return cur;
+	}
+
+	/**
+	 * @param {number} index
+	 * @return {number}
+	 */
+	get(index) {
+		if (index >= this.size) {
+			return -1;
+		}
+		return this.getPrev(index).next.val;
+	}
+
+	/**
+	 * @param {number} val
+	 * @return {void}
+	 */
+	addAtHead(val) {
+		this.addAtIndex(0, val);
+	}
+
+	/**
+	 * @param {number} val
+	 * @return {void}
+	 */
+	addAtTail(val) {
+		this.addAtIndex(this.size, val);
+	}
+
+	/**
+	 * @param {number} index
+	 * @param {number} val
+	 * @return {void}
+	 */
+	addAtIndex(index, val) {
+		if (index > this.size) {
+			return;
+		}
+		let prev = this.getPrev(index);
+		let node = new ListNode(val, prev.next);
+		prev.next = node;
+		this.size++;
+	}
+
+	/**
+	 * @param {number} index
+	 * @return {void}
+	 */
+	deleteAtIndex(index) {
+		if (index >= this.size) {
+			return;
+		}
+		let prev = this.getPrev(index);
+		prev.next = prev.next.next;
+		this.size--;
+	}
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity:
+    * $O(1)$ time for initialization.
+    * $O(1)$ time for $addAtHead()$.
+    * $O(n)$ time for $get()$, $addAtTail()$, $addAtIndex()$, $deleteAtIndex()$.
+* Space complexity: $O(n)$
+
+---
+
+## 3. Doubly Linked List
+
+::tabs-start
+
+```python
+class ListNode:
+    def __init__(self, val):
+        self.val = val
+        self.prev = None
+        self.next = None
+
+class MyLinkedList:
+
+    def __init__(self):
+        self.head = ListNode(0)
+        self.tail = ListNode(0)
+        self.head.next = self.tail
+        self.tail.prev = self.head
+
+    def get(self, index: int) -> int:
+        cur = self.head.next
+        while cur and index > 0:
+            cur = cur.next
+            index -= 1
+        if cur and cur != self.tail and index == 0:
+            return cur.val
+        return -1
+
+    def addAtHead(self, val: int) -> None:
+        node, next, prev = ListNode(val), self.head.next, self.head
+        prev.next = node
+        next.prev = node
+        node.next = next
+        node.prev = prev
+
+    def addAtTail(self, val: int) -> None:
+        node, next, prev = ListNode(val), self.tail, self.tail.prev
+        prev.next = node
+        next.prev = node
+        node.next = next
+        node.prev = prev
+
+    def addAtIndex(self, index: int, val: int) -> None:
+        cur = self.head.next
+        while cur and index > 0:
+            cur = cur.next
+            index -= 1
+        if cur and index == 0:
+            node, next, prev = ListNode(val), cur, cur.prev
+            prev.next = node
+            next.prev = node
+            node.next = next
+            node.prev = prev
+
+
+    def deleteAtIndex(self, index: int) -> None:
+        cur = self.head.next
+        while cur and index > 0:
+            cur = cur.next
+            index -= 1
+        if cur and cur != self.tail and index == 0:
+            next, prev = cur.next, cur.prev
+            next.prev = prev
+            prev.next = next
+```
+
+```java
+class ListNode {
+    int val;
+    ListNode prev;
+    ListNode next;
+
+    ListNode(int val) {
+        this.val = val;
+        this.prev = null;
+        this.next = null;
+    }
+}
+
+public class MyLinkedList {
+    ListNode head;
+    ListNode tail;
+
+    MyLinkedList() {
+        head = new ListNode(0);
+        tail = new ListNode(0);
+        head.next = tail;
+        tail.prev = head;
+    }
+
+    int get(int index) {
+        ListNode cur = head.next;
+        while (cur != null && index > 0) {
+            cur = cur.next;
+            index--;
+        }
+        if (cur != null && cur != tail && index == 0) {
+            return cur.val;
+        }
+        return -1;
+    }
+
+    void addAtHead(int val) {
+        ListNode node = new ListNode(val);
+        ListNode next = head.next;
+        ListNode prev = head;
+        prev.next = node;
+        next.prev = node;
+        node.next = next;
+        node.prev = prev;
+    }
+
+    void addAtTail(int val) {
+        ListNode node = new ListNode(val);
+        ListNode next = tail;
+        ListNode prev = tail.prev;
+        prev.next = node;
+        next.prev = node;
+        node.next = next;
+        node.prev = prev;
+    }
+
+    void addAtIndex(int index, int val) {
+        ListNode cur = head.next;
+        while (cur != null && index > 0) {
+            cur = cur.next;
+            index--;
+        }
+        if (cur != null && index == 0) {
+            ListNode node = new ListNode(val);
+            ListNode next = cur;
+            ListNode prev = cur.prev;
+            prev.next = node;
+            next.prev = node;
+            node.next = next;
+            node.prev = prev;
+        }
+    }
+
+    void deleteAtIndex(int index) {
+        ListNode cur = head.next;
+        while (cur != null && index > 0) {
+            cur = cur.next;
+            index--;
+        }
+        if (cur != null && cur != tail && index == 0) {
+            ListNode next = cur.next;
+            ListNode prev = cur.prev;
+            next.prev = prev;
+            prev.next = next;
+        }
+    }
+}
+```
+
+```cpp
+class MyLinkedList {
+    struct ListNode {
+        int val;
+        ListNode* prev;
+        ListNode* next;
+        ListNode(int val) : val(val), prev(nullptr), next(nullptr) {}
+    };
+public:
+	ListNode* head;
+	ListNode* tail;
+
+	MyLinkedList() {
+		head = new ListNode(0);
+		tail = new ListNode(0);
+		head->next = tail;
+		tail->prev = head;
+	}
+
+	int get(int index) {
+		ListNode* cur = head->next;
+		while (cur && index > 0) {
+			cur = cur->next;
+			index--;
+		}
+		if (cur && cur != tail && index == 0) {
+			return cur->val;
+		}
+		return -1;
+	}
+
+	void addAtHead(int val) {
+		ListNode* node = new ListNode(val);
+		ListNode* next = head->next;
+		ListNode* prev = head;
+		prev->next = node;
+		next->prev = node;
+		node->next = next;
+		node->prev = prev;
+	}
+
+	void addAtTail(int val) {
+		ListNode* node = new ListNode(val);
+		ListNode* next = tail;
+		ListNode* prev = tail->prev;
+		prev->next = node;
+		next->prev = node;
+		node->next = next;
+		node->prev = prev;
+	}
+
+	void addAtIndex(int index, int val) {
+		ListNode* cur = head->next;
+		while (cur && index > 0) {
+			cur = cur->next;
+			index--;
+		}
+		if (cur && index == 0) {
+			ListNode* node = new ListNode(val);
+			ListNode* next = cur;
+			ListNode* prev = cur->prev;
+			prev->next = node;
+			next->prev = node;
+			node->next = next;
+			node->prev = prev;
+		}
+	}
+
+	void deleteAtIndex(int index) {
+		ListNode* cur = head->next;
+		while (cur && index > 0) {
+			cur = cur->next;
+			index--;
+		}
+		if (cur && cur != tail && index == 0) {
+			ListNode* next = cur->next;
+			ListNode* prev = cur->prev;
+			next->prev = prev;
+			prev->next = next;
+			delete cur;
+		}
+	}
+};
+```
+
+```javascript
+class ListNode {
+	/**
+     * @constructor
+	 * @param {number} val
+	 */
+	constructor(val) {
+		this.val = val;
+		this.prev = null;
+		this.next = null;
+	}
+}
+
+class MyLinkedList {
+	constructor() {
+		this.head = new ListNode(0);
+		this.tail = new ListNode(0);
+		this.head.next = this.tail;
+		this.tail.prev = this.head;
+	}
+
+	/**
+	 * @param {number} index
+	 * @return {number}
+	 */
+	get(index) {
+		let cur = this.head.next;
+		while (cur && index > 0) {
+			cur = cur.next;
+			index--;
+		}
+		if (cur && cur !== this.tail && index === 0) {
+			return cur.val;
+		}
+		return -1;
+	}
+
+	/**
+	 * @param {number} val
+	 * @return {void}
+	 */
+	addAtHead(val) {
+		const node = new ListNode(val);
+		const next = this.head.next;
+		const prev = this.head;
+		prev.next = node;
+		next.prev = node;
+		node.next = next;
+		node.prev = prev;
+	}
+
+	/**
+	 * @param {number} val
+	 * @return {void}
+	 */
+	addAtTail(val) {
+		const node = new ListNode(val);
+		const next = this.tail;
+		const prev = this.tail.prev;
+		prev.next = node;
+		next.prev = node;
+		node.next = next;
+		node.prev = prev;
+	}
+
+	/**
+	 * @param {number} index
+	 * @param {number} val
+	 * @return {void}
+	 */
+	addAtIndex(index, val) {
+		let cur = this.head.next;
+		while (cur && index > 0) {
+			cur = cur.next;
+			index--;
+		}
+		if (cur && index === 0) {
+			const node = new ListNode(val);
+			const next = cur;
+			const prev = cur.prev;
+			prev.next = node;
+			next.prev = node;
+			node.next = next;
+			node.prev = prev;
+		}
+	}
+
+	/**
+	 * @param {number} index
+	 * @return {void}
+	 */
+	deleteAtIndex(index) {
+		let cur = this.head.next;
+		while (cur && index > 0) {
+			cur = cur.next;
+			index--;
+		}
+		if (cur && cur !== this.tail && index === 0) {
+			const next = cur.next;
+			const prev = cur.prev;
+			next.prev = prev;
+			prev.next = next;
+		}
+	}
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity:
+    * $O(1)$ time for initialization.
+    * $O(1)$ time for $addAtHead()$, $addAtTail()$.
+    * $O(n)$ time for $get()$, $addAtIndex()$, $deleteAtIndex()$.
+* Space complexity: $O(n)$
+
+---
+
+## 4. Doubly Linked List (Optimal)
+
+::tabs-start
+
+```python
+class ListNode:
+    def __init__(self, val=0, next=None, prev=None):
+        self.val = val
+        self.next = next
+        self.prev = prev
+
+class MyLinkedList:
+    def __init__(self):
+        self.head = ListNode(0)
+        self.tail = ListNode(0)
+        self.head.next = self.tail
+        self.tail.prev = self.head
+        self.size = 0
+
+    def getPrev(self, index: int) -> ListNode:
+        if index <= self.size // 2:
+            cur = self.head
+            for _ in range(index):
+                cur = cur.next
+        else:
+            cur = self.tail
+            for _ in range(self.size - index + 1):
+                cur = cur.prev
+        return cur
+
+    def get(self, index: int) -> int:
+        if index >= self.size:
+            return -1
+        return self.getPrev(index).next.val
+
+    def addAtHead(self, val: int) -> None:
+        self.addAtIndex(0, val)
+
+    def addAtTail(self, val: int) -> None:
+        self.addAtIndex(self.size, val)
+
+    def addAtIndex(self, index: int, val: int) -> None:
+        if index > self.size:
+            return
+        node = ListNode(val)
+        prev = self.getPrev(index)
+        next = prev.next
+        prev.next = node
+        node.prev = prev
+        node.next = next
+        next.prev = node
+        self.size += 1
+
+    def deleteAtIndex(self, index: int) -> None:
+        if index >= self.size:
+            return
+        prev = self.getPrev(index)
+        cur = prev.next
+        next = cur.next
+        prev.next = next
+        next.prev = prev
+        self.size -= 1
+```
+
+```java
+class ListNode {
+    int val;
+    ListNode next;
+    ListNode prev;
+    
+    ListNode(int val) {
+        this(val, null, null);
+    }
+    
+    ListNode(int val, ListNode next, ListNode prev) {
+        this.val = val;
+        this.next = next;
+        this.prev = prev;
+    }
+}
+
+public class MyLinkedList {
+    ListNode head;
+    ListNode tail;
+    int size;
+    
+    public MyLinkedList() {
+        head = new ListNode(0);
+        tail = new ListNode(0);
+        head.next = tail;
+        tail.prev = head;
+        size = 0;
+    }
+
+    private ListNode getPrev(int index) {
+        if (index <= size / 2) {
+            ListNode cur = head;
+            for (int i = 0; i < index; i++) {
+                cur = cur.next;
+            }
+            return cur;
+        } else {
+            ListNode cur = tail;
+            for (int i = 0; i < size - index + 1; i++) {
+                cur = cur.prev;
+            }
+            return cur;
+        }
+    }
+    
+    public int get(int index) {
+        if (index >= size) return -1;
+        return getPrev(index).next.val;
+    }
+    
+    public void addAtHead(int val) {
+        addAtIndex(0, val);
+    }
+    
+    public void addAtTail(int val) {
+        addAtIndex(size, val);
+    }
+    
+    public void addAtIndex(int index, int val) {
+        if (index > size) return;
+        ListNode node = new ListNode(val);
+        ListNode prev = getPrev(index);
+        ListNode next = prev.next;
+        prev.next = node;
+        node.prev = prev;
+        node.next = next;
+        next.prev = node;
+        size++;
+    }
+    
+    public void deleteAtIndex(int index) {
+        if (index >= size) return;
+        ListNode prev = getPrev(index);
+        ListNode cur = prev.next;
+        ListNode next = cur.next;
+        prev.next = next;
+        next.prev = prev;
+        size--;
+    }
+}
+```
+
+```cpp
+class MyLinkedList {
+    struct ListNode {
+        int val;
+        ListNode* next;
+        ListNode* prev;
+        ListNode(int val = 0, ListNode* next = nullptr, ListNode* prev = nullptr) {
+            this->val = val;
+            this->next = next;
+            this->prev = prev;
+        }
+    };
+    
+public:
+    ListNode* head;
+    ListNode* tail;
+    int size;
+    
+    MyLinkedList() {
+        head = new ListNode(0);
+        tail = new ListNode(0);
+        head->next = tail;
+        tail->prev = head;
+        size = 0;
+    }
+    
+    ListNode* getPrev(int index) {
+        if (index <= size / 2) {
+            ListNode* cur = head;
+            for (int i = 0; i < index; i++) {
+                cur = cur->next;
+            }
+            return cur;
+        } else {
+            ListNode* cur = tail;
+            for (int i = 0; i < size - index + 1; i++) {
+                cur = cur->prev;
+            }
+            return cur;
+        }
+    }
+    
+    int get(int index) {
+        if (index >= size) return -1;
+        return getPrev(index)->next->val;
+    }
+    
+    void addAtHead(int val) {
+        addAtIndex(0, val);
+    }
+    
+    void addAtTail(int val) {
+        addAtIndex(size, val);
+    }
+    
+    void addAtIndex(int index, int val) {
+        if (index > size) return;
+        ListNode* node = new ListNode(val);
+        ListNode* prev = getPrev(index);
+        ListNode* next = prev->next;
+        prev->next = node;
+        node->prev = prev;
+        node->next = next;
+        next->prev = node;
+        size++;
+    }
+    
+    void deleteAtIndex(int index) {
+        if (index >= size) return;
+        ListNode* prev = getPrev(index);
+        ListNode* cur = prev->next;
+        ListNode* next = cur->next;
+        prev->next = next;
+        next->prev = prev;
+        delete cur;
+        size--;
+    }
+};
+```
+
+```javascript
+class ListNode {
+    /**
+     * @constructor
+     * @param {number}
+     * @param {ListNode|null}
+     * @param {ListNode|null}
+     */
+	constructor(val = 0, next = null, prev = null) {
+		this.val = val;
+		this.next = next;
+		this.prev = prev;
+	}
+}
+
+class MyLinkedList {
+	constructor() {
+		this.head = new ListNode(0);
+		this.tail = new ListNode(0);
+		this.head.next = this.tail;
+		this.tail.prev = this.head;
+		this.size = 0;
+	}
+
+	/**
+	 * @param {number} index
+	 * @return {ListNode}
+	 */
+	getPrev(index) {
+		let cur;
+		if (index <= this.size / 2) {
+			cur = this.head;
+			for (let i = 0; i < index; i++) {
+				cur = cur.next;
+			}
+		} else {
+			cur = this.tail;
+			for (let i = 0; i < this.size - index + 1; i++) {
+				cur = cur.prev;
+			}
+		}
+		return cur;
+	}
+
+	/**
+	 * @param {number} index
+	 * @return {number}
+	 */
+	get(index) {
+		if (index >= this.size) {
+			return -1;
+		}
+		return this.getPrev(index).next.val;
+	}
+
+	/**
+	 * @param {number} val
+	 * @return {void}
+	 */
+	addAtHead(val) {
+		this.addAtIndex(0, val);
+	}
+
+	/**
+	 * @param {number} val
+	 * @return {void}
+	 */
+	addAtTail(val) {
+		this.addAtIndex(this.size, val);
+	}
+
+	/**
+	 * @param {number} index
+	 * @param {number} val
+	 * @return {void}
+	 */
+	addAtIndex(index, val) {
+		if (index > this.size) {
+			return;
+		}
+		const node = new ListNode(val);
+		const prev = this.getPrev(index);
+		const next = prev.next;
+		prev.next = node;
+		node.prev = prev;
+		node.next = next;
+		next.prev = node;
+		this.size++;
+	}
+
+	/**
+	 * @param {number} index
+	 * @return {void}
+	 */
+	deleteAtIndex(index) {
+		if (index >= this.size) {
+			return;
+		}
+		const prev = this.getPrev(index);
+		const cur = prev.next;
+		const next = cur.next;
+		prev.next = next;
+		next.prev = prev;
+		this.size--;
+	}
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity:
+    * $O(1)$ time for initialization.
+    * $O(1)$ time for $addAtHead()$, $addAtTail()$.
+    * $O(n)$ time for $get()$, $addAtIndex()$, $deleteAtIndex()$.
+* Space complexity: $O(n)$
\ No newline at end of file
diff --git a/articles/even-odd-tree.md b/articles/even-odd-tree.md
new file mode 100644
index 000000000..4c5b25687
--- /dev/null
+++ b/articles/even-odd-tree.md
@@ -0,0 +1,543 @@
+## 1. Breadth First Search
+
+::tabs-start
+
+```python
+# Definition for a binary tree node.
+# class TreeNode:
+#     def __init__(self, val=0, left=None, right=None):
+#         self.val = val
+#         self.left = left
+#         self.right = right
+class Solution:
+    def isEvenOddTree(self, root: Optional[TreeNode]) -> bool:
+        even = True
+        q = deque([root])
+
+        while q:
+            prev = float("-inf") if even else float("inf")
+            for _ in range(len(q)):
+                node = q.popleft()
+
+                if even and (node.val % 2 == 0 or node.val <= prev):
+                    return False
+                elif not even and (node.val % 2 == 1 or node.val >= prev):
+                    return False
+
+                if node.left:
+                    q.append(node.left)
+                if node.right:
+                    q.append(node.right)
+
+                prev = node.val
+
+            even = not even
+
+        return True
+```
+
+```java
+/**
+ * Definition for a binary tree node.
+ * public class TreeNode {
+ *     int val;
+ *     TreeNode left;
+ *     TreeNode right;
+ *     TreeNode() {}
+ *     TreeNode(int val) { this.val = val; }
+ *     TreeNode(int val, TreeNode left, TreeNode right) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+public class Solution {
+    public boolean isEvenOddTree(TreeNode root) {
+        boolean even = true;
+        Queue<TreeNode> q = new LinkedList<>();
+        q.offer(root);
+
+        while (!q.isEmpty()) {
+            int prev = even ? Integer.MIN_VALUE : Integer.MAX_VALUE;
+            for (int i = q.size(); i > 0; i--) {
+                TreeNode node = q.poll();
+
+                if (even && (node.val % 2 == 0 || node.val <= prev)) return false;
+                if (!even && (node.val % 2 == 1 || node.val >= prev)) return false;
+
+                if (node.left != null) q.offer(node.left);
+                if (node.right != null) q.offer(node.right);
+
+                prev = node.val;
+            }
+            even = !even;
+        }
+        return true;
+    }
+}
+```
+
+```cpp
+/**
+ * Definition for a binary tree node.
+ * struct TreeNode {
+ *     int val;
+ *     TreeNode *left;
+ *     TreeNode *right;
+ *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
+ * };
+ */
+class Solution {
+public:
+    bool isEvenOddTree(TreeNode* root) {
+        bool even = true;
+        queue<TreeNode*> q;
+        q.push(root);
+
+        while (!q.empty()) {
+            int prev = even ? INT_MIN : INT_MAX;
+            for (int i = q.size(); i > 0; i--) {
+                TreeNode* node = q.front();q.pop();
+
+                if (even && (node->val % 2 == 0 || node->val <= prev)) return false;
+                if (!even && (node->val % 2 == 1 || node->val >= prev)) return false;
+
+                if (node->left) q.push(node->left);
+                if (node->right) q.push(node->right);
+
+                prev = node->val;
+            }
+            even = !even;
+        }
+        return true;
+    }
+};
+```
+
+```javascript
+/**
+ * Definition for a binary tree node.
+ * class TreeNode {
+ *     constructor(val = 0, left = null, right = null) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+class Solution {
+    /**
+     * @param {TreeNode} root
+     * @return {boolean}
+     */
+    isEvenOddTree(root) {
+        let even = true;
+        const q = new Queue([root]);
+
+        while (!q.isEmpty()) {
+            let prev = even ? -Infinity : Infinity;
+            for (let i = q.size(); i > 0; i--) {
+                let node = q.pop();
+
+                if (even && (node.val % 2 === 0 || node.val <= prev)) return false;
+                if (!even && (node.val % 2 === 1 || node.val >= prev)) return false;
+
+                if (node.left) q.push(node.left);
+                if (node.right) q.push(node.right);
+
+                prev = node.val;
+            }
+            even = !even;
+        }
+        return true;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(n)$
+
+---
+
+## 2. Depth First Search
+
+::tabs-start
+
+```python
+# Definition for a binary tree node.
+# class TreeNode:
+#     def __init__(self, val=0, left=None, right=None):
+#         self.val = val
+#         self.left = left
+#         self.right = right
+class Solution:
+    def isEvenOddTree(self, root: Optional[TreeNode]) -> bool:
+        levels = []
+
+        def dfs(node, level):
+            if not node:
+                return True
+
+            even = level % 2 == 0
+            if ((even and node.val % 2 == 0) or 
+                (not even and (node.val % 2 == 1))
+            ):
+                return False
+
+            if len(levels) == level:
+                levels.append(node.val)
+            else:
+                if ((even and node.val <= levels[level]) or 
+                    (not even and node.val >= levels[level])
+                ):
+                    return False
+                levels[level] = node.val
+
+            return dfs(node.left, level + 1) and dfs(node.right, level + 1)
+
+        return dfs(root, 0)
+```
+
+```java
+/**
+ * Definition for a binary tree node.
+ * public class TreeNode {
+ *     int val;
+ *     TreeNode left;
+ *     TreeNode right;
+ *     TreeNode() {}
+ *     TreeNode(int val) { this.val = val; }
+ *     TreeNode(int val, TreeNode left, TreeNode right) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+public class Solution {
+    List<Integer> levels = new ArrayList<>();
+
+    private boolean dfs(TreeNode node, int level) {
+        if (node == null) return true;
+
+        boolean even = level % 2 == 0;
+        if ((even && node.val % 2 == 0) || 
+            (!even && node.val % 2 == 1)) {
+            return false;
+        }
+
+        if (levels.size() == level) {
+            levels.add(node.val);
+        } else {
+            if ((even && node.val <= levels.get(level)) || 
+                (!even && node.val >= levels.get(level))) {
+                return false;
+            }
+            levels.set(level, node.val);
+        }
+
+        return dfs(node.left, level + 1) && dfs(node.right, level + 1);
+    }
+
+    public boolean isEvenOddTree(TreeNode root) {
+        return dfs(root, 0);
+    }
+}
+```
+
+```cpp
+/**
+ * Definition for a binary tree node.
+ * struct TreeNode {
+ *     int val;
+ *     TreeNode *left;
+ *     TreeNode *right;
+ *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
+ * };
+ */
+class Solution {
+public:
+    vector<int> levels;
+
+    bool dfs(TreeNode* node, int level) {
+        if (!node) return true;
+
+        bool even = level % 2 == 0;
+        if ((even && node->val % 2 == 0) || 
+            (!even && node->val % 2 == 1)) {
+            return false;
+        }
+
+        if (levels.size() == level) {
+            levels.push_back(node->val);
+        } else {
+            if ((even && node->val <= levels[level]) || 
+                (!even && node->val >= levels[level])) {
+                return false;
+            }
+            levels[level] = node->val;
+        }
+
+        return dfs(node->left, level + 1) && dfs(node->right, level + 1);
+    }
+
+    bool isEvenOddTree(TreeNode* root) {
+        return dfs(root, 0);
+    }
+};
+```
+
+```javascript
+/**
+ * Definition for a binary tree node.
+ * class TreeNode {
+ *     constructor(val = 0, left = null, right = null) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+class Solution {
+    /**
+     * @param {TreeNode} root
+     * @return {boolean}
+     */
+    isEvenOddTree(root) {
+        const levels = [];
+
+        const dfs = (node, level) => {
+            if (!node) return true;
+
+            const even = level % 2 === 0;
+            if ((even && node.val % 2 === 0) || 
+                (!even && node.val % 2 === 1)) {
+                return false;
+            }
+
+            if (levels.length === level) {
+                levels.push(node.val);
+            } else {
+                if ((even && node.val <= levels[level]) || 
+                    (!even && node.val >= levels[level])) {
+                    return false;
+                }
+                levels[level] = node.val;
+            }
+
+            return dfs(node.left, level + 1) && dfs(node.right, level + 1);
+        };
+
+        return dfs(root, 0);
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(n)$
+
+---
+
+## 3. Iterative DFS
+
+::tabs-start
+
+```python
+# Definition for a binary tree node.
+# class TreeNode:
+#     def __init__(self, val=0, left=None, right=None):
+#         self.val = val
+#         self.left = left
+#         self.right = right
+class Solution:
+    def isEvenOddTree(self, root: Optional[TreeNode]) -> bool:
+        stack = [(root, 0)]
+        levels = []
+
+        while stack:
+            node, level = stack.pop()
+
+            even = level % 2 == 0
+            if ((even and node.val % 2 == 0) or 
+                (not even and node.val % 2 == 1)
+            ):
+                return False
+
+            if len(levels) == level:
+                levels.append(node.val)
+            else:
+                if ((even and node.val <= levels[level]) or 
+                    (not even and node.val >= levels[level])
+                ):
+                    return False
+                levels[level] = node.val
+
+            if node.right:
+                stack.append((node.right, level + 1))
+            if node.left:
+                stack.append((node.left, level + 1))
+
+        return True
+```
+
+```java
+/**
+ * Definition for a binary tree node.
+ * public class TreeNode {
+ *     int val;
+ *     TreeNode left;
+ *     TreeNode right;
+ *     TreeNode() {}
+ *     TreeNode(int val) { this.val = val; }
+ *     TreeNode(int val, TreeNode left, TreeNode right) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+public class Solution {
+    public boolean isEvenOddTree(TreeNode root) {
+        Stack<Pair<TreeNode, Integer>> stack = new Stack<>();
+        stack.push(new Pair<>(root, 0));
+        List<Integer> levels = new ArrayList<>();
+
+        while (!stack.isEmpty()) {
+            Pair<TreeNode, Integer> pair = stack.pop();
+            TreeNode node = pair.getKey();
+            int level = pair.getValue();
+
+            boolean even = level % 2 == 0;
+            if ((even && node.val % 2 == 0) || 
+                (!even && node.val % 2 == 1))
+                return false;
+
+            if (levels.size() == level) {
+                levels.add(node.val);
+            } else {
+                if ((even && node.val <= levels.get(level)) || 
+                    (!even && node.val >= levels.get(level)))
+                    return false;
+                levels.set(level, node.val);
+            }
+
+            if (node.right != null) stack.push(new Pair<>(node.right, level + 1));
+            if (node.left != null) stack.push(new Pair<>(node.left, level + 1));
+        }
+
+        return true;
+    }
+}
+```
+
+```cpp
+/**
+ * Definition for a binary tree node.
+ * struct TreeNode {
+ *     int val;
+ *     TreeNode *left;
+ *     TreeNode *right;
+ *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
+ * };
+ */
+class Solution {
+public:
+    bool isEvenOddTree(TreeNode* root) {
+        stack<pair<TreeNode*, int>> stack;
+        stack.push({root, 0});
+        vector<int> levels;
+
+        while (!stack.empty()) {
+            auto [node, level] = stack.top();
+            stack.pop();
+
+            bool even = level % 2 == 0;
+            if ((even && node->val % 2 == 0) || 
+                (!even && node->val % 2 == 1))
+                return false;
+
+            if (levels.size() == level) {
+                levels.push_back(node->val);
+            } else {
+                if ((even && node->val <= levels[level]) || 
+                    (!even && node->val >= levels[level]))
+                    return false;
+                levels[level] = node->val;
+            }
+
+            if (node->right) stack.push({node->right, level + 1});
+            if (node->left) stack.push({node->left, level + 1});
+        }
+
+        return true;
+    }
+};
+```
+
+```javascript
+/**
+ * Definition for a binary tree node.
+ * class TreeNode {
+ *     constructor(val = 0, left = null, right = null) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+class Solution {
+    /**
+     * @param {TreeNode} root
+     * @return {boolean}
+     */
+    isEvenOddTree(root) {
+        const stack = [[root, 0]];
+        const levels = [];
+
+        while (stack.length) {
+            const [node, level] = stack.pop();
+
+            const even = level % 2 === 0;
+            if ((even && node.val % 2 === 0) || 
+                (!even && node.val % 2 === 1))
+                return false;
+
+            if (levels.length === level) {
+                levels.push(node.val);
+            } else {
+                if ((even && node.val <= levels[level]) || 
+                    (!even && node.val >= levels[level]))
+                    return false;
+                levels[level] = node.val;
+            }
+
+            if (node.right) stack.push([node.right, level + 1]);
+            if (node.left) stack.push([node.left, level + 1]);
+        }
+
+        return true;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(n)$
\ No newline at end of file
diff --git a/articles/find-bottom-left-tree-value.md b/articles/find-bottom-left-tree-value.md
new file mode 100644
index 000000000..c04645674
--- /dev/null
+++ b/articles/find-bottom-left-tree-value.md
@@ -0,0 +1,633 @@
+## 1. Breadth First Search
+
+::tabs-start
+
+```python
+# Definition for a binary tree node.
+# class TreeNode:
+#     def __init__(self, val=0, left=None, right=None):
+#         self.val = val
+#         self.left = left
+#         self.right = right
+class Solution:
+    def findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
+        q = deque([root])
+
+        while q:
+            node = q.popleft()
+            if node.right:
+                q.append(node.right)
+            if node.left:
+                q.append(node.left)
+
+        return node.val
+```
+
+```java
+/**
+ * Definition for a binary tree node.
+ * public class TreeNode {
+ *     int val;
+ *     TreeNode left;
+ *     TreeNode right;
+ *     TreeNode() {}
+ *     TreeNode(int val) { this.val = val; }
+ *     TreeNode(int val, TreeNode left, TreeNode right) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+public class Solution {
+    public int findBottomLeftValue(TreeNode root) {
+        Queue<TreeNode> q = new LinkedList<>();
+        q.offer(root);
+        TreeNode node = null;
+
+        while (!q.isEmpty()) {
+            node = q.poll();
+            if (node.right != null) q.offer(node.right);
+            if (node.left != null) q.offer(node.left);
+        }
+        return node.val;
+    }
+}
+```
+
+```cpp
+/**
+ * Definition for a binary tree node.
+ * struct TreeNode {
+ *     int val;
+ *     TreeNode *left;
+ *     TreeNode *right;
+ *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
+ * };
+ */
+class Solution {
+public:
+    int findBottomLeftValue(TreeNode* root) {
+        queue<TreeNode*> q;
+        q.push(root);
+        TreeNode* node = nullptr;
+
+        while (!q.empty()) {
+            node = q.front();
+            q.pop();
+            if (node->right) q.push(node->right);
+            if (node->left) q.push(node->left);
+        }
+        return node->val;
+    }
+};
+```
+
+```javascript
+/**
+ * Definition for a binary tree node.
+ * class TreeNode {
+ *     constructor(val = 0, left = null, right = null) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+class Solution {
+    /**
+     * @param {TreeNode} root
+     * @return {number}
+     */
+    findBottomLeftValue(root) {
+        const q = new Queue([root]);
+        let node = null;
+
+        while (!q.isEmpty()) {
+            node = q.pop();
+            if (node.right) q.push(node.right);
+            if (node.left) q.push(node.left);
+        }
+        return node.val;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(n)$
+
+---
+
+## 2. Depth First Search
+
+::tabs-start
+
+```python
+# Definition for a binary tree node.
+# class TreeNode:
+#     def __init__(self, val=0, left=None, right=None):
+#         self.val = val
+#         self.left = left
+#         self.right = right
+class Solution:
+    def findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
+        self.maxDepth, self.res = -1, root.val
+
+        def dfs(node, depth):
+            if not node:
+                return
+            if depth > self.maxDepth:
+                self.maxDepth, self.res = depth, node.val
+            
+            dfs(node.left, depth + 1)
+            dfs(node.right, depth + 1)
+
+        dfs(root, 0)
+        return self.res
+```
+
+```java
+/**
+ * Definition for a binary tree node.
+ * public class TreeNode {
+ *     int val;
+ *     TreeNode left;
+ *     TreeNode right;
+ *     TreeNode() {}
+ *     TreeNode(int val) { this.val = val; }
+ *     TreeNode(int val, TreeNode left, TreeNode right) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+public class Solution {
+    private int maxDepth = -1;
+    private int res;
+
+    public int findBottomLeftValue(TreeNode root) {
+        res = root.val;
+        dfs(root, 0);
+        return res;
+    }
+
+    private void dfs(TreeNode node, int depth) {
+        if (node == null) return;
+        if (depth > maxDepth) {
+            maxDepth = depth;
+            res = node.val;
+        }
+
+        dfs(node.left, depth + 1);
+        dfs(node.right, depth + 1);
+    }
+}
+```
+
+```cpp
+/**
+ * Definition for a binary tree node.
+ * struct TreeNode {
+ *     int val;
+ *     TreeNode *left;
+ *     TreeNode *right;
+ *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
+ * };
+ */
+class Solution {
+public:
+    int maxDepth = -1, res;
+
+    int findBottomLeftValue(TreeNode* root) {
+        res = root->val;
+        dfs(root, 0);
+        return res;
+    }
+
+private:
+    void dfs(TreeNode* node, int depth) {
+        if (!node) return;
+        if (depth > maxDepth) {
+            maxDepth = depth;
+            res = node->val;
+        }
+
+        dfs(node->left, depth + 1);
+        dfs(node->right, depth + 1);
+    }
+};
+```
+
+```javascript
+/**
+ * Definition for a binary tree node.
+ * class TreeNode {
+ *     constructor(val = 0, left = null, right = null) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+class Solution {
+    /**
+     * @param {TreeNode} root
+     * @return {number}
+     */
+    findBottomLeftValue(root) {
+        let maxDepth = -1, res = root.val;
+
+        const dfs = (node, depth) => {
+            if (!node) return;
+            if (depth > maxDepth) {
+                maxDepth = depth;
+                res = node.val;
+            }
+
+            dfs(node.left, depth + 1);
+            dfs(node.right, depth + 1);
+        };
+
+        dfs(root, 0);
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(n)$ for recursion stack.
+
+---
+
+## 3. Iterative DFS
+
+::tabs-start
+
+```python
+# Definition for a binary tree node.
+# class TreeNode:
+#     def __init__(self, val=0, left=None, right=None):
+#         self.val = val
+#         self.left = left
+#         self.right = right
+class Solution:
+    def findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
+        res, maxDepth = root.val, -1
+        stack = [(root, 0)]
+
+        while stack:
+            node, depth = stack.pop()
+            if depth > maxDepth:
+                maxDepth = depth
+                res = node.val
+
+            if node.right:
+                stack.append((node.right, depth + 1))
+            if node.left:
+                stack.append((node.left, depth + 1))
+
+        return res
+```
+
+```java
+/**
+ * Definition for a binary tree node.
+ * public class TreeNode {
+ *     int val;
+ *     TreeNode left;
+ *     TreeNode right;
+ *     TreeNode() {}
+ *     TreeNode(int val) { this.val = val; }
+ *     TreeNode(int val, TreeNode left, TreeNode right) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+public class Solution {
+    public int findBottomLeftValue(TreeNode root) {
+        int res = root.val, maxDepth = -1;
+        Stack<Pair<TreeNode, Integer>> stack = new Stack<>();
+        stack.push(new Pair<>(root, 0));
+
+        while (!stack.isEmpty()) {
+            Pair<TreeNode, Integer> p = stack.pop();
+            TreeNode node = p.getKey();
+            int depth = p.getValue();
+            if (depth > maxDepth) {
+                maxDepth = depth;
+                res = node.val;
+            }
+
+            if (node.right != null) {
+                stack.push(new Pair<>(node.right, depth + 1));
+            }
+            if (node.left != null) {
+                stack.push(new Pair<>(node.left, depth + 1));
+            }
+        }
+
+        return res;
+    }
+}
+```
+
+```cpp
+/**
+ * Definition for a binary tree node.
+ * struct TreeNode {
+ *     int val;
+ *     TreeNode *left;
+ *     TreeNode *right;
+ *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
+ * };
+ */
+class Solution {
+public:
+    int findBottomLeftValue(TreeNode* root) {
+        int res = root->val, maxDepth = -1;
+        stack<pair<TreeNode*, int>> stack;
+        stack.push({root, 0});
+
+        while (!stack.empty()) {
+            auto [node, depth] = stack.top();stack.pop();
+            if (depth > maxDepth) {
+                maxDepth = depth;
+                res = node->val;
+            }
+
+            if (node->right) {
+                stack.push({node->right, depth + 1});
+            }
+            if (node->left) {
+                stack.push({node->left, depth + 1});
+            }
+        }
+
+        return res;
+    }
+};
+```
+
+```javascript
+/**
+ * Definition for a binary tree node.
+ * class TreeNode {
+ *     constructor(val = 0, left = null, right = null) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+class Solution {
+    /**
+     * @param {TreeNode} root
+     * @return {number}
+     */
+    findBottomLeftValue(root) {
+        let res = root.val, maxDepth = -1;
+        const stack = [[root, 0]];
+
+        while (stack.length) {
+            const [node, depth] = stack.pop();
+            if (depth > maxDepth) {
+                maxDepth = depth;
+                res = node.val;
+            }
+
+            if (node.right) stack.push([node.right, depth + 1]);
+            if (node.left) stack.push([node.left, depth + 1]);
+        }
+
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(n)$
+
+---
+
+## 4. Morris Traversal
+
+::tabs-start
+
+```python
+# Definition for a binary tree node.
+# class TreeNode:
+#     def __init__(self, val=0, left=None, right=None):
+#         self.val = val
+#         self.left = left
+#         self.right = right
+class Solution:
+    def findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
+        res, maxDepth, curDepth = root.val, -1, 0
+        cur = root
+
+        while cur:
+            if not cur.left:
+                if curDepth > maxDepth:
+                    maxDepth, res = curDepth, cur.val
+                cur = cur.right
+                curDepth += 1
+            else:
+                prev = cur.left
+                steps = 1
+                while prev.right and prev.right != cur:
+                    prev = prev.right
+                    steps += 1
+
+                if not prev.right:
+                    prev.right = cur
+                    cur = cur.left
+                    curDepth += 1
+                else:
+                    prev.right = None
+                    curDepth -= steps
+                    cur = cur.right
+
+        return res
+```
+
+```java
+/**
+ * Definition for a binary tree node.
+ * public class TreeNode {
+ *     int val;
+ *     TreeNode left;
+ *     TreeNode right;
+ *     TreeNode() {}
+ *     TreeNode(int val) { this.val = val; }
+ *     TreeNode(int val, TreeNode left, TreeNode right) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+public class Solution {
+    public int findBottomLeftValue(TreeNode root) {
+        int res = root.val, maxDepth = -1, curDepth = 0;
+        TreeNode cur = root;
+
+        while (cur != null) {
+            if (cur.left == null) {
+                if (curDepth > maxDepth) {
+                    maxDepth = curDepth;
+                    res = cur.val;
+                }
+                cur = cur.right;
+                curDepth++;
+            } else {
+                TreeNode prev = cur.left;
+                int steps = 1;
+                while (prev.right != null && prev.right != cur) {
+                    prev = prev.right;
+                    steps++;
+                }
+
+                if (prev.right == null) {
+                    prev.right = cur;
+                    cur = cur.left;
+                    curDepth++;
+                } else {
+                    prev.right = null;
+                    curDepth -= steps;
+                    cur = cur.right;
+                }
+            }
+        }
+        return res;
+    }
+}
+```
+
+```cpp
+/**
+ * Definition for a binary tree node.
+ * struct TreeNode {
+ *     int val;
+ *     TreeNode *left;
+ *     TreeNode *right;
+ *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
+ * };
+ */
+class Solution {
+public:
+    int findBottomLeftValue(TreeNode* root) {
+        int res = root->val, maxDepth = -1, curDepth = 0;
+        TreeNode* cur = root;
+
+        while (cur) {
+            if (!cur->left) {
+                if (curDepth > maxDepth) {
+                    maxDepth = curDepth;
+                    res = cur->val;
+                }
+                cur = cur->right;
+                curDepth++;
+            } else {
+                TreeNode* prev = cur->left;
+                int steps = 1;
+                while (prev->right && prev->right != cur) {
+                    prev = prev->right;
+                    steps++;
+                }
+
+                if (!prev->right) {
+                    prev->right = cur;
+                    cur = cur->left;
+                    curDepth++;
+                } else {
+                    prev->right = nullptr;
+                    curDepth -= steps;
+                    cur = cur->right;
+                }
+            }
+        }
+        return res;
+    }
+};
+```
+
+```javascript
+/**
+ * Definition for a binary tree node.
+ * class TreeNode {
+ *     constructor(val = 0, left = null, right = null) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+class Solution {
+    /**
+     * @param {TreeNode} root
+     * @return {number}
+     */
+    findBottomLeftValue(root) {
+        let res = root.val, maxDepth = -1, curDepth = 0;
+        let cur = root;
+
+        while (cur) {
+            if (!cur.left) {
+                if (curDepth > maxDepth) {
+                    maxDepth = curDepth;
+                    res = cur.val;
+                }
+                cur = cur.right;
+                curDepth++;
+            } else {
+                let prev = cur.left, steps = 1;
+                while (prev.right && prev.right !== cur) {
+                    prev = prev.right;
+                    steps++;
+                }
+
+                if (!prev.right) {
+                    prev.right = cur;
+                    cur = cur.left;
+                    curDepth++;
+                } else {
+                    prev.right = null;
+                    curDepth -= steps;
+                    cur = cur.right;
+                }
+            }
+        }
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(1)$ extra space.
\ No newline at end of file
diff --git a/articles/find-largest-value-in-each-tree-row.md b/articles/find-largest-value-in-each-tree-row.md
new file mode 100644
index 000000000..d54ce9dfd
--- /dev/null
+++ b/articles/find-largest-value-in-each-tree-row.md
@@ -0,0 +1,462 @@
+## 1. Breadth First Search
+
+::tabs-start
+
+```python
+# Definition for a binary tree node.
+# class TreeNode:
+#     def __init__(self, val=0, left=None, right=None):
+#         self.val = val
+#         self.left = left
+#         self.right = right
+class Solution:
+    def largestValues(self, root: Optional[TreeNode]) -> List[int]:
+        if not root:
+            return []
+
+        res = []
+        q = deque([root])
+        while q:
+            row_max = q[0].val
+            for _ in range(len(q)):
+                node = q.popleft()
+                row_max = max(row_max, node.val)
+                if node.left:
+                    q.append(node.left)
+                if node.right:
+                    q.append(node.right)
+            res.append(row_max)
+
+        return res
+```
+
+```java
+/**
+ * Definition for a binary tree node.
+ * public class TreeNode {
+ *     int val;
+ *     TreeNode left;
+ *     TreeNode right;
+ *     TreeNode() {}
+ *     TreeNode(int val) { this.val = val; }
+ *     TreeNode(int val, TreeNode left, TreeNode right) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+public class Solution {
+    public List<Integer> largestValues(TreeNode root) {
+        if (root == null) return new ArrayList<>();
+
+        List<Integer> res = new ArrayList<>();
+        Queue<TreeNode> q = new LinkedList<>();
+        q.offer(root);
+
+        while (!q.isEmpty()) {
+            int rowMax = q.peek().val;
+            for (int i = q.size(); i > 0; i--) {
+                TreeNode node = q.poll();
+                rowMax = Math.max(rowMax, node.val);
+                if (node.left != null) q.offer(node.left);
+                if (node.right != null) q.offer(node.right);
+            }
+            res.add(rowMax);
+        }
+
+        return res;
+    }
+}
+```
+
+```cpp
+/**
+ * Definition for a binary tree node.
+ * struct TreeNode {
+ *     int val;
+ *     TreeNode *left;
+ *     TreeNode *right;
+ *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
+ * };
+ */
+class Solution {
+public:
+    vector<int> largestValues(TreeNode* root) {
+        if (!root) return {};
+
+        vector<int> res;
+        queue<TreeNode*> q;
+        q.push(root);
+
+        while (!q.empty()) {
+            int rowMax = q.front()->val;
+            for (int i = q.size(); i > 0; i--) {
+                TreeNode* node = q.front(); q.pop();
+                rowMax = max(rowMax, node->val);
+                if (node->left) q.push(node->left);
+                if (node->right) q.push(node->right);
+            }
+            res.push_back(rowMax);
+        }
+
+        return res;
+    }
+};
+```
+
+```javascript
+/**
+ * Definition for a binary tree node.
+ * class TreeNode {
+ *     constructor(val = 0, left = null, right = null) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+class Solution {
+    /**
+     * @param {TreeNode} root
+     * @return {number[]}
+     */
+    largestValues(root) {
+        if (!root) return [];
+
+        const res = [];
+        const q = new Queue([root]);
+
+        while (!q.isEmpty()) {
+            let rowMax = q.front().val;
+            for (let i = q.size(); i > 0; i--) {
+                const node = q.pop();
+                rowMax = Math.max(rowMax, node.val);
+                if (node.left) q.push(node.left);
+                if (node.right) q.push(node.right);
+            }
+            res.push(rowMax);
+        }
+
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(n)$
+
+---
+
+## 2. Depth First Search
+
+::tabs-start
+
+```python
+# Definition for a binary tree node.
+# class TreeNode:
+#     def __init__(self, val=0, left=None, right=None):
+#         self.val = val
+#         self.left = left
+#         self.right = right
+class Solution:
+    def largestValues(self, root: Optional[TreeNode]) -> List[int]:
+        if not root:
+            return []
+
+        res = []
+        def dfs(node, level):
+            if not node:
+                return
+            if level == len(res):
+                res.append(node.val)
+            else:
+                res[level] = max(res[level], node.val)
+
+            dfs(node.left, level + 1)
+            dfs(node.right, level + 1)
+
+        dfs(root, 0)
+        return res
+```
+
+```java
+/**
+ * Definition for a binary tree node.
+ * public class TreeNode {
+ *     int val;
+ *     TreeNode left;
+ *     TreeNode right;
+ *     TreeNode() {}
+ *     TreeNode(int val) { this.val = val; }
+ *     TreeNode(int val, TreeNode left, TreeNode right) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+public class Solution {
+    public List<Integer> largestValues(TreeNode root) {
+        List<Integer> res = new ArrayList<>();
+        dfs(root, 0, res);
+        return res;
+    }
+
+    private void dfs(TreeNode node, int level, List<Integer> res) {
+        if (node == null) return;
+        if (level == res.size()) {
+            res.add(node.val);
+        } else {
+            res.set(level, Math.max(res.get(level), node.val));
+        }
+
+        dfs(node.left, level + 1, res);
+        dfs(node.right, level + 1, res);
+    }
+}
+```
+
+```cpp
+/**
+ * Definition for a binary tree node.
+ * struct TreeNode {
+ *     int val;
+ *     TreeNode *left;
+ *     TreeNode *right;
+ *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
+ * };
+ */
+class Solution {
+public:
+    vector<int> largestValues(TreeNode* root) {
+        vector<int> res;
+        dfs(root, 0, res);
+        return res;
+    }
+
+private:
+    void dfs(TreeNode* node, int level, vector<int>& res) {
+        if (!node) return;
+        if (level == res.size()) {
+            res.push_back(node->val);
+        } else {
+            res[level] = max(res[level], node->val);
+        }
+
+        dfs(node->left, level + 1, res);
+        dfs(node->right, level + 1, res);
+    }
+};
+```
+
+```javascript
+/**
+ * Definition for a binary tree node.
+ * class TreeNode {
+ *     constructor(val = 0, left = null, right = null) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+class Solution {
+    /**
+     * @param {TreeNode} root
+     * @return {number[]}
+     */
+    largestValues(root) {
+        if (!root) return [];
+
+        const res = [];
+        const dfs = (node, level) => {
+            if (!node) return;
+            if (level === res.length) {
+                res.push(node.val);
+            } else {
+                res[level] = Math.max(res[level], node.val);
+            }
+            dfs(node.left, level + 1);
+            dfs(node.right, level + 1);
+        };
+
+        dfs(root, 0);
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(n)$ for recursion stack.
+
+---
+
+## 3. Iterative DFS
+
+::tabs-start
+
+```python
+# Definition for a binary tree node.
+# class TreeNode:
+#     def __init__(self, val=0, left=None, right=None):
+#         self.val = val
+#         self.left = left
+#         self.right = right
+class Solution:
+    def largestValues(self, root: Optional[TreeNode]) -> List[int]:
+        if not root:
+            return []
+
+        res = []
+        stack = [(root, 0)]
+        while stack:
+            node, level = stack.pop()
+            if level == len(res):
+                res.append(node.val)
+            else:
+                res[level] = max(res[level], node.val)
+
+            if node.right:
+                stack.append((node.right, level + 1))
+            if node.left:
+                stack.append((node.left, level + 1))
+
+        return res
+```
+
+```java
+/**
+ * Definition for a binary tree node.
+ * public class TreeNode {
+ *     int val;
+ *     TreeNode left;
+ *     TreeNode right;
+ *     TreeNode() {}
+ *     TreeNode(int val) { this.val = val; }
+ *     TreeNode(int val, TreeNode left, TreeNode right) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+public class Solution {
+    public List<Integer> largestValues(TreeNode root) {
+        if (root == null) return new ArrayList<>();
+
+        List<Integer> res = new ArrayList<>();
+        Stack<Pair<TreeNode, Integer>> stack = new Stack<>();
+        stack.push(new Pair<>(root, 0));
+        while (!stack.isEmpty()) {
+            Pair<TreeNode, Integer> p = stack.pop();
+            TreeNode node = p.getKey();
+            int level = p.getValue();
+            if (level == res.size()) {
+                res.add(node.val);
+            } else {
+                res.set(level, Math.max(res.get(level), node.val));
+            }
+
+            if (node.right != null) stack.push(new Pair<>(node.right, level + 1));
+            if (node.left != null) stack.push(new Pair<>(node.left, level + 1));
+        }
+
+        return res;
+    }
+}
+```
+
+```cpp
+/**
+ * Definition for a binary tree node.
+ * struct TreeNode {
+ *     int val;
+ *     TreeNode *left;
+ *     TreeNode *right;
+ *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
+ * };
+ */
+class Solution {
+public:
+    vector<int> largestValues(TreeNode* root) {
+        if (!root) return {};
+
+        vector<int> res;
+        stack<pair<TreeNode*, int>> stk;
+        stk.push({root, 0});
+        while (!stk.empty()) {
+            auto [node, level] = stk.top();stk.pop();
+            if (level == res.size()) {
+                res.push_back(node->val);
+            } else {
+                res[level] = max(res[level], node->val);
+            }
+
+            if (node->right) stk.push({node->right, level + 1});
+            if (node->left) stk.push({node->left, level + 1});
+        }
+
+        return res;
+    }
+};
+```
+
+```javascript
+/**
+ * Definition for a binary tree node.
+ * class TreeNode {
+ *     constructor(val = 0, left = null, right = null) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+class Solution {
+    /**
+     * @param {TreeNode} root
+     * @return {number[]}
+     */
+    largestValues(root) {
+        if (!root) return [];
+
+        const res = [];
+        const stack = [[root, 0]];
+        while (stack.length) {
+            const [node, level] = stack.pop();
+            if (level === res.length) {
+                res.push(node.val);
+            } else {
+                res[level] = Math.max(res[level], node.val);
+            }
+
+            if (node.right) stack.push([node.right, level + 1]);
+            if (node.left) stack.push([node.left, level + 1]);
+        }
+
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(n)$
\ No newline at end of file
diff --git a/articles/flip-equivalent-binary-trees.md b/articles/flip-equivalent-binary-trees.md
new file mode 100644
index 000000000..2a2549798
--- /dev/null
+++ b/articles/flip-equivalent-binary-trees.md
@@ -0,0 +1,492 @@
+## 1. Depth First Search
+
+::tabs-start
+
+```python
+# Definition for a binary tree node.
+# class TreeNode:
+#     def __init__(self, val=0, left=None, right=None):
+#         self.val = val
+#         self.left = left
+#         self.right = right
+class Solution:
+    def flipEquiv(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> bool:
+        if not root1 or not root2:
+            return not root1 and not root2
+        if root1.val != root2.val:
+            return False
+
+        return (
+                self.flipEquiv(root1.left, root2.left) and 
+                self.flipEquiv(root1.right, root2.right) or
+                self.flipEquiv(root1.left, root2.right) and 
+                self.flipEquiv(root1.right, root2.left)
+            )
+```
+
+```java
+/**
+ * Definition for a binary tree node.
+ * public class TreeNode {
+ *     int val;
+ *     TreeNode left;
+ *     TreeNode right;
+ *     TreeNode() {}
+ *     TreeNode(int val) { this.val = val; }
+ *     TreeNode(int val, TreeNode left, TreeNode right) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+public class Solution {
+    public boolean flipEquiv(TreeNode root1, TreeNode root2) {
+        if (root1 == null || root2 == null) 
+            return root1 == null && root2 == null;
+        if (root1.val != root2.val) 
+            return false;
+        
+        return (flipEquiv(root1.left, root2.left) && 
+                flipEquiv(root1.right, root2.right) ||
+                flipEquiv(root1.left, root2.right) && 
+                flipEquiv(root1.right, root2.left));
+    }
+}
+```
+
+```cpp
+/**
+ * Definition for a binary tree node.
+ * struct TreeNode {
+ *     int val;
+ *     TreeNode *left;
+ *     TreeNode *right;
+ *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
+ * };
+ */
+class Solution {
+public:
+    bool flipEquiv(TreeNode* root1, TreeNode* root2) {
+        if (!root1 || !root2) 
+            return !root1 && !root2;
+        if (root1->val != root2->val) 
+            return false;
+        
+        return (flipEquiv(root1->left, root2->left) && 
+                flipEquiv(root1->right, root2->right) ||
+                flipEquiv(root1->left, root2->right) && 
+                flipEquiv(root1->right, root2->left));
+    }
+};
+```
+
+```javascript
+/**
+ * Definition for a binary tree node.
+ * class TreeNode {
+ *     constructor(val = 0, left = null, right = null) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+class Solution {
+    /**
+     * @param {TreeNode} root1
+     * @param {TreeNode} root2
+     * @return {boolean}
+     */
+    flipEquiv(root1, root2) {
+        if (!root1 || !root2) 
+            return !root1 && !root2;
+        if (root1.val !== root2.val) 
+            return false;
+        
+        return (this.flipEquiv(root1.left, root2.left) && 
+                this.flipEquiv(root1.right, root2.right) ||
+                this.flipEquiv(root1.left, root2.right) && 
+                this.flipEquiv(root1.right, root2.left));
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(n)$ for recursion stack.
+
+---
+
+## 2. Breadth First Search
+
+::tabs-start
+
+```python
+# Definition for a binary tree node.
+# class TreeNode:
+#     def __init__(self, val=0, left=None, right=None):
+#         self.val = val
+#         self.left = left
+#         self.right = right
+class Solution:
+    def flipEquiv(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> bool:
+        q = deque([(root1, root2)])
+
+        while q:
+            node1, node2 = q.popleft()
+            if not node1 or not node2:
+                if node1 != node2:
+                    return False
+                continue
+            
+            if node1.val != node2.val:
+                return False
+
+            if ((node1.right and node2.right and 
+                 node1.right.val == node2.right.val) or 
+                (not node1.right and not node2.right)
+            ):
+                q.append((node1.left, node2.left))
+                q.append((node1.right, node2.right))
+            else:
+                q.append((node1.left, node2.right))
+                q.append((node1.right, node2.left))
+
+        return True
+```
+
+```java
+/**
+ * Definition for a binary tree node.
+ * public class TreeNode {
+ *     int val;
+ *     TreeNode left;
+ *     TreeNode right;
+ *     TreeNode() {}
+ *     TreeNode(int val) { this.val = val; }
+ *     TreeNode(int val, TreeNode left, TreeNode right) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+public class Solution {
+    public boolean flipEquiv(TreeNode root1, TreeNode root2) {
+        Queue<TreeNode[]> q = new LinkedList<>();
+        q.offer(new TreeNode[]{root1, root2});
+
+        while (!q.isEmpty()) {
+            TreeNode[] pair = q.poll();
+            TreeNode node1 = pair[0], node2 = pair[1];
+
+            if (node1 == null || node2 == null) {
+                if (node1 != node2) return false;
+                continue;
+            }
+
+            if (node1.val != node2.val) return false;
+
+            if ((node1.left != null && node2.left != null && 
+                 node1.left.val == node2.left.val) || 
+                (node1.left == null && node2.left == null)) {
+                q.offer(new TreeNode[]{node1.left, node2.left});
+                q.offer(new TreeNode[]{node1.right, node2.right});
+            } else {
+                q.offer(new TreeNode[]{node1.left, node2.right});
+                q.offer(new TreeNode[]{node1.right, node2.left});
+            }
+        }
+
+        return true;
+    }
+}
+```
+
+```cpp
+/**
+ * Definition for a binary tree node.
+ * struct TreeNode {
+ *     int val;
+ *     TreeNode *left;
+ *     TreeNode *right;
+ *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
+ * };
+ */
+class Solution {
+public:
+    bool flipEquiv(TreeNode* root1, TreeNode* root2) {
+        queue<pair<TreeNode*, TreeNode*>> q;
+        q.push({root1, root2});
+
+        while (!q.empty()) {
+            auto [node1, node2] = q.front();
+            q.pop();
+
+            if (!node1 || !node2) {
+                if (node1 != node2) return false;
+                continue;
+            }
+
+            if (node1->val != node2->val) return false;
+
+            if ((node1->left && node2->left && node1->left->val == node2->left->val) || 
+                (!node1->left && !node2->left)) {
+                q.push({node1->left, node2->left});
+                q.push({node1->right, node2->right});
+            } else {
+                q.push({node1->left, node2->right});
+                q.push({node1->right, node2->left});
+            }
+        }
+
+        return true;
+    }
+};
+```
+
+```javascript
+/**
+ * Definition for a binary tree node.
+ * class TreeNode {
+ *     constructor(val = 0, left = null, right = null) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+class Solution {
+    /**
+     * @param {TreeNode} root1
+     * @param {TreeNode} root2
+     * @return {boolean}
+     */
+    flipEquiv(root1, root2) {
+        let q = new Queue([[root1, root2]]);
+
+        while (!q.isEmpty()) {
+            let [node1, node2] = q.pop();
+
+            if (!node1 || !node2) {
+                if (node1 !== node2) return false;
+                continue;
+            }
+
+            if (node1.val !== node2.val) return false;
+
+            if ((node1.left && node2.left && 
+                node1.left.val === node2.left.val) || 
+                (!node1.left && !node2.left)) {
+                q.push([node1.left, node2.left]);
+                q.push([node1.right, node2.right]);
+            } else {
+                q.push([node1.left, node2.right]);
+                q.push([node1.right, node2.left]);
+            }
+        }
+
+        return true;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(n)$
+
+---
+
+## 3. Iterative DFS
+
+::tabs-start
+
+```python
+# Definition for a binary tree node.
+# class TreeNode:
+#     def __init__(self, val=0, left=None, right=None):
+#         self.val = val
+#         self.left = left
+#         self.right = right
+class Solution:
+    def flipEquiv(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> bool:
+        stack = [(root1, root2)]
+
+        while stack:
+            node1, node2 = stack.pop()
+
+            if not node1 or not node2:
+                if node1 != node2:
+                    return False
+                continue
+
+            if node1.val != node2.val:
+                return False
+
+            if ((node1.left and node2.left and 
+                 node1.left.val == node2.left.val) or 
+                (not node1.left and not node2.left)
+            ):
+                stack.append((node1.left, node2.left))
+                stack.append((node1.right, node2.right))
+            else:
+                stack.append((node1.left, node2.right))
+                stack.append((node1.right, node2.left))
+
+        return True
+```
+
+```java
+/**
+ * Definition for a binary tree node.
+ * public class TreeNode {
+ *     int val;
+ *     TreeNode left;
+ *     TreeNode right;
+ *     TreeNode() {}
+ *     TreeNode(int val) { this.val = val; }
+ *     TreeNode(int val, TreeNode left, TreeNode right) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+public class Solution {
+    public boolean flipEquiv(TreeNode root1, TreeNode root2) {
+        Stack<TreeNode[]> stack = new Stack<>();
+        stack.push(new TreeNode[]{root1, root2});
+
+        while (!stack.isEmpty()) {
+            TreeNode[] pair = stack.pop();
+            TreeNode node1 = pair[0], node2 = pair[1];
+
+            if (node1 == null || node2 == null) {
+                if (node1 != node2) return false;
+                continue;
+            }
+
+            if (node1.val != node2.val) return false;
+
+            if ((node1.left != null && node2.left != null && 
+                 node1.left.val == node2.left.val) || 
+                (node1.left == null && node2.left == null)) {
+                stack.push(new TreeNode[]{node1.left, node2.left});
+                stack.push(new TreeNode[]{node1.right, node2.right});
+            } else {
+                stack.push(new TreeNode[]{node1.left, node2.right});
+                stack.push(new TreeNode[]{node1.right, node2.left});
+            }
+        }
+
+        return true;
+    }
+}
+```
+
+```cpp
+/**
+ * Definition for a binary tree node.
+ * struct TreeNode {
+ *     int val;
+ *     TreeNode *left;
+ *     TreeNode *right;
+ *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
+ * };
+ */
+class Solution {
+public:
+    bool flipEquiv(TreeNode* root1, TreeNode* root2) {
+        stack<pair<TreeNode*, TreeNode*>> stk;
+        stk.push({root1, root2});
+
+        while (!stk.empty()) {
+            auto [node1, node2] = stk.top();stk.pop();
+
+            if (!node1 || !node2) {
+                if (node1 != node2) return false;
+                continue;
+            }
+
+            if (node1->val != node2->val) return false;
+
+            if ((node1->left && node2->left && node1->left->val == node2->left->val) || 
+                (!node1->left && !node2->left)) {
+                stk.push({node1->left, node2->left});
+                stk.push({node1->right, node2->right});
+            } else {
+                stk.push({node1->left, node2->right});
+                stk.push({node1->right, node2->left});
+            }
+        }
+
+        return true;
+    }
+};
+```
+
+```javascript
+/**
+ * Definition for a binary tree node.
+ * class TreeNode {
+ *     constructor(val = 0, left = null, right = null) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+class Solution {
+    /**
+     * @param {TreeNode} root1
+     * @param {TreeNode} root2
+     * @return {boolean}
+     */
+    flipEquiv(root1, root2) {
+        let stack = [[root1, root2]];
+
+        while (stack.length > 0) {
+            let [node1, node2] = stack.pop();
+
+            if (!node1 || !node2) {
+                if (node1 !== node2) return false;
+                continue;
+            }
+
+            if (node1.val !== node2.val) return false;
+
+            if ((node1.left && node2.left && 
+                node1.left.val === node2.left.val) || 
+                (!node1.left && !node2.left)) {
+                stack.push([node1.left, node2.left]);
+                stack.push([node1.right, node2.right]);
+            } else {
+                stack.push([node1.left, node2.right]);
+                stack.push([node1.right, node2.left]);
+            }
+        }
+
+        return true;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(n)$
\ No newline at end of file
diff --git a/articles/insertion-sort-list.md b/articles/insertion-sort-list.md
new file mode 100644
index 000000000..a567be9b0
--- /dev/null
+++ b/articles/insertion-sort-list.md
@@ -0,0 +1,411 @@
+## 1. Convert To Array
+
+::tabs-start
+
+```python
+# Definition for singly-linked list.
+# class ListNode:
+#     def __init__(self, val=0, next=None):
+#         self.val = val
+#         self.next = next
+class Solution:
+    def insertionSortList(self, head: Optional[ListNode]) -> Optional[ListNode]:
+        arr = []
+        cur = head
+        while cur:
+            arr.append(cur.val)
+            cur = cur.next
+
+        arr.sort()
+        cur = head
+        for val in arr:
+            cur.val = val
+            cur = cur.next
+        return head
+```
+
+```java
+/**
+ * Definition for singly-linked list.
+ * public class ListNode {
+ *     int val;
+ *     ListNode next;
+ *     ListNode() {}
+ *     ListNode(int val) { this.val = val; }
+ *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
+ * }
+ */
+public class Solution {
+    public ListNode insertionSortList(ListNode head) {
+        List<Integer> arr = new ArrayList<>();
+        ListNode cur = head;
+
+        while (cur != null) {
+            arr.add(cur.val);
+            cur = cur.next;
+        }
+
+        Collections.sort(arr);
+        cur = head;
+
+        for (int val : arr) {
+            cur.val = val;
+            cur = cur.next;
+        }
+        return head;
+    }
+}
+```
+
+```cpp
+/**
+ * Definition for singly-linked list.
+ * struct ListNode {
+ *     int val;
+ *     ListNode *next;
+ *     ListNode() : val(0), next(nullptr) {}
+ *     ListNode(int x) : val(x), next(nullptr) {}
+ *     ListNode(int x, ListNode *next) : val(x), next(next) {}
+ * };
+ */
+class Solution {
+public:
+    ListNode* insertionSortList(ListNode* head) {
+        vector<int> arr;
+        ListNode* cur = head;
+
+        while (cur) {
+            arr.push_back(cur->val);
+            cur = cur->next;
+        }
+
+        sort(arr.begin(), arr.end());
+        cur = head;
+
+        for (int val : arr) {
+            cur->val = val;
+            cur = cur->next;
+        }
+        return head;
+    }
+};
+```
+
+```javascript
+/**
+ * Definition for singly-linked list.
+ * class ListNode {
+ *     constructor(val = 0, next = null) {
+ *         this.val = val;
+ *         this.next = next;
+ *     }
+ * }
+ */
+class Solution {
+    /**
+     * @param {ListNode} head
+     * @return {ListNode}
+     */
+    insertionSortList(head) {
+        let arr = [];
+        let cur = head;
+
+        while (cur) {
+            arr.push(cur.val);
+            cur = cur.next;
+        }
+
+        arr.sort((a, b) => a - b);
+        cur = head;
+
+        for (let val of arr) {
+            cur.val = val;
+            cur = cur.next;
+        }
+        return head;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n \log n)$
+* Space complexity: $O(n)$
+
+---
+
+## 2. Swapping Values
+
+::tabs-start
+
+```python
+# Definition for singly-linked list.
+# class ListNode:
+#     def __init__(self, val=0, next=None):
+#         self.val = val
+#         self.next = next
+class Solution:
+    def insertionSortList(self, head: Optional[ListNode]) -> Optional[ListNode]:
+        cur = head.next
+        while cur:
+            tmp = head
+            while tmp != cur:
+                if tmp.val > cur.val:
+                    tmp.val, cur.val = cur.val, tmp.val
+                tmp = tmp.next
+            cur = cur.next
+        return head
+```
+
+```java
+/**
+ * Definition for singly-linked list.
+ * public class ListNode {
+ *     int val;
+ *     ListNode next;
+ *     ListNode() {}
+ *     ListNode(int val) { this.val = val; }
+ *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
+ * }
+ */
+public class Solution {
+    public ListNode insertionSortList(ListNode head) {
+        for (ListNode cur = head.next; cur != null; cur = cur.next) {
+            for (ListNode tmp = head; tmp != cur; tmp = tmp.next) {
+                if (tmp.val > cur.val) {
+                    int swap = tmp.val;
+                    tmp.val = cur.val;
+                    cur.val = swap;
+                }
+            }
+        }
+        return head;
+    }
+}
+```
+
+```cpp
+/**
+ * Definition for singly-linked list.
+ * struct ListNode {
+ *     int val;
+ *     ListNode *next;
+ *     ListNode() : val(0), next(nullptr) {}
+ *     ListNode(int x) : val(x), next(nullptr) {}
+ *     ListNode(int x, ListNode *next) : val(x), next(next) {}
+ * };
+ */
+class Solution {
+public:
+    ListNode* insertionSortList(ListNode* head) {
+        for (ListNode* cur = head->next; cur; cur = cur->next) {
+            for (ListNode* tmp = head; tmp != cur; tmp = tmp->next) {
+                if (tmp->val > cur->val) {
+                    swap(tmp->val, cur->val);
+                }
+            }
+        }
+        return head;
+    }
+};
+```
+
+```javascript
+/**
+ * Definition for singly-linked list.
+ * class ListNode {
+ *     constructor(val = 0, next = null) {
+ *         this.val = val;
+ *         this.next = next;
+ *     }
+ * }
+ */
+class Solution {
+    /**
+     * @param {ListNode} head
+     * @return {ListNode}
+     */
+    insertionSortList(head) {
+        for (let cur = head.next; cur; cur = cur.next) {
+            for (let tmp = head; tmp !== cur; tmp = tmp.next) {
+                if (tmp.val > cur.val) {
+                    [tmp.val, cur.val] = [cur.val, tmp.val];
+                }
+            }
+        }
+        return head;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n ^ 2)$
+* Space complexity: $O(1)$ extra space.
+
+---
+
+## 3. Swapping Nodes
+
+::tabs-start
+
+```python
+# Definition for singly-linked list.
+# class ListNode:
+#     def __init__(self, val=0, next=None):
+#         self.val = val
+#         self.next = next
+class Solution:
+    def insertionSortList(self, head: Optional[ListNode]) -> Optional[ListNode]:
+        dummy = ListNode(0, head)
+        prev, cur = head, head.next
+
+        while cur:
+            if cur.val >= prev.val:
+                prev, cur = cur, cur.next
+                continue
+            
+            tmp = dummy
+            while cur.val > tmp.next.val:
+                tmp = tmp.next
+            
+            prev.next = cur.next
+            cur.next = tmp.next
+            tmp.next = cur
+            cur = prev.next
+
+        return dummy.next
+```
+
+```java
+/**
+ * Definition for singly-linked list.
+ * public class ListNode {
+ *     int val;
+ *     ListNode next;
+ *     ListNode() {}
+ *     ListNode(int val) { this.val = val; }
+ *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
+ * }
+ */
+public class Solution {
+    public ListNode insertionSortList(ListNode head) {
+        ListNode dummy = new ListNode(0, head);
+        ListNode prev = head, cur = head.next;
+
+        while (cur != null) {
+            if (cur.val >= prev.val) {
+                prev = cur;
+                cur = cur.next;
+                continue;
+            }
+
+            ListNode tmp = dummy;
+            while (tmp.next.val < cur.val) {
+                tmp = tmp.next;
+            }
+
+            prev.next = cur.next;
+            cur.next = tmp.next;
+            tmp.next = cur;
+            cur = prev.next;
+        }
+
+        return dummy.next;
+    }
+}
+```
+
+```cpp
+/**
+ * Definition for singly-linked list.
+ * struct ListNode {
+ *     int val;
+ *     ListNode *next;
+ *     ListNode() : val(0), next(nullptr) {}
+ *     ListNode(int x) : val(x), next(nullptr) {}
+ *     ListNode(int x, ListNode *next) : val(x), next(next) {}
+ * };
+ */
+class Solution {
+public:
+    ListNode* insertionSortList(ListNode* head) {
+        ListNode* dummy = new ListNode(0, head);
+        ListNode* prev = head;
+        ListNode* cur = head->next;
+
+        while (cur) {
+            if (cur->val >= prev->val) {
+                prev = cur;
+                cur = cur->next;
+                continue;
+            }
+
+            ListNode* tmp = dummy;
+            while (tmp->next->val < cur->val) {
+                tmp = tmp->next;
+            }
+
+            prev->next = cur->next;
+            cur->next = tmp->next;
+            tmp->next = cur;
+            cur = prev->next;
+        }
+
+        return dummy->next;
+    }
+};
+```
+
+```javascript
+/**
+ * Definition for singly-linked list.
+ * class ListNode {
+ *     constructor(val = 0, next = null) {
+ *         this.val = val;
+ *         this.next = next;
+ *     }
+ * }
+ */
+class Solution {
+    /**
+     * @param {ListNode} head
+     * @return {ListNode}
+     */
+    insertionSortList(head) {
+        let dummy = new ListNode(0, head);
+        let prev = head, cur = head.next;
+
+        while (cur) {
+            if (cur.val >= prev.val) {
+                prev = cur;
+                cur = cur.next;
+                continue;
+            }
+
+            let tmp = dummy;
+            while (tmp.next.val < cur.val) {
+                tmp = tmp.next;
+            }
+
+            prev.next = cur.next;
+            cur.next = tmp.next;
+            tmp.next = cur;
+            cur = prev.next;
+        }
+
+        return dummy.next;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n ^ 2)$
+* Space complexity: $O(1)$ extra space.
\ No newline at end of file
diff --git a/articles/minimum-fuel-cost-to-report-to-the-capital.md b/articles/minimum-fuel-cost-to-report-to-the-capital.md
new file mode 100644
index 000000000..77dda576e
--- /dev/null
+++ b/articles/minimum-fuel-cost-to-report-to-the-capital.md
@@ -0,0 +1,299 @@
+## 1. Depth First Search
+
+::tabs-start
+
+```python
+class Solution:
+    def minimumFuelCost(self, roads: list[list[int]], seats: int) -> int:
+        adj = defaultdict(list)
+        for src, dst in roads:
+            adj[src].append(dst)
+            adj[dst].append(src)
+
+        res = 0
+        def dfs(node, parent):
+            nonlocal res
+            passengers = 0
+            for child in adj[node]:
+                if child != parent:
+                    p = dfs(child, node)
+                    passengers += p
+                    res += ceil(p / seats)
+            return passengers + 1
+
+        dfs(0, -1)
+        return res
+```
+
+```java
+public class Solution {
+    private List<Integer>[] adj;
+    private long res = 0;
+
+    public long minimumFuelCost(int[][] roads, int seats) {
+        int n = roads.length + 1;
+        adj = new ArrayList[n];
+
+        for (int i = 0; i < n; i++) {
+            adj[i] = new ArrayList<>();
+        }
+
+        for (int[] road : roads) {
+            adj[road[0]].add(road[1]);
+            adj[road[1]].add(road[0]);
+        }
+
+        dfs(0, -1, seats);
+        return res;
+    }
+
+    private int dfs(int node, int parent, int seats) {
+        int passengers = 0;
+        for (int child : adj[node]) {
+            if (child != parent) {
+                int p = dfs(child, node, seats);
+                passengers += p;
+                res += Math.ceil((double) p / seats);
+            }
+        }
+        return passengers + 1;
+    }
+}
+```
+
+```cpp
+class Solution {
+private:
+    vector<vector<int>> adj;
+    long long res = 0;
+
+public:
+    long long minimumFuelCost(vector<vector<int>>& roads, int seats) {
+        int n = roads.size() + 1;
+        adj.resize(n);
+
+        for (auto& road : roads) {
+            adj[road[0]].push_back(road[1]);
+            adj[road[1]].push_back(road[0]);
+        }
+
+        dfs(0, -1, seats);
+        return res;
+    }
+
+private:
+    int dfs(int node, int parent, int seats) {
+        int passengers = 0;
+        for (int child : adj[node]) {
+            if (child != parent) {
+                int p = dfs(child, node, seats);
+                passengers += p;
+                res += ceil((double) p / seats);
+            }
+        }
+        return passengers + 1;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} roads
+     * @param {number} seats
+     * @return {number}
+     */
+    minimumFuelCost(roads, seats) {
+        const n = roads.length + 1;
+        const adj = Array.from({ length: n }, () => []);
+        let res = 0;
+
+        for (const [src, dst] of roads) {
+            adj[src].push(dst);
+            adj[dst].push(src);
+        }
+
+        const dfs = (node, parent) => {
+            let passengers = 0;
+            for (const child of adj[node]) {
+                if (child !== parent) {
+                    let p = dfs(child, node);
+                    passengers += p;
+                    res += Math.ceil(p / seats);
+                }
+            }
+            return passengers + 1;
+        };
+
+        dfs(0, -1);
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(n)$
+
+---
+
+## 2. Topological Sort (Kahn's Algorithm)
+
+::tabs-start
+
+```python
+class Solution:
+    def minimumFuelCost(self, roads: list[list[int]], seats: int) -> int:
+        n = len(roads) + 1
+        adj = [[] for _ in range(n)]
+        indegree = [0] * n
+        passengers = [1] * n
+        res = 0
+
+        for src, dst in roads:
+            adj[src].append(dst)
+            adj[dst].append(src)
+            indegree[src] += 1
+            indegree[dst] += 1
+
+        q = deque()
+        for i in range(1, n):
+            if indegree[i] == 1:
+                q.append(i)
+
+        while q:
+            node = q.popleft()
+            res += math.ceil(passengers[node] / seats)
+            for parent in adj[node]:
+                indegree[parent] -= 1
+                if indegree[parent] == 1 and parent != 0:
+                    q.append(parent)
+                passengers[parent] += passengers[node]
+
+        return res
+```
+
+```java
+public class Solution {
+    public long minimumFuelCost(int[][] roads, int seats) {
+        int n = roads.length + 1;
+        List<Integer>[] adj = new ArrayList[n];
+        int[] indegree = new int[n];
+        int[] passengers = new int[n];
+        Arrays.fill(passengers, 1);
+        long res = 0;
+
+        for (int i = 0; i < n; i++) adj[i] = new ArrayList<>();
+
+        for (int[] road : roads) {
+            int src = road[0], dst = road[1];
+            adj[src].add(dst);
+            adj[dst].add(src);
+            indegree[src]++;
+            indegree[dst]++;
+        }
+
+        Queue<Integer> q = new LinkedList<>();
+        for (int i = 1; i < n; i++) {
+            if (indegree[i] == 1) q.offer(i);
+        }
+
+        while (!q.isEmpty()) {
+            int node = q.poll();
+            res += (int) Math.ceil((double) passengers[node] / seats);
+            for (int parent : adj[node]) {
+                if (--indegree[parent] == 1 && parent != 0) q.offer(parent);
+                passengers[parent] += passengers[node];
+            }
+        }
+
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    long long minimumFuelCost(vector<vector<int>>& roads, int seats) {
+        int n = roads.size() + 1;
+        vector<vector<int>> adj(n);
+        vector<int> indegree(n, 0), passengers(n, 1);
+        long long res = 0;
+
+        for (auto& road : roads) {
+            int src = road[0], dst = road[1];
+            adj[src].push_back(dst);
+            adj[dst].push_back(src);
+            indegree[src]++;
+            indegree[dst]++;
+        }
+
+        queue<int> q;
+        for (int i = 1; i < n; i++) {
+            if (indegree[i] == 1) q.push(i);
+        }
+
+        while (!q.empty()) {
+            int node = q.front();q.pop();
+            res += ceil((double) passengers[node] / seats);
+            for (int parent : adj[node]) {
+                if (--indegree[parent] == 1 && parent != 0) q.push(parent);
+                passengers[parent] += passengers[node];
+            }
+        }
+
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} roads
+     * @param {number} seats
+     * @return {number}
+     */
+    minimumFuelCost(roads, seats) {
+        const n = roads.length + 1;
+        const adj = Array.from({ length: n }, () => []);
+        const indegree = new Array(n).fill(0);
+        const passengers = new Array(n).fill(1);
+        let res = 0;
+
+        for (const [src, dst] of roads) {
+            adj[src].push(dst);
+            adj[dst].push(src);
+            indegree[src] += 1;
+            indegree[dst] += 1;
+        }
+
+        const q = new Queue();
+        for (let i = 1; i < n; i++) {
+            if (indegree[i] === 1) q.push(i);
+        }
+
+        while (!q.isEmpty()) {
+            const node = q.pop();
+            res += Math.ceil(passengers[node] / seats);
+            for (const parent of adj[node]) {
+                if (--indegree[parent] === 1 && parent !== 0) q.push(parent);
+                passengers[parent] += passengers[node];
+            }
+        }
+
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(n)$
\ No newline at end of file
diff --git a/articles/minimum-score-of-a-path-between-two-cities.md b/articles/minimum-score-of-a-path-between-two-cities.md
new file mode 100644
index 000000000..820b21739
--- /dev/null
+++ b/articles/minimum-score-of-a-path-between-two-cities.md
@@ -0,0 +1,646 @@
+## 1. Depth First Search
+
+::tabs-start
+
+```python
+class Solution:
+    def minScore(self, n: int, roads: list[list[int]]) -> int:
+        adj = defaultdict(list)
+        for src, dst, dist in roads:
+            adj[src].append((dst, dist))
+            adj[dst].append((src, dist))
+
+        res = float("inf")
+        visit = set()
+
+        def dfs(node):
+            nonlocal res
+            if node in visit:
+                return
+            visit.add(node)
+            for nei, dist in adj[node]:
+                res = min(res, dist)
+                dfs(nei)
+
+        dfs(1)
+        return res
+```
+
+```java
+public class Solution {
+    private List<int[]>[] adj;
+    private boolean[] visit;
+    private int res;
+
+    public int minScore(int n, int[][] roads) {
+        adj = new ArrayList[n + 1];
+        visit = new boolean[n + 1];
+        res = Integer.MAX_VALUE;
+
+        for (int i = 0; i <= n; i++) {
+            adj[i] = new ArrayList<>();
+        }
+
+        for (int[] road : roads) {
+            adj[road[0]].add(new int[]{road[1], road[2]});
+            adj[road[1]].add(new int[]{road[0], road[2]});
+        }
+
+        dfs(1);
+        return res;
+    }
+
+    private void dfs(int node) {
+        if (visit[node]) return;
+        visit[node] = true;
+
+        for (int[] edge : adj[node]) {
+            res = Math.min(res, edge[1]);
+            dfs(edge[0]);
+        }
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    vector<vector<pair<int, int>>> adj;
+    vector<bool> visit;
+    int res;
+
+    int minScore(int n, vector<vector<int>>& roads) {
+        adj.resize(n + 1);
+        visit.resize(n + 1, false);
+        res = INT_MAX;
+
+        for (auto& road : roads) {
+            adj[road[0]].push_back({road[1], road[2]});
+            adj[road[1]].push_back({road[0], road[2]});
+        }
+
+        dfs(1);
+        return res;
+    }
+
+    void dfs(int node) {
+        if (visit[node]) return;
+        visit[node] = true;
+
+        for (auto& edge : adj[node]) {
+            res = min(res, edge.second);
+            dfs(edge.first);
+        }
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number} n
+     * @param {number[][]} roads
+     * @return {number}
+     */
+    minScore(n, roads) {
+        const adj = Array.from({ length: n + 1 }, () => []);
+        for (const [src, dst, dist] of roads) {
+            adj[src].push([dst, dist]);
+            adj[dst].push([src, dist]);
+        }
+
+        let res = Infinity;
+        const visit = new Array(n + 1).fill(false);
+
+        const dfs = (node) => {
+            if (visit[node]) return;
+            visit[node] = true;
+
+            for (const [nei, dist] of adj[node]) {
+                res = Math.min(res, dist);
+                dfs(nei);
+            }
+        };
+
+        dfs(1);
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(V + E)$
+* Space complexity: $O(V + E)$
+
+> Where $V$ is the number of vertices and $E$ is the number of edges.
+
+---
+
+## 2. Breadth First Search
+
+::tabs-start
+
+```python
+class Solution:
+    def minScore(self, n: int, roads: list[list[int]]) -> int:
+        adj = [[] for _ in range(n + 1)]
+        for src, dst, dist in roads:
+            adj[src].append((dst, dist))
+            adj[dst].append((src, dist))
+
+        res = float("inf")
+        visit = [False] * (n + 1)
+        q = deque([1])
+        visit[1] = True
+
+        while q:
+            node = q.popleft()
+            for nei, dist in adj[node]:
+                res = min(res, dist)
+                if not visit[nei]:
+                    visit[nei] = True
+                    q.append(nei)
+
+        return res
+```
+
+```java
+public class Solution {
+    public int minScore(int n, int[][] roads) {
+        List<int[]>[] adj = new ArrayList[n + 1];
+        for (int i = 0; i <= n; i++) adj[i] = new ArrayList<>();
+
+        for (int[] road : roads) {
+            adj[road[0]].add(new int[]{road[1], road[2]});
+            adj[road[1]].add(new int[]{road[0], road[2]});
+        }
+
+        int res = Integer.MAX_VALUE;
+        boolean[] visit = new boolean[n + 1];
+        Queue<Integer> q = new LinkedList<>();
+        q.offer(1);
+        visit[1] = true;
+
+        while (!q.isEmpty()) {
+            int node = q.poll();
+            for (int[] edge : adj[node]) {
+                int nei = edge[0], dist = edge[1];
+                res = Math.min(res, dist);
+                if (!visit[nei]) {
+                    visit[nei] = true;
+                    q.offer(nei);
+                }
+            }
+        }
+
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int minScore(int n, vector<vector<int>>& roads) {
+        vector<vector<pair<int, int>>> adj(n + 1);
+        for (auto& road : roads) {
+            adj[road[0]].emplace_back(road[1], road[2]);
+            adj[road[1]].emplace_back(road[0], road[2]);
+        }
+
+        int res = INT_MAX;
+        vector<bool> visit(n + 1, false);
+        queue<int> q;
+        q.push(1);
+        visit[1] = true;
+
+        while (!q.empty()) {
+            int node = q.front();q.pop();
+            for (auto& [nei, dist] : adj[node]) {
+                res = min(res, dist);
+                if (!visit[nei]) {
+                    visit[nei] = true;
+                    q.push(nei);
+                }
+            }
+        }
+
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number} n
+     * @param {number[][]} roads
+     * @return {number}
+     */
+    minScore(n, roads) {
+        const adj = Array.from({ length: n + 1 }, () => []);
+        for (const [src, dst, dist] of roads) {
+            adj[src].push([dst, dist]);
+            adj[dst].push([src, dist]);
+        }
+
+        let res = Infinity;
+        const visit = new Array(n + 1).fill(false);
+        const q = new Queue([1]);
+        visit[1] = true;
+
+        while (!q.isEmpty()) {
+            const node = q.pop();
+            for (const [nei, dist] of adj[node]) {
+                res = Math.min(res, dist);
+                if (!visit[nei]) {
+                    visit[nei] = true;
+                    q.push(nei);
+                }
+            }
+        }
+
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(V + E)$
+* Space complexity: $O(V + E)$
+
+> Where $V$ is the number of vertices and $E$ is the number of edges.
+
+---
+
+## 3. Iterative DFS
+
+::tabs-start
+
+```python
+class Solution:
+    def minScore(self, n: int, roads: list[list[int]]) -> int:
+        adj = [[] for _ in range(n + 1)]
+        for src, dst, dist in roads:
+            adj[src].append((dst, dist))
+            adj[dst].append((src, dist))
+
+        res = float("inf")
+        visit = [False] * (n + 1)
+        stack = [1]
+        visit[1] = True
+
+        while stack:
+            node = stack.pop()
+            for nei, dist in adj[node]:
+                res = min(res, dist)
+                if not visit[nei]:
+                    visit[nei] = True
+                    stack.append(nei)
+
+        return res
+```
+
+```java
+public class Solution {
+    public int minScore(int n, int[][] roads) {
+        List<int[]>[] adj = new ArrayList[n + 1];
+        for (int i = 0; i <= n; i++) adj[i] = new ArrayList<>();
+
+        for (int[] road : roads) {
+            adj[road[0]].add(new int[]{road[1], road[2]});
+            adj[road[1]].add(new int[]{road[0], road[2]});
+        }
+
+        int res = Integer.MAX_VALUE;
+        boolean[] visit = new boolean[n + 1];
+        Stack<Integer> stack = new Stack<>();
+        stack.push(1);
+        visit[1] = true;
+
+        while (!stack.isEmpty()) {
+            int node = stack.pop();
+            for (int[] edge : adj[node]) {
+                int nei = edge[0], dist = edge[1];
+                res = Math.min(res, dist);
+                if (!visit[nei]) {
+                    visit[nei] = true;
+                    stack.push(nei);
+                }
+            }
+        }
+
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int minScore(int n, vector<vector<int>>& roads) {
+        vector<vector<pair<int, int>>> adj(n + 1);
+        for (auto& road : roads) {
+            adj[road[0]].emplace_back(road[1], road[2]);
+            adj[road[1]].emplace_back(road[0], road[2]);
+        }
+
+        int res = INT_MAX;
+        vector<bool> visit(n + 1, false);
+        stack<int> stk;
+        stk.push(1);
+        visit[1] = true;
+
+        while (!stk.empty()) {
+            int node = stk.top();stk.pop();
+            for (auto& [nei, dist] : adj[node]) {
+                res = min(res, dist);
+                if (!visit[nei]) {
+                    visit[nei] = true;
+                    stk.push(nei);
+                }
+            }
+        }
+
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number} n
+     * @param {number[][]} roads
+     * @return {number}
+     */
+    minScore(n, roads) {
+        const adj = Array.from({ length: n + 1 }, () => []);
+        for (const [src, dst, dist] of roads) {
+            adj[src].push([dst, dist]);
+            adj[dst].push([src, dist]);
+        }
+
+        let res = Infinity;
+        const visit = new Array(n + 1).fill(false);
+        const stack = [1];
+        visit[1] = true;
+
+        while (stack.length) {
+            const node = stack.pop();
+            for (const [nei, dist] of adj[node]) {
+                res = Math.min(res, dist);
+                if (!visit[nei]) {
+                    visit[nei] = true;
+                    stack.push(nei);
+                }
+            }
+        }
+
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(V + E)$
+* Space complexity: $O(V + E)$
+
+> Where $V$ is the number of vertices and $E$ is the number of edges.
+
+---
+
+## 4. Disjoint Set Union
+
+::tabs-start
+
+```python
+class DSU:
+    def __init__(self, n):
+        self.Parent = list(range(n + 1))
+        self.Size = [1] * (n + 1)
+
+    def find(self, node):
+        if self.Parent[node] != node:
+            self.Parent[node] = self.find(self.Parent[node])
+        return self.Parent[node]
+
+    def union(self, u, v):
+        pu, pv = self.find(u), self.find(v)
+        if pu == pv:
+            return False
+        if self.Size[pu] >= self.Size[pv]:
+            self.Size[pu] += self.Size[pv]
+            self.Parent[pv] = pu
+        else:
+            self.Size[pv] += self.Size[pu]
+            self.Parent[pu] = pv
+        return True
+
+class Solution:
+    def minScore(self, n: int, roads: list[list[int]]) -> int:
+        dsu = DSU(n)
+        for src, dst, _ in roads:
+            dsu.union(src, dst)
+
+        res = float("inf")
+        root = dsu.find(1)
+        for src, dst, dist in roads:
+            if dsu.find(src) == root:
+                res = min(res, dist)
+
+        return res
+```
+
+```java
+class DSU {
+    int[] parent, size;
+
+    public DSU(int n) {
+        parent = new int[n + 1];
+        size = new int[n + 1];
+        for (int i = 0; i <= n; i++) {
+            parent[i] = i;
+            size[i] = 1;
+        }
+    }
+
+    public int find(int node) {
+        if (parent[node] != node) {
+            parent[node] = find(parent[node]);
+        }
+        return parent[node];
+    }
+
+    public boolean union(int u, int v) {
+        int pu = find(u), pv = find(v);
+        if (pu == pv) return false;
+        if (size[pu] >= size[pv]) {
+            size[pu] += size[pv];
+            parent[pv] = pu;
+        } else {
+            size[pv] += size[pu];
+            parent[pu] = pv;
+        }
+        return true;
+    }
+}
+
+public class Solution {
+    public int minScore(int n, int[][] roads) {
+        DSU dsu = new DSU(n);
+        for (int[] road : roads) {
+            dsu.union(road[0], road[1]);
+        }
+
+        int res = Integer.MAX_VALUE;
+        int root = dsu.find(1);
+        for (int[] road : roads) {
+            if (dsu.find(road[0]) == root) {
+                res = Math.min(res, road[2]);
+            }
+        }
+
+        return res;
+    }
+}
+```
+
+```cpp
+class DSU {
+public:
+    vector<int> parent, size;
+    
+    DSU(int n) {
+        parent.resize(n + 1);
+        size.resize(n + 1, 1);
+        for (int i = 0; i <= n; i++) {
+            parent[i] = i;
+        }
+    }
+
+    int find(int node) {
+        if (parent[node] != node) {
+            parent[node] = find(parent[node]);
+        }
+        return parent[node];
+    }
+
+    bool unionSets(int u, int v) {
+        int pu = find(u), pv = find(v);
+        if (pu == pv) return false;
+        if (size[pu] >= size[pv]) {
+            size[pu] += size[pv];
+            parent[pv] = pu;
+        } else {
+            size[pv] += size[pu];
+            parent[pu] = pv;
+        }
+        return true;
+    }
+};
+
+class Solution {
+public:
+    int minScore(int n, vector<vector<int>>& roads) {
+        DSU dsu(n);
+        for (auto& road : roads) {
+            dsu.unionSets(road[0], road[1]);
+        }
+
+        int res = INT_MAX;
+        int root = dsu.find(1);
+        for (auto& road : roads) {
+            if (dsu.find(road[0]) == root) {
+                res = min(res, road[2]);
+            }
+        }
+
+        return res;
+    }
+};
+```
+
+```javascript
+class DSU {
+    /**
+     * @constructor
+     * @param {number} n
+     */
+    constructor(n) {
+        this.parent = Array.from({ length: n + 1 }, (_, i) => i);
+        this.size = new Array(n + 1).fill(1);
+    }
+
+    /**
+     * @param {number} node
+     * @return {number}
+     */
+    find(node) {
+        if (this.parent[node] !== node) {
+            this.parent[node] = this.find(this.parent[node]);
+        }
+        return this.parent[node];
+    }
+
+    /**
+     * @param {number} u
+     * @param {number} u=v
+     * @return {boolean}
+     */
+    union(u, v) {
+        let pu = this.find(u), pv = this.find(v);
+        if (pu === pv) return false;
+        if (this.size[pu] >= this.size[pv]) {
+            this.size[pu] += this.size[pv];
+            this.parent[pv] = pu;
+        } else {
+            this.size[pv] += this.size[pu];
+            this.parent[pu] = pv;
+        }
+        return true;
+    }
+}
+
+class Solution {
+    /**
+     * @param {number} n
+     * @param {number[][]} roads
+     * @return {number}
+     */
+    minScore(n, roads) {
+        const dsu = new DSU(n);
+        for (const [src, dst] of roads) {
+            dsu.union(src, dst);
+        }
+
+        let res = Infinity;
+        const root = dsu.find(1);
+        for (const [src, dst, dist] of roads) {
+            if (dsu.find(src) === root) {
+                res = Math.min(res, dist);
+            }
+        }
+
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(V + (E * α(V)))$
+* Space complexity: $O(V)$
+
+> Where $V$ is the number of vertices and $E$ is the number of edges in the graph. $α()$ is used for amortized complexity.
\ No newline at end of file
diff --git a/articles/number-of-closed-islands.md b/articles/number-of-closed-islands.md
new file mode 100644
index 000000000..d3ab68940
--- /dev/null
+++ b/articles/number-of-closed-islands.md
@@ -0,0 +1,836 @@
+## 1. Depth First Search - I
+
+::tabs-start
+
+```python
+class Solution:
+    def closedIsland(self, grid: List[List[int]]) -> int:
+        ROWS, COLS = len(grid), len(grid[0])
+        directions = [[0, 1], [0, -1], [1, 0], [-1, 0]]
+        visit = set()
+
+        def dfs(r, c):
+            if r < 0 or c < 0 or r == ROWS or c == COLS:
+                return 0  # False
+            if grid[r][c] == 1 or (r, c) in visit:
+                return 1  # True
+
+            visit.add((r, c))
+            res = True
+            for dx, dy in directions:
+                if not dfs(r + dx, c + dy):
+                    res = False
+            return res
+
+        res = 0
+        for r in range(ROWS):
+            for c in range(COLS):
+                if not grid[r][c] and (r, c) not in visit:
+                    res += dfs(r, c)
+
+        return res
+```
+
+```java
+public class Solution {
+    private int[][] directions = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
+    private boolean[][] visit;
+    private int ROWS, COLS;
+    
+    public int closedIsland(int[][] grid) {
+        ROWS = grid.length;
+        COLS = grid[0].length;
+        visit = new boolean[ROWS][COLS];
+
+        int res = 0;
+        for (int r = 0; r < ROWS; r++) {
+            for (int c = 0; c < COLS; c++) {
+                if (grid[r][c] == 0 && !visit[r][c]) {
+                    if (dfs(grid, r, c)) {
+                        res++;
+                    }
+                }
+            }
+        }
+        return res;
+    }
+
+    private boolean dfs(int[][] grid, int r, int c) {
+        if (r < 0 || c < 0 || r == ROWS || c == COLS) {
+            return false;
+        }
+        if (grid[r][c] == 1 || visit[r][c]) {
+            return true;
+        }
+
+        visit[r][c] = true;
+        boolean res = true;
+        for (int[] d : directions) {
+            if (!dfs(grid, r + d[0], c + d[1])) {
+                res = false;
+            }
+        }
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+    int ROWS, COLS;
+    vector<vector<int>> directions;
+    vector<vector<bool>> visit;
+
+public:
+    int closedIsland(vector<vector<int>>& grid) {
+        ROWS = grid.size();
+        COLS = grid[0].size();
+        directions = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
+        visit.assign(ROWS, vector<bool>(COLS, false));
+
+        int res = 0;
+        for (int r = 0; r < ROWS; r++) {
+            for (int c = 0; c < COLS; c++) {
+                if (grid[r][c] == 0 && !visit[r][c]) {
+                    if (dfs(grid, r, c)) {
+                        res++;
+                    }
+                }
+            }
+        }
+        return res;
+    }
+
+private:
+    bool dfs(vector<vector<int>>& grid, int r, int c) {
+        if (r < 0 || c < 0 || r == ROWS || c == COLS) {
+            return false;
+        }
+        if (grid[r][c] == 1 || visit[r][c]) {
+            return true;
+        }
+
+        visit[r][c] = true;
+        bool res = true;
+        for (auto& d : directions) {
+            if (!dfs(grid, r + d[0], c + d[1])) {
+                res = false;
+            }
+        }
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} grid
+     * @return {number}
+     */
+    closedIsland(grid) {
+        const ROWS = grid.length, COLS = grid[0].length;
+        const directions = [0, 1, 0, -1, 0];
+        const visit = Array.from({ length: ROWS }, () => Array(COLS).fill(false));
+
+        const dfs = (r, c) => {
+            if (r < 0 || c < 0 || r === ROWS || c === COLS) return false;
+            if (grid[r][c] === 1 || visit[r][c]) return true;
+
+            visit[r][c] = true;
+            let res = true;
+            for (let d = 0; d < 4; d++) {
+                if (!dfs(r + directions[d], c + directions[d + 1])) {
+                    res = false;
+                }
+            }
+            return res;
+        };
+
+        let res = 0;
+        for (let r = 0; r < ROWS; r++) {
+            for (let c = 0; c < COLS; c++) {
+                if (grid[r][c] === 0 && !visit[r][c]) {
+                    if (dfs(r, c)) res++;
+                }
+            }
+        }
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(m * n)$
+* Space complexity: $O(m * n)$
+
+> Where $m$ is the number of rows and $n$ is the number of columns in the given grid.
+
+---
+
+## 2. Depth First Search - II
+
+::tabs-start
+
+```python
+class Solution:
+    def closedIsland(self, grid: list[list[int]]) -> int:
+        ROWS, COLS = len(grid), len(grid[0])
+        directions = [0, 1, 0, -1, 0]
+
+        def dfs(r, c):
+            if r < 0 or c < 0 or r == ROWS or c == COLS or grid[r][c] == 1:
+                return
+            grid[r][c] = 1
+            for d in range(4):
+                dfs(r + directions[d], c + directions[d + 1])
+
+        for r in range(ROWS):
+            dfs(r, 0)
+            dfs(r, COLS - 1)
+        for c in range(COLS):
+            dfs(0, c)
+            dfs(ROWS - 1, c)
+
+        res = 0
+        for r in range(1, ROWS - 1):
+            for c in range(1, COLS - 1):
+                if grid[r][c] == 0:
+                    dfs(r, c)
+                    res += 1
+        return res
+```
+
+```java
+public class Solution {
+    private int ROWS, COLS;
+    private int[] directions = {0, 1, 0, -1, 0};
+
+    public int closedIsland(int[][] grid) {
+        ROWS = grid.length;
+        COLS = grid[0].length;
+
+        for (int r = 0; r < ROWS; r++) {
+            dfs(grid, r, 0);
+            dfs(grid, r, COLS - 1);
+        }
+        for (int c = 0; c < COLS; c++) {
+            dfs(grid, 0, c);
+            dfs(grid, ROWS - 1, c);
+        }
+
+        int res = 0;
+        for (int r = 1; r < ROWS - 1; r++) {
+            for (int c = 1; c < COLS - 1; c++) {
+                if (grid[r][c] == 0) {
+                    dfs(grid, r, c);
+                    res++;
+                }
+            }
+        }
+        return res;
+    }
+
+    private void dfs(int[][] grid, int r, int c) {
+        if (r < 0 || c < 0 || r >= ROWS || c >= COLS || grid[r][c] == 1) {
+            return;
+        }
+        grid[r][c] = 1;
+        for (int d = 0; d < 4; d++) {
+            dfs(grid, r + directions[d], c + directions[d + 1]);
+        }
+    }
+}
+```
+
+```cpp
+class Solution {
+    const int directions[5] = {0, 1, 0, -1, 0};
+    int ROWS, COLS;
+
+public:
+    int closedIsland(vector<vector<int>>& grid) {
+        ROWS = grid.size();
+        COLS = grid[0].size();
+
+        for (int r = 0; r < ROWS; r++) {
+            dfs(grid, r, 0);
+            dfs(grid, r, COLS - 1);
+        }
+        for (int c = 0; c < COLS; c++) {
+            dfs(grid, 0, c);
+            dfs(grid, ROWS - 1, c);
+        }
+
+        int res = 0;
+        for (int r = 1; r < ROWS - 1; r++) {
+            for (int c = 1; c < COLS - 1; c++) {
+                if (grid[r][c] == 0) {
+                    dfs(grid, r, c);
+                    res++;
+                }
+            }
+        }
+        return res;
+    }
+
+private:
+    void dfs(vector<vector<int>>& grid, int r, int c) {
+        if (r < 0 || c < 0 || r >= ROWS || c >= COLS || grid[r][c] == 1) {
+            return;
+        }
+        grid[r][c] = 1;
+        for (int d = 0; d < 4; d++) {
+            dfs(grid, r + directions[d], c + directions[d + 1]);
+        }
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} grid
+     * @return {number}
+     */
+    closedIsland(grid) {
+        const ROWS = grid.length, COLS = grid[0].length;
+        const directions = [0, 1, 0, -1, 0];
+
+        const dfs = (r, c) => {
+            if (r < 0 || c < 0 || r === ROWS || c === COLS || grid[r][c] === 1) return;
+            grid[r][c] = 1;
+            for (let d = 0; d < 4; d++) {
+                dfs(r + directions[d], c + directions[d + 1]);
+            }
+        };
+
+        for (let r = 0; r < ROWS; r++) {
+            dfs(r, 0);
+            dfs(r, COLS - 1);
+        }
+        for (let c = 0; c < COLS; c++) {
+            dfs(0, c);
+            dfs(ROWS - 1, c);
+        }
+
+        let res = 0;
+        for (let r = 1; r < ROWS - 1; r++) {
+            for (let c = 1; c < COLS - 1; c++) {
+                if (grid[r][c] === 0) {
+                    dfs(r, c);
+                    res++;
+                }
+            }
+        }
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(m * n)$
+* Space complexity: $O(m * n)$
+
+> Where $m$ is the number of rows and $n$ is the number of columns in the given grid.
+
+---
+
+## 3. Breadth First Search
+
+::tabs-start
+
+```python
+class Solution:
+    def closedIsland(self, grid: list[list[int]]) -> int:
+        ROWS, COLS = len(grid), len(grid[0])
+        directions = [[0, 1], [0, -1], [1, 0], [-1, 0]]
+        visit = set()
+        res = 0
+
+        def bfs(r, c):
+            q = deque([(r, c)])
+            visit.add((r, c))
+            is_closed = True
+
+            while q:
+                x, y = q.popleft()
+                for dx, dy in directions:
+                    nx, ny = x + dx, y + dy
+                    if nx < 0 or ny < 0 or nx >= ROWS or ny >= COLS:
+                        is_closed = False
+                        continue
+                    if grid[nx][ny] == 1 or (nx, ny) in visit:
+                        continue
+                    visit.add((nx, ny))
+                    q.append((nx, ny))
+                    
+            return is_closed
+
+        for r in range(ROWS):
+            for c in range(COLS):
+                if grid[r][c] == 0 and (r, c) not in visit:
+                    res += bfs(r, c)
+
+        return res
+```
+
+```java
+public class Solution {
+    private int[][] directions = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
+    private int ROWS, COLS;
+    private boolean[][] visit;
+
+    public int closedIsland(int[][] grid) {
+        ROWS = grid.length;
+        COLS = grid[0].length;
+        visit = new boolean[ROWS][COLS];
+        int res = 0;
+
+        for (int r = 0; r < ROWS; r++) {
+            for (int c = 0; c < COLS; c++) {
+                if (grid[r][c] == 0 && !visit[r][c]) {
+                    if (bfs(grid, r, c)) res++;
+                }
+            }
+        }
+        return res;
+    }
+
+    private boolean bfs(int[][] grid, int r, int c) {
+        Queue<int[]> q = new LinkedList<>();
+        q.offer(new int[]{r, c});
+        visit[r][c] = true;
+        boolean isClosed = true;
+
+        while (!q.isEmpty()) {
+            int[] cell = q.poll();
+            int x = cell[0], y = cell[1];
+
+            for (int[] d : directions) {
+                int nx = x + d[0], ny = y + d[1];
+                if (nx < 0 || ny < 0 || nx >= ROWS || ny >= COLS) {
+                    isClosed = false;
+                    continue;
+                }
+                if (grid[nx][ny] == 1 || visit[nx][ny]) continue;
+                visit[nx][ny] = true;
+                q.offer(new int[]{nx, ny});
+            }
+        }
+        return isClosed;
+    }
+}
+```
+
+```cpp
+class Solution {
+    int directions[4][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
+    int ROWS, COLS;
+    vector<vector<bool>> visit;
+
+public:
+    int closedIsland(vector<vector<int>>& grid) {
+        ROWS = grid.size();
+        COLS = grid[0].size();
+        visit.assign(ROWS, vector<bool>(COLS, false));
+        int res = 0;
+
+        for (int r = 0; r < ROWS; r++) {
+            for (int c = 0; c < COLS; c++) {
+                if (grid[r][c] == 0 && !visit[r][c]) {
+                    if (bfs(grid, r, c)) res++;
+                }
+            }
+        }
+        return res;
+    }
+
+private:
+    bool bfs(vector<vector<int>>& grid, int r, int c) {
+        queue<pair<int, int>> q;
+        q.push({r, c});
+        visit[r][c] = true;
+        bool isClosed = true;
+
+        while (!q.empty()) {
+            auto [x, y] = q.front();q.pop();
+            for (auto& d : directions) {
+                int nx = x + d[0], ny = y + d[1];
+                if (nx < 0 || ny < 0 || nx >= ROWS || ny >= COLS) {
+                    isClosed = false;
+                    continue;
+                }
+                if (grid[nx][ny] == 1 || visit[nx][ny]) continue;
+                visit[nx][ny] = true;
+                q.push({nx, ny});
+            }
+        }
+        return isClosed;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} grid
+     * @return {number}
+     */
+    closedIsland(grid) {
+        const ROWS = grid.length, COLS = grid[0].length;
+        const directions = [[0, 1], [0, -1], [1, 0], [-1, 0]];
+        const visit = Array.from({ length: ROWS }, () => Array(COLS).fill(false));
+        let res = 0;
+
+        const bfs = (r, c) => {
+            const q = new Queue([[r, c]]);
+            visit[r][c] = true;
+            let isClosed = true;
+
+            while (!q.isEmpty()) {
+                const [x, y] = q.pop();
+                for (const [dx, dy] of directions) {
+                    const nx = x + dx, ny = y + dy;
+                    if (nx < 0 || ny < 0 || nx >= ROWS || ny >= COLS) {
+                        isClosed = false;
+                        continue;
+                    }
+                    if (grid[nx][ny] === 1 || visit[nx][ny]) continue;
+                    visit[nx][ny] = true;
+                    q.push([nx, ny]);
+                }
+            }
+            return isClosed;
+        };
+
+        for (let r = 0; r < ROWS; r++) {
+            for (let c = 0; c < COLS; c++) {
+                if (grid[r][c] === 0 && !visit[r][c]) {
+                    if (bfs(r, c)) res++;
+                }
+            }
+        }
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(m * n)$
+* Space complexity: $O(m * n)$
+
+> Where $m$ is the number of rows and $n$ is the number of columns in the given grid.
+
+---
+
+## 4. Disjoint Set Union
+
+::tabs-start
+
+```python
+class DSU:
+    def __init__(self, n):
+        self.Parent = list(range(n + 1))
+        self.Size = [1] * (n + 1)
+
+    def find(self, node):
+        if self.Parent[node] != node:
+            self.Parent[node] = self.find(self.Parent[node])
+        return self.Parent[node]
+
+    def union(self, u, v):
+        pu, pv = self.find(u), self.find(v)
+        if pu == pv:
+            return False
+        if self.Size[pu] >= self.Size[pv]:
+            self.Size[pu] += self.Size[pv]
+            self.Parent[pv] = pu
+        else:
+            self.Size[pv] += self.Size[pu]
+            self.Parent[pu] = pv
+        return True
+
+class Solution:
+    def closedIsland(self, grid: List[List[int]]) -> int:
+        ROWS, COLS = len(grid), len(grid[0])
+        N = ROWS * COLS
+        def index(r, c):
+            return r * COLS + c
+        
+        dsu = DSU(N)
+        directions = [0, 1, 0, -1, 0]
+        for r in range(ROWS):
+            for c in range(COLS):
+                if grid[r][c] == 0:
+                    for d in range(4):
+                        nr, nc = r + directions[d], c + directions[d + 1]
+                        if min(nr, nc) < 0 or nr == ROWS or nc == COLS:
+                            dsu.union(N, index(r, c))
+                        elif grid[nr][nc] == 0:
+                            dsu.union(index(r, c), index(nr, nc))
+
+        res = 0
+        rootN = dsu.find(N)
+        for r in range(ROWS):
+            for c in range(COLS):
+                if grid[r][c] == 1:
+                    continue
+                node = index(r, c)
+                root = dsu.find(node)
+                if root == node and root != rootN:
+                    res += 1
+        return res
+```
+
+```java
+class DSU {
+    int[] Parent, Size;
+
+    public DSU(int n) {
+        Parent = new int[n + 1];
+        Size = new int[n + 1];
+        for (int i = 0; i <= n; i++) {
+            Parent[i] = i;
+            Size[i] = 1;
+        }
+    }
+
+    public int find(int node) {
+        if (Parent[node] != node) {
+            Parent[node] = find(Parent[node]);
+        }
+        return Parent[node];
+    }
+
+    public boolean union(int u, int v) {
+        int pu = find(u), pv = find(v);
+        if (pu == pv) return false;
+        if (Size[pu] >= Size[pv]) {
+            Size[pu] += Size[pv];
+            Parent[pv] = pu;
+        } else {
+            Size[pv] += Size[pu];
+            Parent[pu] = pv;
+        }
+        return true;
+    }
+}
+
+public class Solution {
+    public int closedIsland(int[][] grid) {
+        int ROWS = grid.length, COLS = grid[0].length;
+        int N = ROWS * COLS;
+        
+        DSU dsu = new DSU(N);
+        int[] directions = {0, 1, 0, -1, 0};
+
+        for (int r = 0; r < ROWS; r++) {
+            for (int c = 0; c < COLS; c++) {
+                if (grid[r][c] == 0) {
+                    for (int d = 0; d < 4; d++) {
+                        int nr = r + directions[d], nc = c + directions[d + 1];
+                        if (nr < 0 || nc < 0 || nr == ROWS || nc == COLS) {
+                            dsu.union(N, r * COLS + c);
+                        } else if (grid[nr][nc] == 0) {
+                            dsu.union(r * COLS + c, nr * COLS + nc);
+                        }
+                    }
+                }
+            }
+        }
+
+        int res = 0, rootN = dsu.find(N);
+        for (int r = 0; r < ROWS; r++) {
+            for (int c = 0; c < COLS; c++) {
+                if (grid[r][c] == 0) {
+                    int node = r * COLS + c;
+                    int root = dsu.find(node);
+                    if (root == node && root != rootN) {
+                        res++;
+                    }
+                }
+            }
+        }
+        return res;
+    }
+}
+```
+
+```cpp
+class DSU {
+public:
+    vector<int> Parent, Size;
+
+    DSU(int n) {
+        Parent.resize(n + 1);
+        Size.resize(n + 1, 1);
+        for (int i = 0; i <= n; i++) {
+            Parent[i] = i;
+        }
+    }
+
+    int find(int node) {
+        if (Parent[node] != node) {
+            Parent[node] = find(Parent[node]);
+        }
+        return Parent[node];
+    }
+
+    bool unionSets(int u, int v) {
+        int pu = find(u), pv = find(v);
+        if (pu == pv) return false;
+        if (Size[pu] >= Size[pv]) {
+            Size[pu] += Size[pv];
+            Parent[pv] = pu;
+        } else {
+            Size[pv] += Size[pu];
+            Parent[pu] = pv;
+        }
+        return true;
+    }
+};
+
+class Solution {
+public:
+    int closedIsland(vector<vector<int>>& grid) {
+        int ROWS = grid.size(), COLS = grid[0].size();
+        int N = ROWS * COLS;
+        
+        DSU dsu(N);
+        int directions[5] = {0, 1, 0, -1, 0};
+
+        for (int r = 0; r < ROWS; r++) {
+            for (int c = 0; c < COLS; c++) {
+                if (grid[r][c] == 0) {
+                    for (int d = 0; d < 4; d++) {
+                        int nr = r + directions[d], nc = c + directions[d + 1];
+                        if (nr < 0 || nc < 0 || nr == ROWS || nc == COLS) {
+                            dsu.unionSets(N, r * COLS + c);
+                        } else if (grid[nr][nc] == 0) {
+                            dsu.unionSets(r * COLS + c, nr * COLS + nc);
+                        }
+                    }
+                }
+            }
+        }
+
+        int res = 0, rootN = dsu.find(N);
+        for (int r = 0; r < ROWS; r++) {
+            for (int c = 0; c < COLS; c++) {
+                if (grid[r][c] == 0) {
+                    int node = r * COLS + c;
+                    int root = dsu.find(node);
+                    if (root == node && root != rootN) {
+                        res++;
+                    }
+                }
+            }
+        }
+        return res;
+    }
+};
+```
+
+```javascript
+class DSU {
+    /**
+     * @constructor
+     * @param {number} n
+     */
+    constructor(n) {
+        this.parent = Array.from({ length: n + 1 }, (_, i) => i);
+        this.size = new Array(n + 1).fill(1);
+    }
+
+    /**
+     * @param {number} node
+     * @return {number}
+     */
+    find(node) {
+        if (this.parent[node] !== node) {
+            this.parent[node] = this.find(this.parent[node]);
+        }
+        return this.parent[node];
+    }
+
+    /**
+     * @param {number} u
+     * @param {number} u=v
+     * @return {boolean}
+     */
+    union(u, v) {
+        let pu = this.find(u), pv = this.find(v);
+        if (pu === pv) return false;
+        if (this.size[pu] >= this.size[pv]) {
+            this.size[pu] += this.size[pv];
+            this.parent[pv] = pu;
+        } else {
+            this.size[pv] += this.size[pu];
+            this.parent[pu] = pv;
+        }
+        return true;
+    }
+}
+
+class Solution {
+    /**
+     * @param {number[][]} grid
+     * @return {number}
+     */
+    closedIsland(grid) {
+        const ROWS = grid.length, COLS = grid[0].length;
+        const N = ROWS * COLS;
+        
+        const dsu = new DSU(N);
+        const directions = [0, 1, 0, -1, 0];
+
+        for (let r = 0; r < ROWS; r++) {
+            for (let c = 0; c < COLS; c++) {
+                if (grid[r][c] === 0) {
+                    for (let d = 0; d < 4; d++) {
+                        let nr = r + directions[d], nc = c + directions[d + 1];
+                        if (nr < 0 || nc < 0 || nr === ROWS || nc === COLS) {
+                            dsu.union(N, r * COLS + c);
+                        } else if (grid[nr][nc] === 0) {
+                            dsu.union(r * COLS + c, nr * COLS + nc);
+                        }
+                    }
+                }
+            }
+        }
+
+        let res = 0, rootN = dsu.find(N);
+        for (let r = 0; r < ROWS; r++) {
+            for (let c = 0; c < COLS; c++) {
+                if (grid[r][c] === 0) {
+                    let node = r * COLS + c;
+                    let root = dsu.find(node);
+                    if (root === node && root !== rootN) {
+                        res++;
+                    }
+                }
+            }
+        }
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(m * n)$
+* Space complexity: $O(m * n)$
+
+> Where $m$ is the number of rows and $n$ is the number of columns in the given grid.
\ No newline at end of file
diff --git a/articles/number-of-enclaves.md b/articles/number-of-enclaves.md
new file mode 100644
index 000000000..a5da06e58
--- /dev/null
+++ b/articles/number-of-enclaves.md
@@ -0,0 +1,607 @@
+## 1. Depth First Search
+
+::tabs-start
+
+```python
+class Solution:
+    def numEnclaves(self, grid: List[List[int]]) -> int:
+        ROWS, COLS = len(grid), len(grid[0])
+        direct = [[0, 1], [0, -1], [1, 0], [-1, 0]]
+
+        # Return num of land cells
+        def dfs(r, c):
+            if (r < 0 or c < 0 or 
+                r == ROWS or c == COLS or 
+                not grid[r][c] or (r, c) in visit):
+                return 0
+            visit.add((r, c))
+            res = 1
+            for dr, dc in direct:
+                res += dfs(r + dr, c + dc)
+            return res
+
+        visit = set()
+        land, borderLand = 0, 0
+        for r in range(ROWS):
+            for c in range(COLS):
+                land += grid[r][c]
+                if (grid[r][c] and (r, c) not in visit and 
+                    (c in [0, COLS - 1] or r in [0, ROWS - 1])):
+                    borderLand += dfs(r, c)
+
+        return land - borderLand
+```
+
+```java
+public class Solution {
+    private int ROWS, COLS;
+    private boolean[][] visit;
+    private int[][] direct = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
+    
+    public int numEnclaves(int[][] grid) {
+        this.ROWS = grid.length;
+        this.COLS = grid[0].length;
+        this.visit = new boolean[ROWS][COLS];
+
+        int land = 0, borderLand = 0;
+        for (int r = 0; r < ROWS; r++) {
+            for (int c = 0; c < COLS; c++) {
+                land += grid[r][c];
+                if (grid[r][c] == 1 && !visit[r][c] && 
+                    (r == 0 || r == ROWS - 1 || c == 0 || c == COLS - 1)) {
+                    borderLand += dfs(r, c, grid);
+                }
+            }
+        }
+        return land - borderLand;
+    }
+
+    private int dfs(int r, int c, int[][] grid) {
+        if (r < 0 || c < 0 || r == ROWS || c == COLS || 
+            grid[r][c] == 0 || visit[r][c]) {
+            return 0;
+        }
+        visit[r][c] = true;
+        int res = 1;
+        for (int[] d : direct) {
+            res += dfs(r + d[0], c + d[1], grid);
+        }
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int ROWS, COLS;
+    vector<vector<bool>> visit;
+    vector<vector<int>> direct = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
+
+    int numEnclaves(vector<vector<int>>& grid) {
+        this->ROWS = grid.size();
+        this->COLS = grid[0].size();
+        this->visit = vector<vector<bool>>(ROWS, vector<bool>(COLS, false));
+
+        int land = 0, borderLand = 0;
+        for (int r = 0; r < ROWS; r++) {
+            for (int c = 0; c < COLS; c++) {
+                land += grid[r][c];
+                if (grid[r][c] == 1 && !visit[r][c] && 
+                    (r == 0 || r == ROWS - 1 || c == 0 || c == COLS - 1)) {
+                    borderLand += dfs(r, c, grid);
+                }
+            }
+        }
+        return land - borderLand;
+    }
+
+private:
+    int dfs(int r, int c, vector<vector<int>>& grid) {
+        if (r < 0 || c < 0 || r == ROWS || c == COLS || 
+            grid[r][c] == 0 || visit[r][c]) {
+            return 0;
+        }
+        visit[r][c] = true;
+        int res = 1;
+        for (auto& d : direct) {
+            res += dfs(r + d[0], c + d[1], grid);
+        }
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} grid
+     * @return {number}
+     */
+    numEnclaves(grid) {
+        const ROWS = grid.length, COLS = grid[0].length;
+        const visit = Array.from({ length: ROWS }, () => 
+            Array(COLS).fill(false)
+        );
+        const direct = [0, 1, 0, -1, 0];
+
+        const dfs = (r, c) => {
+            if (r < 0 || c < 0 || r === ROWS || c === COLS || 
+                grid[r][c] === 0 || visit[r][c]) {
+                return 0;
+            }
+            visit[r][c] = true;
+            let res = 1;
+            for (let d = 0; d < 4; d++) {
+                res += dfs(r + direct[d], c + direct[d + 1]);
+            }
+            return res;
+        };
+
+        let land = 0, borderLand = 0;
+        for (let r = 0; r < ROWS; r++) {
+            for (let c = 0; c < COLS; c++) {
+                land += grid[r][c];
+                if (grid[r][c] === 1 && !visit[r][c] &&
+                    (r === 0 || r === ROWS - 1 || c === 0 || c === COLS - 1)) {
+                    borderLand += dfs(r, c);
+                }
+            }
+        }
+        return land - borderLand;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(m * n)$
+* Space complexity: $O(m * n)$
+
+> Where $m$ is the number of rows and $n$ is the number of columns in the given grid.
+
+---
+
+## 2. Breadth First Search
+
+::tabs-start
+
+```python
+class Solution:
+    def numEnclaves(self, grid: list[list[int]]) -> int:
+        ROWS, COLS = len(grid), len(grid[0])
+        direct = [[0, 1], [0, -1], [1, 0], [-1, 0]]
+        visit = [[False] * COLS for _ in range(ROWS)]
+        q = deque()
+        
+        land, borderLand = 0, 0
+        for r in range(ROWS):
+            for c in range(COLS):
+                land += grid[r][c]
+                if (grid[r][c] == 1 and 
+                    (r in [0, ROWS - 1] or c in [0, COLS - 1])
+                ):
+                    q.append((r, c))
+                    visit[r][c] = True
+
+        while q:
+            r, c = q.popleft()
+            borderLand += 1
+            for dr, dc in direct:
+                nr, nc = r + dr, c + dc
+                if (0 <= nr < ROWS and 0 <= nc < COLS and 
+                    grid[nr][nc] == 1 and not visit[nr][nc]
+                ):
+                    q.append((nr, nc))
+                    visit[nr][nc] = True
+
+        return land - borderLand
+```
+
+```java
+public class Solution {
+    public int numEnclaves(int[][] grid) {
+        int ROWS = grid.length, COLS = grid[0].length;
+        int[][] direct = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
+        boolean[][] visit = new boolean[ROWS][COLS];
+        Queue<int[]> q = new LinkedList<>();
+
+        int land = 0, borderLand = 0;
+        for (int r = 0; r < ROWS; r++) {
+            for (int c = 0; c < COLS; c++) {
+                land += grid[r][c];
+                if (grid[r][c] == 1 && (r == 0 || r == ROWS - 1 || 
+                    c == 0 || c == COLS - 1)) {
+                    q.offer(new int[]{r, c});
+                    visit[r][c] = true;
+                }
+            }
+        }
+
+        while (!q.isEmpty()) {
+            int[] cell = q.poll();
+            int r = cell[0], c = cell[1];
+            borderLand++;
+
+            for (int[] d : direct) {
+                int nr = r + d[0], nc = c + d[1];
+                if (nr >= 0 && nc >= 0 && nr < ROWS && nc < COLS && 
+                    grid[nr][nc] == 1 && !visit[nr][nc]) {
+                    q.offer(new int[]{nr, nc});
+                    visit[nr][nc] = true;
+                }
+            }
+        }
+
+        return land - borderLand;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int ROWS, COLS;
+    vector<vector<bool>> visit;
+    vector<vector<int>> direct = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
+
+    int numEnclaves(vector<vector<int>>& grid) {
+        this->ROWS = grid.size();
+        this->COLS = grid[0].size();
+        this->visit = vector<vector<bool>>(ROWS, vector<bool>(COLS, false));
+
+        int land = 0, borderLand = 0;
+        for (int r = 0; r < ROWS; r++) {
+            for (int c = 0; c < COLS; c++) {
+                land += grid[r][c];
+                if (grid[r][c] == 1 && !visit[r][c] && 
+                    (r == 0 || r == ROWS - 1 || c == 0 || c == COLS - 1)) {
+                    borderLand += dfs(r, c, grid);
+                }
+            }
+        }
+        return land - borderLand;
+    }
+
+private:
+    int dfs(int r, int c, vector<vector<int>>& grid) {
+        if (r < 0 || c < 0 || r == ROWS || c == COLS || 
+            grid[r][c] == 0 || visit[r][c]) {
+            return 0;
+        }
+        visit[r][c] = true;
+        int res = 1;
+        for (auto& d : direct) {
+            res += dfs(r + d[0], c + d[1], grid);
+        }
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} grid
+     * @return {number}
+     */
+    numEnclaves(grid) {
+        const ROWS = grid.length, COLS = grid[0].length;
+        const direct = [0, 1, 0, -1, 0];
+        const visit = Array.from({ length: ROWS }, () => 
+            Array(COLS).fill(false)
+        );
+        const q = new Queue();
+
+        let land = 0, borderLand = 0;
+        for (let r = 0; r < ROWS; r++) {
+            for (let c = 0; c < COLS; c++) {
+                land += grid[r][c];
+                if (grid[r][c] === 1 && (r === 0 || r === ROWS - 1 || 
+                    c === 0 || c === COLS - 1)) {
+                    q.push([r, c]);
+                    visit[r][c] = true;
+                }
+            }
+        }
+
+        while (!q.isEmpty()) {
+            let [r, c] = q.pop();
+            borderLand++;
+            for (let d = 0; d < 4; d++) {
+                let nr = r + direct[d], nc = c + direct[d + 1];
+                if (nr >= 0 && nc >= 0 && nr < ROWS && nc < COLS && 
+                    grid[nr][nc] === 1 && !visit[nr][nc]) {
+                    q.push([nr, nc]);
+                    visit[nr][nc] = true;
+                }
+            }
+        }
+
+        return land - borderLand;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(m * n)$
+* Space complexity: $O(m * n)$
+
+> Where $m$ is the number of rows and $n$ is the number of columns in the given grid.
+
+---
+
+## 3. Disjoint Set Union
+
+::tabs-start
+
+```python
+class DSU:
+    def __init__(self, n):
+        self.Parent = list(range(n + 1))
+        self.Size = [1] * (n + 1)
+
+    def find(self, node):
+        if self.Parent[node] != node:
+            self.Parent[node] = self.find(self.Parent[node])
+        return self.Parent[node]
+
+    def union(self, u, v):
+        pu, pv = self.find(u), self.find(v)
+        if pu == pv:
+            return False
+        if self.Size[pu] >= self.Size[pv]:
+            self.Size[pu] += self.Size[pv]
+            self.Parent[pv] = pu
+        else:
+            self.Size[pv] += self.Size[pu]
+            self.Parent[pu] = pv
+        return True
+
+class Solution:
+    def numEnclaves(self, grid: list[list[int]]) -> int:
+        ROWS, COLS = len(grid), len(grid[0])
+        N = ROWS * COLS
+        def index(r, c):
+            return r * COLS + c
+
+        dsu = DSU(N)
+        directions = [0, 1, 0, -1, 0]
+        land = 0
+        for r in range(ROWS):
+            for c in range(COLS):
+                if grid[r][c] == 0:
+                    continue
+                land += 1
+                for d in range(4):
+                    nr, nc = r + directions[d], c + directions[d + 1]
+                    if 0 <= nr < ROWS and 0 <= nc < COLS:
+                        if grid[nr][nc] == 1:
+                            dsu.union(index(r, c), index(nr, nc))
+                    else:
+                        dsu.union(N, index(r, c))
+
+        borderLand = dsu.Size[dsu.find(N)]
+        return land - borderLand + 1
+```
+
+```java
+class DSU {
+    int[] Parent, Size;
+
+    public DSU(int n) {
+        Parent = new int[n + 1];
+        Size = new int[n + 1];
+        for (int i = 0; i <= n; i++) {
+            Parent[i] = i;
+            Size[i] = 1;
+        }
+    }
+
+    public int find(int node) {
+        if (Parent[node] != node) {
+            Parent[node] = find(Parent[node]);
+        }
+        return Parent[node];
+    }
+
+    public boolean union(int u, int v) {
+        int pu = find(u), pv = find(v);
+        if (pu == pv) return false;
+        if (Size[pu] >= Size[pv]) {
+            Size[pu] += Size[pv];
+            Parent[pv] = pu;
+        } else {
+            Size[pv] += Size[pu];
+            Parent[pu] = pv;
+        }
+        return true;
+    }
+}
+
+public class Solution {
+    public int numEnclaves(int[][] grid) {
+        int ROWS = grid.length, COLS = grid[0].length;
+        int N = ROWS * COLS;
+        DSU dsu = new DSU(N);
+        int[] directions = {0, 1, 0, -1, 0};
+        int land = 0;
+
+        for (int r = 0; r < ROWS; r++) {
+            for (int c = 0; c < COLS; c++) {
+                if (grid[r][c] == 0) continue;
+                land++;
+                for (int d = 0; d < 4; d++) {
+                    int nr = r + directions[d], nc = c + directions[d + 1];
+                    if (nr >= 0 && nc >= 0 && nr < ROWS && nc < COLS) {
+                        if (grid[nr][nc] == 1) {
+                            dsu.union(r * COLS + c, nr * COLS + nc);
+                        }
+                    } else {
+                        dsu.union(N, r * COLS + c);
+                    }
+                }
+            }
+        }
+
+        int borderLand = dsu.Size[dsu.find(N)];
+        return land - borderLand + 1;
+    }
+}
+```
+
+```cpp
+class DSU {
+public:
+    vector<int> Parent, Size;
+
+    DSU(int n) {
+        Parent.resize(n + 1);
+        Size.resize(n + 1, 1);
+        for (int i = 0; i <= n; i++) {
+            Parent[i] = i;
+        }
+    }
+
+    int find(int node) {
+        if (Parent[node] != node) {
+            Parent[node] = find(Parent[node]);
+        }
+        return Parent[node];
+    }
+
+    bool unionSets(int u, int v) {
+        int pu = find(u), pv = find(v);
+        if (pu == pv) return false;
+        if (Size[pu] >= Size[pv]) {
+            Size[pu] += Size[pv];
+            Parent[pv] = pu;
+        } else {
+            Size[pv] += Size[pu];
+            Parent[pu] = pv;
+        }
+        return true;
+    }
+};
+
+class Solution {
+public:
+    int numEnclaves(vector<vector<int>>& grid) {
+        int ROWS = grid.size(), COLS = grid[0].size();
+        int N = ROWS * COLS;
+        DSU dsu(N);
+        vector<int> directions = {0, 1, 0, -1, 0};
+        int land = 0;
+
+        for (int r = 0; r < ROWS; r++) {
+            for (int c = 0; c < COLS; c++) {
+                if (grid[r][c] == 0) continue;
+                land++;
+                for (int d = 0; d < 4; d++) {
+                    int nr = r + directions[d], nc = c + directions[d + 1];
+                    if (nr >= 0 && nc >= 0 && nr < ROWS && nc < COLS) {
+                        if (grid[nr][nc] == 1) {
+                            dsu.unionSets(r * COLS + c, nr * COLS + nc);
+                        }
+                    } else {
+                        dsu.unionSets(N, r * COLS + c);
+                    }
+                }
+            }
+        }
+
+        int borderLand = dsu.Size[dsu.find(N)];
+        return land - borderLand + 1;
+    }
+};
+```
+
+```javascript
+class DSU {
+    /**
+     * @constructor
+     * @param {number} n
+     */
+    constructor(n) {
+        this.parent = Array.from({ length: n + 1 }, (_, i) => i);
+        this.size = new Array(n + 1).fill(1);
+    }
+
+    /**
+     * @param {number} node
+     * @return {number}
+     */
+    find(node) {
+        if (this.parent[node] !== node) {
+            this.parent[node] = this.find(this.parent[node]);
+        }
+        return this.parent[node];
+    }
+
+    /**
+     * @param {number} u
+     * @param {number} u=v
+     * @return {boolean}
+     */
+    union(u, v) {
+        let pu = this.find(u), pv = this.find(v);
+        if (pu === pv) return false;
+        if (this.size[pu] >= this.size[pv]) {
+            this.size[pu] += this.size[pv];
+            this.parent[pv] = pu;
+        } else {
+            this.size[pv] += this.size[pu];
+            this.parent[pu] = pv;
+        }
+        return true;
+    }
+}
+
+class Solution {
+    /**
+     * @param {number[][]} grid
+     * @return {number}
+     */
+    numEnclaves(grid) {
+        const ROWS = grid.length, COLS = grid[0].length;
+        const N = ROWS * COLS;
+        const dsu = new DSU(N);
+        const directions = [0, 1, 0, -1, 0];
+        let land = 0;
+
+        for (let r = 0; r < ROWS; r++) {
+            for (let c = 0; c < COLS; c++) {
+                if (grid[r][c] === 0) continue;
+                land++;
+                for (let d = 0; d < 4; d++) {
+                    let nr = r + directions[d], nc = c + directions[d + 1];
+                    if (nr >= 0 && nc >= 0 && nr < ROWS && nc < COLS) {
+                        if (grid[nr][nc] === 1) {
+                            dsu.union(r * COLS + c, nr * COLS + nc);
+                        }
+                    } else {
+                        dsu.union(N, r * COLS + c);
+                    }
+                }
+            }
+        }
+
+        const borderLand = dsu.size[dsu.find(N)];
+        return land - borderLand + 1;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(m * n)$
+* Space complexity: $O(m * n)$
+
+> Where $m$ is the number of rows and $n$ is the number of columns in the given grid.
\ No newline at end of file
diff --git a/articles/pseudo-palindromic-paths-in-a-binary-tree.md b/articles/pseudo-palindromic-paths-in-a-binary-tree.md
new file mode 100644
index 000000000..96bf58f3b
--- /dev/null
+++ b/articles/pseudo-palindromic-paths-in-a-binary-tree.md
@@ -0,0 +1,806 @@
+## 1. Depth First Search
+
+::tabs-start
+
+```python
+# Definition for a binary tree node.
+# class TreeNode:
+#     def __init__(self, val=0, left=None, right=None):
+#         self.val = val
+#         self.left = left
+#         self.right = right
+class Solution:
+    def pseudoPalindromicPaths(self, root: Optional[TreeNode]) -> int:
+        count = defaultdict(int)
+        odd = 0
+
+        def dfs(cur):
+            nonlocal odd
+            if not cur:
+                return 0
+
+            count[cur.val] += 1
+            odd_change = 1 if count[cur.val] % 2 == 1 else -1
+            odd += odd_change
+
+            if not cur.left and not cur.right:
+                res = 1 if odd <= 1 else 0
+            else:
+                res = dfs(cur.left) + dfs(cur.right)
+
+            odd -= odd_change
+            count[cur.val] -= 1
+            return res
+
+        return dfs(root)
+```
+
+```java
+/**
+ * Definition for a binary tree node.
+ * public class TreeNode {
+ *     int val;
+ *     TreeNode left;
+ *     TreeNode right;
+ *     TreeNode() {}
+ *     TreeNode(int val) { this.val = val; }
+ *     TreeNode(int val, TreeNode left, TreeNode right) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+public class Solution {
+    public int pseudoPalindromicPaths(TreeNode root) {
+        Map<Integer, Integer> count = new HashMap<>();
+        int[] odd = new int[1];
+
+        return dfs(root, count, odd);
+    }
+
+    private int dfs(TreeNode cur, Map<Integer, Integer> count, int[] odd) {
+        if (cur == null) return 0;
+
+        count.put(cur.val, count.getOrDefault(cur.val, 0) + 1);
+        int odd_change = (count.get(cur.val) % 2 == 1) ? 1 : -1;
+        odd[0] += odd_change;
+
+        int res;
+        if (cur.left == null && cur.right == null) {
+            res = (odd[0] <= 1) ? 1 : 0;
+        } else {
+            res = dfs(cur.left, count, odd) + dfs(cur.right, count, odd);
+        }
+
+        odd[0] -= odd_change;
+        count.put(cur.val, count.get(cur.val) - 1);
+        return res;
+    }
+}
+```
+
+```cpp
+/**
+ * Definition for a binary tree node.
+ * struct TreeNode {
+ *     int val;
+ *     TreeNode *left;
+ *     TreeNode *right;
+ *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
+ * };
+ */
+class Solution {
+public:
+    int pseudoPalindromicPaths(TreeNode* root) {
+        unordered_map<int, int> count;
+        int odd = 0;
+        return dfs(root, count, odd);
+    }
+
+private:
+    int dfs(TreeNode* cur, unordered_map<int, int>& count, int& odd) {
+        if (!cur) return 0;
+
+        count[cur->val]++;
+        int odd_change = (count[cur->val] % 2 == 1) ? 1 : -1;
+        odd += odd_change;
+
+        int res;
+        if (!cur->left && !cur->right) {
+            res = (odd <= 1) ? 1 : 0;
+        } else {
+            res = dfs(cur->left, count, odd) + dfs(cur->right, count, odd);
+        }
+
+        odd -= odd_change;
+        count[cur->val]--;
+        return res;
+    }
+};
+```
+
+```javascript
+/**
+ * Definition for a binary tree node.
+ * class TreeNode {
+ *     constructor(val = 0, left = null, right = null) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+class Solution {
+    /**
+     * @param {TreeNode} root
+     * @return {number}
+     */
+    pseudoPalindromicPaths(root) {
+        const count = new Map();
+        let odd = 0;
+
+        const dfs = (cur) => {
+            if (!cur) return 0;
+
+            count.set(cur.val, (count.get(cur.val) || 0) + 1);
+            let odd_change = (count.get(cur.val) % 2 === 1) ? 1 : -1;
+            odd += odd_change;
+
+            let res;
+            if (!cur.left && !cur.right) {
+                res = (odd <= 1) ? 1 : 0;
+            } else {
+                res = dfs(cur.left) + dfs(cur.right);
+            }
+
+            odd -= odd_change;
+            count.set(cur.val, count.get(cur.val) - 1);
+            return res;
+        };
+
+        return dfs(root);
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(h)$ for recursion stack.
+
+> Where $n$ is the number of nodes and $h$ is the height of the given tree.
+
+---
+
+## 2. Depth First Search (Using Array)
+
+::tabs-start
+
+```python
+# Definition for a binary tree node.
+# class TreeNode:
+#     def __init__(self, val=0, left=None, right=None):
+#         self.val = val
+#         self.left = left
+#         self.right = right
+class Solution:
+    def pseudoPalindromicPaths(self, root: Optional[TreeNode]) -> int:
+        count = [0] * 10
+        odd = 0
+
+        def dfs(cur):
+            nonlocal odd
+            if not cur:
+                return 0
+
+            count[cur.val] ^= 1
+            odd += 1 if count[cur.val] else -1
+
+            if not cur.left and not cur.right and odd <= 1:
+                res = 1
+            else:
+                res = dfs(cur.left) + dfs(cur.right)
+
+            odd -= 1 if count[cur.val] else -1
+            count[cur.val] ^= 1
+
+            return res
+
+        return dfs(root)
+```
+
+```java
+/**
+ * Definition for a binary tree node.
+ * public class TreeNode {
+ *     int val;
+ *     TreeNode left;
+ *     TreeNode right;
+ *     TreeNode() {}
+ *     TreeNode(int val) { this.val = val; }
+ *     TreeNode(int val, TreeNode left, TreeNode right) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+public class Solution {
+    public int pseudoPalindromicPaths(TreeNode root) {
+        int[] count = new int[10];
+        return dfs(root, count, 0);
+    }
+
+    private int dfs(TreeNode cur, int[] count, int odd) {
+        if (cur == null) return 0;
+
+        count[cur.val] ^= 1;
+        odd += count[cur.val] == 1 ? 1 : -1;
+
+        int res = (cur.left == null && cur.right == null && odd <= 1) ? 1 
+                  : dfs(cur.left, count, odd) + dfs(cur.right, count, odd);
+
+        odd += count[cur.val] == 1 ? 1 : -1;
+        count[cur.val] ^= 1;
+
+        return res;
+    }
+}
+```
+
+```cpp
+/**
+ * Definition for a binary tree node.
+ * struct TreeNode {
+ *     int val;
+ *     TreeNode *left;
+ *     TreeNode *right;
+ *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
+ * };
+ */
+class Solution {
+public:
+    int pseudoPalindromicPaths(TreeNode* root) {
+        int count[10] = {};
+        return dfs(root, count, 0);
+    }
+
+private:
+    int dfs(TreeNode* cur, int count[], int odd) {
+        if (!cur) return 0;
+
+        count[cur->val] ^= 1;
+        odd += (count[cur->val] == 1) ? 1 : -1;
+
+        int res = (!cur->left && !cur->right && odd <= 1) ? 1 
+                  : dfs(cur->left, count, odd) + dfs(cur->right, count, odd);
+
+        odd += (count[cur->val] == 1) ? 1 : -1;
+        count[cur->val] ^= 1;
+
+        return res;
+    }
+};
+```
+
+```javascript
+/**
+ * Definition for a binary tree node.
+ * class TreeNode {
+ *     constructor(val = 0, left = null, right = null) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+class Solution {
+    /**
+     * @param {TreeNode} root
+     * @return {number}
+     */
+    pseudoPalindromicPaths(root) {
+        const count = new Array(10).fill(0);
+
+        const dfs = (cur, odd) => {
+            if (!cur) return 0;
+
+            count[cur.val] ^= 1;
+            odd += count[cur.val] === 1 ? 1 : -1;
+
+            let res = (!cur.left && !cur.right && odd <= 1) 
+                    ? 1 : dfs(cur.left, odd) + dfs(cur.right, odd);
+
+            odd += count[cur.val] === 1 ? 1 : -1;
+            count[cur.val] ^= 1;
+
+            return res;
+        };
+
+        return dfs(root, 0);
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(h)$ for recursion stack.
+
+> Where $n$ is the number of nodes and $h$ is the height of the given tree.
+
+---
+
+## 3. Depth First Search (Bit Mask)
+
+::tabs-start
+
+```python
+# Definition for a binary tree node.
+# class TreeNode:
+#     def __init__(self, val=0, left=None, right=None):
+#         self.val = val
+#         self.left = left
+#         self.right = right
+class Solution:
+    def pseudoPalindromicPaths(self, root: Optional[TreeNode]) -> int:
+        def dfs(node, path):
+            if not node:
+                return 0
+
+            path ^= 1 << node.val
+            if not node.left and not node.right:
+                return 1 if (path & (path - 1)) == 0 else 0
+
+            return dfs(node.left, path) + dfs(node.right, path)
+
+        return dfs(root, 0)
+```
+
+```java
+/**
+ * Definition for a binary tree node.
+ * public class TreeNode {
+ *     int val;
+ *     TreeNode left;
+ *     TreeNode right;
+ *     TreeNode() {}
+ *     TreeNode(int val) { this.val = val; }
+ *     TreeNode(int val, TreeNode left, TreeNode right) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+public class Solution {
+    public int pseudoPalindromicPaths(TreeNode root) {
+        return dfs(root, 0);
+    }
+
+    private int dfs(TreeNode node, int path) {
+        if (node == null) return 0;
+
+        path ^= (1 << node.val);
+        if (node.left == null && node.right == null) {
+            return (path & (path - 1)) == 0 ? 1 : 0;
+        }
+
+        return dfs(node.left, path) + dfs(node.right, path);
+    }
+}
+```
+
+```cpp
+/**
+ * Definition for a binary tree node.
+ * struct TreeNode {
+ *     int val;
+ *     TreeNode *left;
+ *     TreeNode *right;
+ *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
+ * };
+ */
+class Solution {
+public:
+    int pseudoPalindromicPaths(TreeNode* root) {
+        return dfs(root, 0);
+    }
+
+private:
+    int dfs(TreeNode* node, int path) {
+        if (!node) return 0;
+
+        path ^= (1 << node->val);
+        if (!node->left && !node->right) {
+            return (path & (path - 1)) == 0 ? 1 : 0;
+        }
+
+        return dfs(node->left, path) + dfs(node->right, path);
+    }
+};
+```
+
+```javascript
+/**
+ * Definition for a binary tree node.
+ * class TreeNode {
+ *     constructor(val = 0, left = null, right = null) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+class Solution {
+    /**
+     * @param {TreeNode} root
+     * @return {number}
+     */
+    pseudoPalindromicPaths(root) {
+        const dfs = (node, path) => {
+            if (!node) return 0;
+
+            path ^= (1 << node.val);
+            if (!node.left && !node.right) {
+                return (path & (path - 1)) === 0 ? 1 : 0;
+            }
+
+            return dfs(node.left, path) + dfs(node.right, path);
+        };
+
+        return dfs(root, 0);
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(h)$ for recursion stack.
+
+> Where $n$ is the number of nodes and $h$ is the height of the given tree.
+
+---
+
+## 4. Breadth First Search
+
+::tabs-start
+
+```python
+# Definition for a binary tree node.
+# class TreeNode:
+#     def __init__(self, val=0, left=None, right=None):
+#         self.val = val
+#         self.left = left
+#         self.right = right
+class Solution:
+    def pseudoPalindromicPaths(self, root: Optional[TreeNode]) -> int:
+        res = 0
+        q = deque([(root, 0)])
+        while q:
+            node, path = q.popleft()
+            path ^= 1 << node.val
+
+            if not node.left and not node.right:
+                if path & (path - 1) == 0:
+                    res += 1
+                continue
+
+            if node.left:
+                q.append((node.left, path))
+            if node.right:
+                q.append((node.right, path))
+
+        return res
+```
+
+```java
+/**
+ * Definition for a binary tree node.
+ * public class TreeNode {
+ *     int val;
+ *     TreeNode left;
+ *     TreeNode right;
+ *     TreeNode() {}
+ *     TreeNode(int val) { this.val = val; }
+ *     TreeNode(int val, TreeNode left, TreeNode right) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+public class Solution {
+    public int pseudoPalindromicPaths(TreeNode root) {
+        int count = 0;
+        Queue<Pair> q = new LinkedList<>();
+        q.offer(new Pair(root, 0));
+        while (!q.isEmpty()) {
+            Pair p = q.poll();
+            TreeNode node = p.node;
+            int path = p.path ^ (1 << node.val);
+
+            if (node.left == null && node.right == null) {
+                if ((path & (path - 1)) == 0) {
+                    count++;
+                }
+            } else {
+                if (node.left != null) q.offer(new Pair(node.left, path));
+                if (node.right != null) q.offer(new Pair(node.right, path));
+            }
+        }
+
+        return count;
+    }
+
+    private static class Pair {
+        TreeNode node;
+        int path;
+        Pair(TreeNode node, int path) {
+            this.node = node;
+            this.path = path;
+        }
+    }
+}
+```
+
+```cpp
+/**
+ * Definition for a binary tree node.
+ * struct TreeNode {
+ *     int val;
+ *     TreeNode *left;
+ *     TreeNode *right;
+ *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
+ * };
+ */
+class Solution {
+public:
+    int pseudoPalindromicPaths(TreeNode* root) {
+        int res = 0;
+        queue<pair<TreeNode*, int>> q;
+        q.push({root, 0});
+        while (!q.empty()) {
+            auto [node, path] = q.front();q.pop();
+            path ^= (1 << node->val);
+
+            if (!node->left && !node->right) {
+                if ((path & (path - 1)) == 0) res++;
+                continue;
+            }
+
+            if (node->left) q.push({node->left, path});
+            if (node->right) q.push({node->right, path});
+        }
+
+        return res;
+    }
+};
+```
+
+```javascript
+/**
+ * Definition for a binary tree node.
+ * class TreeNode {
+ *     constructor(val = 0, left = null, right = null) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+class Solution {
+    /**
+     * @param {TreeNode} root
+     * @return {number}
+     */
+    pseudoPalindromicPaths(root) {
+        let res = 0;
+        const q = new Queue([[root, 0]]);
+
+        while (!q.isEmpty()) {
+            const [node, path] = q.pop();
+            const newPath = path ^ (1 << node.val);
+
+            if (!node.left && !node.right) {
+                if ((newPath & (newPath - 1)) === 0) res++;
+                continue;
+            }
+
+            if (node.left) q.push([node.left, newPath]);
+            if (node.right) q.push([node.right, newPath]);
+        }
+
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(n)$
+
+---
+
+## 5. Iterative DFS
+
+::tabs-start
+
+```python
+# Definition for a binary tree node.
+# class TreeNode:
+#     def __init__(self, val=0, left=None, right=None):
+#         self.val = val
+#         self.left = left
+#         self.right = right
+class Solution:
+    def pseudoPalindromicPaths(self, root: Optional[TreeNode]) -> int:
+        count = 0
+        stack = [(root, 0)]
+        while stack:
+            node, path = stack.pop()
+            path ^= (1 << node.val)
+
+            if not node.left and not node.right:
+                if path & (path - 1) == 0:
+                    count += 1
+            else:
+                if node.right:
+                    stack.append((node.right, path))
+                if node.left:
+                    stack.append((node.left, path))
+
+        return count
+```
+
+```java
+/**
+ * Definition for a binary tree node.
+ * public class TreeNode {
+ *     int val;
+ *     TreeNode left;
+ *     TreeNode right;
+ *     TreeNode() {}
+ *     TreeNode(int val) { this.val = val; }
+ *     TreeNode(int val, TreeNode left, TreeNode right) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+public class Solution {
+    public int pseudoPalindromicPaths(TreeNode root) {
+        int count = 0;
+        Stack<Pair> stack = new Stack<>();
+        stack.push(new Pair(root, 0));
+
+        while (!stack.isEmpty()) {
+            Pair p = stack.pop();
+            TreeNode node = p.node;
+            int path = p.path ^ (1 << node.val);
+
+            if (node.left == null && node.right == null) {
+                if ((path & (path - 1)) == 0) {
+                    count++;
+                }
+            } else {
+                if (node.right != null) stack.push(new Pair(node.right, path));
+                if (node.left != null) stack.push(new Pair(node.left, path));
+            }
+        }
+        return count;
+    }
+
+    private static class Pair {
+        TreeNode node;
+        int path;
+        Pair(TreeNode node, int path) {
+            this.node = node;
+            this.path = path;
+        }
+    }
+}
+```
+
+```cpp
+/**
+ * Definition for a binary tree node.
+ * struct TreeNode {
+ *     int val;
+ *     TreeNode *left;
+ *     TreeNode *right;
+ *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
+ * };
+ */
+class Solution {
+public:
+    int pseudoPalindromicPaths(TreeNode* root) {
+        stack<pair<TreeNode*, int>> s;
+        s.push({root, 0});
+        int count = 0;
+
+        while (!s.empty()) {
+            auto [node, path] = s.top();
+            s.pop();
+            path ^= (1 << node->val);
+
+            if (!node->left && !node->right) {
+                if ((path & (path - 1)) == 0) count++;
+            } else {
+                if (node->right) s.push({node->right, path});
+                if (node->left) s.push({node->left, path});
+            }
+        }
+
+        return count;
+    }
+};
+```
+
+```javascript
+/**
+ * Definition for a binary tree node.
+ * class TreeNode {
+ *     constructor(val = 0, left = null, right = null) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+class Solution {
+    /**
+     * @param {TreeNode} root
+     * @return {number}
+     */
+    pseudoPalindromicPaths(root) {
+        let count = 0;
+        const stack = [[root, 0]];
+
+        while (stack.length) {
+            const [node, path] = stack.pop();
+            const newPath = path ^ (1 << node.val);
+
+            if (!node.left && !node.right) {
+                if ((newPath & (newPath - 1)) === 0) count++;
+            } else {
+                if (node.right) stack.push([node.right, newPath]);
+                if (node.left) stack.push([node.left, newPath]);
+            }
+        }
+
+        return count;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(h)$
+
+> Where $n$ is the number of nodes and $h$ is the height of the given tree.
\ No newline at end of file
diff --git a/articles/shortest-path-with-alternating-colors.md b/articles/shortest-path-with-alternating-colors.md
new file mode 100644
index 000000000..f5d927069
--- /dev/null
+++ b/articles/shortest-path-with-alternating-colors.md
@@ -0,0 +1,543 @@
+## 1. Breadth First Search - I
+
+::tabs-start
+
+```python
+class Solution:
+    def shortestAlternatingPaths(self, n: int, redEdges: list[list[int]], blueEdges: list[list[int]]) -> list[int]:
+        red, blue = defaultdict(list), defaultdict(list)
+        
+        for src, dst in redEdges:
+            red[src].append(dst)
+
+        for src, dst in blueEdges:
+            blue[src].append(dst)
+
+        answer = [-1 for _ in range(n)]
+        q = deque()
+        q.append((0, 0, None))  # [node, length, prev_edge_color]
+        visit = set()
+        visit.add((0, None))
+
+        while q:
+            node, length, edgeColor = q.popleft()
+            if answer[node] == -1:
+                answer[node] = length
+
+            if edgeColor != "RED":
+                for nei in red[node]:
+                    if (nei, "RED") not in visit:
+                        visit.add((nei, "RED"))
+                        q.append((nei, length + 1, "RED"))
+
+            if edgeColor != "BLUE":
+                for nei in blue[node]:
+                    if (nei, "BLUE") not in visit:
+                        visit.add((nei, "BLUE"))
+                        q.append((nei, length + 1, "BLUE"))
+
+        return answer
+```
+
+```java
+public class Solution {
+    public int[] shortestAlternatingPaths(int n, int[][] redEdges, int[][] blueEdges) {
+        List<Integer>[] red = new ArrayList[n], blue = new ArrayList[n];
+        for (int i = 0; i < n; i++) {
+            red[i] = new ArrayList<>();
+            blue[i] = new ArrayList<>();
+        }
+        for (int[] edge : redEdges) red[edge[0]].add(edge[1]);
+        for (int[] edge : blueEdges) blue[edge[0]].add(edge[1]);
+
+        int[] answer = new int[n];
+        Arrays.fill(answer, -1);
+        Queue<int[]> q = new LinkedList<>();
+        q.offer(new int[]{0, 0, -1});
+        Set<String> visit = new HashSet<>();
+        visit.add("0,-1");
+
+        while (!q.isEmpty()) {
+            int[] nodeData = q.poll();
+            int node = nodeData[0], length = nodeData[1], edgeColor = nodeData[2];
+
+            if (answer[node] == -1) answer[node] = length;
+
+            if (edgeColor != 0) {
+                for (int nei : red[node]) {
+                    if (visit.add(nei + ",0")) {
+                        q.offer(new int[]{nei, length + 1, 0});
+                    }
+                }
+            }
+            if (edgeColor != 1) {
+                for (int nei : blue[node]) {
+                    if (visit.add(nei + ",1")) {
+                        q.offer(new int[]{nei, length + 1, 1});
+                    }
+                }
+            }
+        }
+        return answer;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    vector<int> shortestAlternatingPaths(int n, vector<vector<int>>& redEdges, vector<vector<int>>& blueEdges) {
+        vector<vector<int>> red(n), blue(n);
+        for (auto& edge : redEdges) red[edge[0]].push_back(edge[1]);
+        for (auto& edge : blueEdges) blue[edge[0]].push_back(edge[1]);
+
+        vector<int> answer(n, -1);
+        queue<vector<int>> q;
+        q.push({0, 0, -1});
+        unordered_set<string> visit;
+        visit.insert("0,-1");
+
+        while (!q.empty()) {
+            vector<int> nodeData = q.front();
+            q.pop();
+            int node = nodeData[0], length = nodeData[1], edgeColor = nodeData[2];
+
+            if (answer[node] == -1) answer[node] = length;
+
+            if (edgeColor != 0) {
+                for (int nei : red[node]) {
+                    string key = to_string(nei) + ",0";
+                    if (visit.insert(key).second) {
+                        q.push({nei, length + 1, 0});
+                    }
+                }
+            }
+            if (edgeColor != 1) {
+                for (int nei : blue[node]) {
+                    string key = to_string(nei) + ",1";
+                    if (visit.insert(key).second) {
+                        q.push({nei, length + 1, 1});
+                    }
+                }
+            }
+        }
+        return answer;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number} n
+     * @param {number[][]} redEdges
+     * @param {number[][]} blueEdges
+     * @return {number[]}
+     */
+    shortestAlternatingPaths(n, redEdges, blueEdges) {
+        const red = Array.from({ length: n }, () => []);
+        const blue = Array.from({ length: n }, () => []);
+
+        for (const [src, dst] of redEdges) red[src].push(dst);
+        for (const [src, dst] of blueEdges) blue[src].push(dst);
+
+        const answer = new Array(n).fill(-1);
+        const q = new Queue([[0, 0, null]]);
+        const visit = new Set(["0,null"]);
+
+        while (!q.isEmpty()) {
+            const [node, length, edgeColor] = q.pop();
+            if (answer[node] === -1) answer[node] = length;
+
+            if (edgeColor !== "RED") {
+                for (const nei of red[node]) {
+                    if (!visit.has(`${nei},RED`)) {
+                        visit.add(`${nei},RED`);
+                        q.push([nei, length + 1, "RED"]);
+                    }
+                }
+            }
+            if (edgeColor !== "BLUE") {
+                for (const nei of blue[node]) {
+                    if (!visit.has(`${nei},BLUE`)) {
+                        visit.add(`${nei},BLUE`);
+                        q.push([nei, length + 1, "BLUE"]);
+                    }
+                }
+            }
+        }
+        return answer;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(V + E)$
+* Space complexity: $O(V + E)$
+
+> Where $V$ is the number of vertices and $E$ is the number of edges.
+
+---
+
+## 2. Breadth First Search - II
+
+::tabs-start
+
+```python
+class Solution:
+    def shortestAlternatingPaths(self, n: int, redEdges: list[list[int]], blueEdges: list[list[int]]) -> list[int]:
+        def buildGraph(edges):
+            adj = [[] for _ in range(n)]
+            for u, v in edges:
+                adj[u].append(v)
+            return adj
+        
+        red, blue = buildGraph(redEdges), buildGraph(blueEdges)
+        adj = [red, blue]
+        INF = float("inf")
+        dist = [[INF] * 2 for _ in range(n)]
+        dist[0][0] = dist[0][1] = 0
+
+        q = deque([(0, 0), (0, 1)])
+        while q:
+            node, color = q.popleft()
+            for nei in adj[color][node]:
+                if dist[nei][color ^ 1] > dist[node][color] + 1:
+                    dist[nei][color ^ 1] = dist[node][color] + 1
+                    q.append((nei, color ^ 1))
+
+        answer = [0] + [-1] * (n - 1)
+        for i in range(1, n):
+            answer[i] = min(dist[i][0], dist[i][1])
+            if answer[i] == INF:
+                answer[i] = -1
+        return answer
+```
+
+```java
+public class Solution {
+    public int[] shortestAlternatingPaths(int n, int[][] redEdges, int[][] blueEdges) {
+        List<Integer>[][] adj = new ArrayList[2][n];
+        adj[0] = buildGraph(n, redEdges);
+        adj[1] = buildGraph(n, blueEdges);
+
+        int INF = Integer.MAX_VALUE;
+        int[][] dist = new int[n][2];
+
+        for (int i = 0; i < n; i++) Arrays.fill(dist[i], INF);
+        dist[0][0] = dist[0][1] = 0;
+
+        Queue<int[]> q = new LinkedList<>();
+        q.offer(new int[]{0, 0});
+        q.offer(new int[]{0, 1});
+
+        while (!q.isEmpty()) {
+            int[] cur = q.poll();
+            int node = cur[0], color = cur[1];
+
+            for (int nei : adj[color][node]) {
+                if (dist[nei][color ^ 1] > dist[node][color] + 1) {
+                    dist[nei][color ^ 1] = dist[node][color] + 1;
+                    q.offer(new int[]{nei, color ^ 1});
+                }
+            }
+        }
+
+        int[] answer = new int[n];
+        for (int i = 0; i < n; i++) {
+            answer[i] = Math.min(dist[i][0], dist[i][1]);
+            if (answer[i] == INF) answer[i] = -1;
+        }
+        return answer;
+    }
+
+    private List<Integer>[] buildGraph(int n, int[][] edges) {
+        List<Integer>[] adj = new ArrayList[n];
+        for (int i = 0; i < n; i++) {
+            adj[i] = new ArrayList<>();
+        }
+        for (int[] edge : edges) {
+            adj[edge[0]].add(edge[1]);
+        }
+        return adj;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    vector<int> shortestAlternatingPaths(int n, vector<vector<int>>& redEdges, vector<vector<int>>& blueEdges) {
+        vector<vector<int>> red = buildGraph(n, redEdges);
+        vector<vector<int>> blue = buildGraph(n, blueEdges);
+        vector<vector<int>> adj[] = {red, blue};
+
+        const int INF = 1e6;
+        vector<vector<int>> dist(n, vector<int>(2, INF));
+        dist[0][0] = dist[0][1] = 0;
+
+        queue<pair<int, int>> q;
+        q.push({0, 0});
+        q.push({0, 1});
+
+        while (!q.empty()) {
+            auto [node, color] = q.front();q.pop();
+            for (int nei : adj[color][node]) {
+                if (dist[nei][color ^ 1] > dist[node][color] + 1) {
+                    dist[nei][color ^ 1] = dist[node][color] + 1;
+                    q.push({nei, color ^ 1});
+                }
+            }
+        }
+
+        vector<int> answer(n, -1);
+        for (int i = 0; i < n; i++) {
+            answer[i] = min(dist[i][0], dist[i][1]);
+            if (answer[i] == INF) answer[i] = -1;
+        }
+        return answer;
+    }
+
+private:
+    vector<vector<int>> buildGraph(int n, vector<vector<int>>& edges) {
+        vector<vector<int>> adj(n);
+        for (auto& edge : edges) {
+            adj[edge[0]].push_back(edge[1]);
+        }
+        return adj;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number} n
+     * @param {number[][]} redEdges
+     * @param {number[][]} blueEdges
+     * @return {number[]}
+     */
+    shortestAlternatingPaths(n, redEdges, blueEdges) {
+        const red = this.buildGraph(n, redEdges);
+        const blue = this.buildGraph(n, blueEdges);
+        const adj = [red, blue];
+        const INF = 1e6;
+        const dist = Array.from({ length: n }, () => [INF, INF]);
+        dist[0][0] = dist[0][1] = 0;
+
+        const q = new Queue([[0, 0], [0, 1]]);
+        while (!q.isEmpty()) {
+            const [node, color] = q.pop();
+            for (const nei of adj[color][node]) {
+                if (dist[nei][color ^ 1] > dist[node][color] + 1) {
+                    dist[nei][color ^ 1] = dist[node][color] + 1;
+                    q.push([nei, color ^ 1]);
+                }
+            }
+        }
+
+        return Array.from({ length: n }, (_, i) => {
+            let minDist = Math.min(dist[i][0], dist[i][1]);
+            return minDist === INF ? -1 : minDist;
+        });
+    }
+
+    /**
+     * @param {number} n
+     * @param {number[][]} edges
+     * @return {number[][]}
+     */
+    buildGraph(n, edges) {
+        const adj = Array.from({ length: n }, () => []);
+        for (const [u, v] of edges) {
+            adj[u].push(v);
+        }
+        return adj;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(V + E)$
+* Space complexity: $O(V + E)$
+
+> Where $V$ is the number of vertices and $E$ is the number of edges.
+
+---
+
+## 3. Depth First Search
+
+::tabs-start
+
+```python
+class Solution:
+    def shortestAlternatingPaths(self, n: int, redEdges: list[list[int]], blueEdges: list[list[int]]) -> list[int]:
+        def buildGraph(edges):
+            adj = [[] for _ in range(n)]
+            for u, v in edges:
+                adj[u].append(v)
+            return adj
+
+        red, blue = buildGraph(redEdges), buildGraph(blueEdges)
+        adj = [red, blue]
+        INF = float("inf")
+        dist = [[INF] * 2 for _ in range(n)]
+        dist[0][0] = dist[0][1] = 0
+
+        def dfs(node, color):
+            for nei in adj[color][node]:
+                if dist[nei][color ^ 1] > dist[node][color] + 1:
+                    dist[nei][color ^ 1] = dist[node][color] + 1
+                    dfs(nei, color ^ 1)
+
+        dfs(0, 0)
+        dfs(0, 1)
+
+        answer = [0] + [-1] * (n - 1)
+        for i in range(1, n):
+            answer[i] = min(dist[i][0], dist[i][1])
+            if answer[i] == INF:
+                answer[i] = -1
+
+        return answer
+```
+
+```java
+public class Solution {
+    public int[] shortestAlternatingPaths(int n, int[][] redEdges, int[][] blueEdges) {
+        List<Integer>[][] adj = new ArrayList[2][n];
+        adj[0] = buildGraph(n, redEdges);
+        adj[1] = buildGraph(n, blueEdges);
+
+        int INF = Integer.MAX_VALUE;
+        int[][] dist = new int[n][2];
+        for (int i = 0; i < n; i++) Arrays.fill(dist[i], INF);
+        dist[0][0] = dist[0][1] = 0;
+
+        dfs(0, 0, adj, dist);
+        dfs(0, 1, adj, dist);
+
+        int[] answer = new int[n];
+        for (int i = 0; i < n; i++) {
+            answer[i] = Math.min(dist[i][0], dist[i][1]);
+            if (answer[i] == INF) answer[i] = -1;
+        }
+        return answer;
+    }
+
+    private void dfs(int node, int color, List<Integer>[][] adj, int[][] dist) {
+        for (int nei : adj[color][node]) {
+            if (dist[nei][color ^ 1] > dist[node][color] + 1) {
+                dist[nei][color ^ 1] = dist[node][color] + 1;
+                dfs(nei, color ^ 1, adj, dist);
+            }
+        }
+    }
+
+    private List<Integer>[] buildGraph(int n, int[][] edges) {
+        List<Integer>[] adj = new ArrayList[n];
+        for (int i = 0; i < n; i++) {
+            adj[i] = new ArrayList<>();
+        }
+        for (int[] edge : edges) {
+            adj[edge[0]].add(edge[1]);
+        }
+        return adj;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    vector<int> shortestAlternatingPaths(int n, vector<vector<int>>& redEdges, vector<vector<int>>& blueEdges) {
+        vector<vector<int>> adj[2] = {buildGraph(n, redEdges), buildGraph(n, blueEdges)};
+        
+        int INF = numeric_limits<int>::max();
+        vector<vector<int>> dist(n, vector<int>(2, INF));
+        dist[0][0] = dist[0][1] = 0;
+
+        dfs(0, 0, adj, dist);
+        dfs(0, 1, adj, dist);
+
+        vector<int> answer(n, -1);
+        for (int i = 0; i < n; i++) {
+            answer[i] = min(dist[i][0], dist[i][1]);
+            if (answer[i] == INF) answer[i] = -1;
+        }
+        return answer;
+    }
+
+private:
+    void dfs(int node, int color, vector<vector<int>> adj[], vector<vector<int>>& dist) {
+        for (int nei : adj[color][node]) {
+            if (dist[nei][color ^ 1] > dist[node][color] + 1) {
+                dist[nei][color ^ 1] = dist[node][color] + 1;
+                dfs(nei, color ^ 1, adj, dist);
+            }
+        }
+    }
+
+    vector<vector<int>> buildGraph(int n, vector<vector<int>>& edges) {
+        vector<vector<int>> adj(n);
+        for (auto& edge : edges) {
+            adj[edge[0]].push_back(edge[1]);
+        }
+        return adj;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number} n
+     * @param {number[][]} redEdges
+     * @param {number[][]} blueEdges
+     * @return {number[]}
+     */
+    shortestAlternatingPaths(n, redEdges, blueEdges) {
+        const INF = Number.MAX_SAFE_INTEGER;
+        const adj = [Array.from({ length: n }, () => []), 
+                     Array.from({ length: n }, () => [])];
+
+        redEdges.forEach(([u, v]) => adj[0][u].push(v));
+        blueEdges.forEach(([u, v]) => adj[1][u].push(v));
+
+        const dist = Array.from({ length: n }, () => [INF, INF]);
+        dist[0][0] = dist[0][1] = 0;
+
+        const dfs = (node, color) => {
+            adj[color][node].forEach(nei => {
+                if (dist[nei][color ^ 1] > dist[node][color] + 1) {
+                    dist[nei][color ^ 1] = dist[node][color] + 1;
+                    dfs(nei, color ^ 1);
+                }
+            });
+        };
+
+        dfs(0, 0);
+        dfs(0, 1);
+
+        return dist.map(([red, blue]) => {
+            let res = Math.min(red, blue);
+            return res === INF ? -1 : res;
+        });
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(V + E)$
+* Space complexity: $O(V + E)$
+
+> Where $V$ is the number of vertices and $E$ is the number of edges.
\ No newline at end of file
diff --git a/articles/smallest-string-starting-from-leaf.md b/articles/smallest-string-starting-from-leaf.md
new file mode 100644
index 000000000..d3d241adb
--- /dev/null
+++ b/articles/smallest-string-starting-from-leaf.md
@@ -0,0 +1,474 @@
+## 1. Depth First Search
+
+::tabs-start
+
+```python
+# Definition for a binary tree node.
+# class TreeNode:
+#     def __init__(self, val=0, left=None, right=None):
+#         self.val = val
+#         self.left = left
+#         self.right = right
+class Solution:
+    def smallestFromLeaf(self, root: Optional[TreeNode]) -> str:
+        def dfs(root, cur):
+            if not root:
+                return
+
+            cur = chr(ord('a') + root.val) + cur
+            if root.left and root.right:
+                return min(
+                    dfs(root.left, cur),
+                    dfs(root.right, cur)
+                )
+
+            if root.right:
+                return dfs(root.right, cur)
+            if root.left:
+                return dfs(root.left, cur)
+            return cur
+
+        return dfs(root, "")
+```
+
+```java
+/**
+ * Definition for a binary tree node.
+ * public class TreeNode {
+ *     int val;
+ *     TreeNode left;
+ *     TreeNode right;
+ *     TreeNode() {}
+ *     TreeNode(int val) { this.val = val; }
+ *     TreeNode(int val, TreeNode left, TreeNode right) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+public class Solution {
+    public String smallestFromLeaf(TreeNode root) {
+        return dfs(root, "");
+    }
+
+    private String dfs(TreeNode root, String cur) {
+        if (root == null) {
+            return null;
+        }
+
+        cur = (char) ('a' + root.val) + cur;
+        if (root.left != null && root.right != null) {
+            return min(dfs(root.left, cur), dfs(root.right, cur));
+        }
+
+        if (root.right != null) {
+            return dfs(root.right, cur);
+        }
+        if (root.left != null) {
+            return dfs(root.left, cur);
+        }
+        return cur;
+    }
+
+    private String min(String a, String b) {
+        if (a == null) return b;
+        if (b == null) return a;
+        return a.compareTo(b) < 0 ? a : b;
+    }
+}
+```
+
+```cpp
+/**
+ * Definition for a binary tree node.
+ * struct TreeNode {
+ *     int val;
+ *     TreeNode *left;
+ *     TreeNode *right;
+ *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
+ * };
+ */
+class Solution {
+public:
+    string smallestFromLeaf(TreeNode* root) {
+        return dfs(root, "");
+    }
+
+private:
+    string dfs(TreeNode* root, string cur) {
+        if (!root) return "";
+
+        cur = char('a' + root->val) + cur;
+        if (root->left && root->right) {
+            return min(dfs(root->left, cur), dfs(root->right, cur));
+        }
+
+        if (root->right) return dfs(root->right, cur);
+        if (root->left) return dfs(root->left, cur);
+        return cur;
+    }
+};
+```
+
+```javascript
+/**
+ * Definition for a binary tree node.
+ * class TreeNode {
+ *     constructor(val = 0, left = null, right = null) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+class Solution {
+    /**
+     * @param {TreeNode} root
+     * @return {string}
+     */
+    smallestFromLeaf(root) {
+        const min = (a, b) => {
+            if (!a) return b;
+            if (!b) return a;
+            return a < b ? a : b;
+        };
+
+        const dfs = (node, cur) => {
+            if (!node) return;
+            
+            cur = String.fromCharCode(97 + node.val) + cur;
+
+            if (node.left && node.right) {
+                return min(dfs(node.left, cur), dfs(node.right, cur));
+            }
+            if (node.left) return dfs(node.left, cur);
+            if (node.right) return dfs(node.right, cur);
+            return cur;
+        };
+
+        return dfs(root, "");
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n ^ 2)$
+* Space complexity: $O(n ^ 2)$
+
+---
+
+## 2. Breadth First Search
+
+::tabs-start
+
+```python
+# Definition for a binary tree node.
+# class TreeNode:
+#     def __init__(self, val=0, left=None, right=None):
+#         self.val = val
+#         self.left = left
+#         self.right = right
+class Solution:
+    def smallestFromLeaf(self, root: Optional[TreeNode]) -> str:
+        q = deque([(root, "")])
+        res = None
+
+        while q:
+            node, cur = q.popleft()
+            cur = chr(ord('a') + node.val) + cur
+
+            if not node.left and not node.right:
+                res = min(res, cur) if res else cur
+
+            if node.left:
+                q.append((node.left, cur))
+            if node.right:
+                q.append((node.right, cur))
+
+        return res
+```
+
+```java
+/**
+ * Definition for a binary tree node.
+ * public class TreeNode {
+ *     int val;
+ *     TreeNode left;
+ *     TreeNode right;
+ *     TreeNode() {}
+ *     TreeNode(int val) { this.val = val; }
+ *     TreeNode(int val, TreeNode left, TreeNode right) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+public class Solution {
+    public String smallestFromLeaf(TreeNode root) {
+        Queue<Pair<TreeNode, String>> q = new LinkedList<>();
+        q.offer(new Pair<>(root, ""));
+        String res = null;
+
+        while (!q.isEmpty()) {
+            Pair<TreeNode, String> pair = q.poll();
+            TreeNode node = pair.getKey();
+            String cur = (char) ('a' + node.val) + pair.getValue();
+
+            if (node.left == null && node.right == null) {
+                if (res == null || cur.compareTo(res) < 0) {
+                    res = cur;
+                }
+            }
+
+            if (node.left != null) q.offer(new Pair<>(node.left, cur));
+            if (node.right != null) q.offer(new Pair<>(node.right, cur));
+        }
+        return res;
+    }
+}
+```
+
+```cpp
+/**
+ * Definition for a binary tree node.
+ * struct TreeNode {
+ *     int val;
+ *     TreeNode *left;
+ *     TreeNode *right;
+ *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
+ * };
+ */
+class Solution {
+public:
+    string smallestFromLeaf(TreeNode* root) {
+        queue<pair<TreeNode*, string>> q;
+        q.push({root, ""});
+        string res;
+
+        while (!q.empty()) {
+            auto [node, cur] = q.front();
+            q.pop();
+            cur = char('a' + node->val) + cur;
+
+            if (!node->left && !node->right) {
+                if (res.empty() || cur < res) {
+                    res = cur;
+                }
+            }
+
+            if (node->left) q.push({node->left, cur});
+            if (node->right) q.push({node->right, cur});
+        }
+        return res;
+    }
+};
+```
+
+```javascript
+/**
+ * Definition for a binary tree node.
+ * class TreeNode {
+ *     constructor(val = 0, left = null, right = null) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+class Solution {
+    /**
+     * @param {TreeNode} root
+     * @return {string}
+     */
+    smallestFromLeaf(root) {
+        const q = new Queue();
+        q.push([root, ""]);
+        let res = null;
+
+        while (!q.isEmpty()) {
+            const [node, cur] = q.pop();
+            const newCur = String.fromCharCode(97 + node.val) + cur;
+
+            if (!node.left && !node.right) {
+                res = res === null || newCur < res ? newCur : res;
+            }
+
+            if (node.left) q.push([node.left, newCur]);
+            if (node.right) q.push([node.right, newCur]);
+        }
+
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n ^ 2)$
+* Space complexity: $O(n ^ 2)$
+
+---
+
+## 3. Iterative DFS
+
+::tabs-start
+
+```python
+# Definition for a binary tree node.
+# class TreeNode:
+#     def __init__(self, val=0, left=None, right=None):
+#         self.val = val
+#         self.left = left
+#         self.right = right
+class Solution:
+    def smallestFromLeaf(self, root: Optional[TreeNode]) -> str:
+        stack = [(root, "")]
+        res = None
+
+        while stack:
+            node, cur = stack.pop()
+            cur = chr(ord('a') + node.val) + cur
+
+            if not node.left and not node.right:
+                res = min(res, cur) if res else cur
+            
+            if node.right:
+                stack.append((node.right, cur))
+            if node.left:
+                stack.append((node.left, cur))
+        
+        return res
+```
+
+```java
+/**
+ * Definition for a binary tree node.
+ * public class TreeNode {
+ *     int val;
+ *     TreeNode left;
+ *     TreeNode right;
+ *     TreeNode() {}
+ *     TreeNode(int val) { this.val = val; }
+ *     TreeNode(int val, TreeNode left, TreeNode right) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+public class Solution {
+    public String smallestFromLeaf(TreeNode root) {
+        Stack<Pair<TreeNode, String>> stack = new Stack<>();
+        stack.push(new Pair<>(root, ""));
+        String res = null;
+
+        while (!stack.isEmpty()) {
+            Pair<TreeNode, String> pair = stack.pop();
+            TreeNode node = pair.getKey();
+            String cur = (char) ('a' + node.val) + pair.getValue();
+
+            if (node.left == null && node.right == null) {
+                if (res == null || cur.compareTo(res) < 0) {
+                    res = cur;
+                }
+            }
+
+            if (node.right != null) stack.push(new Pair<>(node.right, cur));
+            if (node.left != null) stack.push(new Pair<>(node.left, cur));
+        }
+        return res;
+    }
+}
+```
+
+```cpp
+/**
+ * Definition for a binary tree node.
+ * struct TreeNode {
+ *     int val;
+ *     TreeNode *left;
+ *     TreeNode *right;
+ *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
+ * };
+ */
+class Solution {
+public:
+    string smallestFromLeaf(TreeNode* root) {
+        stack<pair<TreeNode*, string>> stk;
+        stk.push({root, ""});
+        string res;
+
+        while (!stk.empty()) {
+            auto [node, cur] = stk.top();stk.pop();
+            cur = char('a' + node->val) + cur;
+
+            if (!node->left && !node->right) {
+                if (res.empty() || cur < res) {
+                    res = cur;
+                }
+            }
+
+            if (node->right) stk.push({node->right, cur});
+            if (node->left) stk.push({node->left, cur});
+        }
+        return res;
+    }
+};
+```
+
+```javascript
+/**
+ * Definition for a binary tree node.
+ * class TreeNode {
+ *     constructor(val = 0, left = null, right = null) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+class Solution {
+    /**
+     * @param {TreeNode} root
+     * @return {string}
+     */
+    smallestFromLeaf(root) {
+        const stack = [[root, ""]];
+        let res = null;
+
+        while (stack.length) {
+            const [node, cur] = stack.pop();
+            const newCur = String.fromCharCode(97 + node.val) + cur;
+
+            if (!node.left && !node.right) {
+                res = res === null || newCur < res ? newCur : res;
+            }
+
+            if (node.right) stack.push([node.right, newCur]);
+            if (node.left) stack.push([node.left, newCur]);
+        }
+
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n ^ 2)$
+* Space complexity: $O(n ^ 2)$
\ No newline at end of file
diff --git a/articles/split-linked-list-in-parts.md b/articles/split-linked-list-in-parts.md
new file mode 100644
index 000000000..5df42573a
--- /dev/null
+++ b/articles/split-linked-list-in-parts.md
@@ -0,0 +1,343 @@
+## 1. Convert To Array
+
+::tabs-start
+
+```python
+# Definition for singly-linked list.
+# class ListNode:
+#     def __init__(self, val=0, next=None):
+#         self.val = val
+#         self.next = next
+class Solution:
+    def splitListToParts(self, head: Optional[ListNode], k: int) -> List[Optional[ListNode]]:
+        arr, cur = [], head
+        while cur:
+            arr.append(cur)
+            cur = cur.next
+
+        N = len(arr)
+        base_len, remainder = N // k, N % k
+
+        res = [None] * k
+        start = 0
+        for i in range(k):
+            if start < N:
+                res[i] = arr[start]
+                tail = start + base_len - 1
+                if remainder:
+                    tail += 1
+                    remainder -= 1
+                arr[tail].next = None
+                start = tail + 1
+
+        return res
+```
+
+```java
+/**
+ * Definition for singly-linked list.
+ * public class ListNode {
+ *     int val;
+ *     ListNode next;
+ *     ListNode() {}
+ *     ListNode(int val) { this.val = val; }
+ *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
+ * }
+ */
+public class Solution {
+    public ListNode[] splitListToParts(ListNode head, int k) {
+        List<ListNode> arr = new ArrayList<>();
+        for (ListNode cur = head; cur != null; cur = cur.next) {
+            arr.add(cur);
+        }
+
+        int N = arr.size();
+        int base_len = N / k, remainder = N % k;
+
+        ListNode[] res = new ListNode[k];
+        int start = 0;
+        for (int i = 0; i < k; i++) {
+            if (start < N) {
+                res[i] = arr.get(start);
+                int tail = start + base_len - 1;
+                if (remainder > 0) {
+                    tail++;
+                    remainder--;
+                }
+                arr.get(tail).next = null;
+                start = tail + 1;
+            }
+        }
+
+        return res;
+    }
+}
+```
+
+```cpp
+/**
+ * Definition for singly-linked list.
+ * struct ListNode {
+ *     int val;
+ *     ListNode *next;
+ *     ListNode() : val(0), next(nullptr) {}
+ *     ListNode(int x) : val(x), next(nullptr) {}
+ *     ListNode(int x, ListNode *next) : val(x), next(next) {}
+ * };
+ */
+class Solution {
+public:
+    vector<ListNode*> splitListToParts(ListNode* head, int k) {
+        vector<ListNode*> arr;
+        for (ListNode* cur = head; cur != nullptr; cur = cur->next) {
+            arr.push_back(cur);
+        }
+
+        int N = arr.size();
+        int base_len = N / k, remainder = N % k;
+
+        vector<ListNode*> res(k, nullptr);
+        int start = 0;
+        for (int i = 0; i < k; i++) {
+            if (start < N) {
+                res[i] = arr[start];
+                int tail = start + base_len - 1;
+                if (remainder > 0) {
+                    tail++;
+                    remainder--;
+                }
+                arr[tail]->next = nullptr;
+                start = tail + 1;
+            }
+        }
+
+        return res;
+    }
+};
+```
+
+```javascript
+/**
+ * Definition for singly-linked list.
+ * class ListNode {
+ *     constructor(val = 0, next = null) {
+ *         this.val = val;
+ *         this.next = next;
+ *     }
+ * }
+ */
+class Solution {
+    /**
+     * @param {ListNode} head
+     * @param {number} k
+     * @return {ListNode[]}
+     */
+    splitListToParts(head, k) {
+        let arr = [];
+        for (let cur = head; cur !== null; cur = cur.next) {
+            arr.push(cur);
+        }
+
+        let N = arr.length;
+        let base_len = Math.floor(N / k), remainder = N % k;
+
+        let res = new Array(k).fill(null);
+        let start = 0;
+        for (let i = 0; i < k; i++) {
+            if (start < N) {
+                res[i] = arr[start];
+                let tail = start + base_len - 1;
+                if (remainder > 0) {
+                    tail++;
+                    remainder--;
+                }
+                arr[tail].next = null;
+                start = tail + 1;
+            }
+        }
+
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(n)$
+
+---
+
+## 2. Iteration
+
+::tabs-start
+
+```python
+# Definition for singly-linked list.
+# class ListNode:
+#     def __init__(self, val=0, next=None):
+#         self.val = val
+#         self.next = next
+class Solution:
+    def splitListToParts(self, head: Optional[ListNode], k: int) -> List[Optional[ListNode]]:
+        length, curr = 0, head
+        while curr:
+            curr = curr.next
+            length += 1
+
+        base_len, remainder = length // k, length % k
+        curr, res = head, []
+        
+        for i in range(k):
+            res.append(curr)
+            for j in range(base_len - 1 + (1 if remainder else 0)):
+                if not curr:
+                    break
+                curr = curr.next
+            remainder -= 1 if remainder else 0
+            if curr:
+                curr.next, curr = None, curr.next
+
+        return res
+```
+
+```java
+/**
+ * Definition for singly-linked list.
+ * public class ListNode {
+ *     int val;
+ *     ListNode next;
+ *     ListNode() {}
+ *     ListNode(int val) { this.val = val; }
+ *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
+ * }
+ */
+public class Solution {
+    public ListNode[] splitListToParts(ListNode head, int k) {
+        int length = 0;
+        ListNode curr = head;
+        while (curr != null) {
+            curr = curr.next;
+            length++;
+        }
+
+        int baseLen = length / k, remainder = length % k;
+        ListNode[] res = new ListNode[k];
+        curr = head;
+
+        for (int i = 0; i < k; i++) {
+            res[i] = curr;
+            for (int j = 0; j < baseLen - 1 + (remainder > 0 ? 1 : 0); j++) {
+                if (curr == null) break;
+                curr = curr.next;
+            }
+            if (curr != null) {
+                ListNode temp = curr.next;
+                curr.next = null;
+                curr = temp;
+            }
+            remainder--;
+        }
+        return res;
+    }
+}
+```
+
+```cpp
+/**
+ * Definition for singly-linked list.
+ * struct ListNode {
+ *     int val;
+ *     ListNode *next;
+ *     ListNode() : val(0), next(nullptr) {}
+ *     ListNode(int x) : val(x), next(nullptr) {}
+ *     ListNode(int x, ListNode *next) : val(x), next(next) {}
+ * };
+ */
+class Solution {
+public:
+    vector<ListNode*> splitListToParts(ListNode* head, int k) {
+        int length = 0;
+        ListNode* curr = head;
+        while (curr) {
+            curr = curr->next;
+            length++;
+        }
+
+        int baseLen = length / k, remainder = length % k;
+        vector<ListNode*> res(k, nullptr);
+        curr = head;
+
+        for (int i = 0; i < k; i++) {
+            res[i] = curr;
+            for (int j = 0; j < baseLen - 1 + (remainder > 0 ? 1 : 0); j++) {
+                if (!curr) break;
+                curr = curr->next;
+            }
+            if (curr) {
+                ListNode* temp = curr->next;
+                curr->next = nullptr;
+                curr = temp;
+            }
+            remainder--;
+        }
+        return res;
+    }
+};
+```
+
+```javascript
+/**
+ * Definition for singly-linked list.
+ * class ListNode {
+ *     constructor(val = 0, next = null) {
+ *         this.val = val;
+ *         this.next = next;
+ *     }
+ * }
+ */
+class Solution {
+    /**
+     * @param {ListNode} head
+     * @param {number} k
+     * @return {ListNode[]}
+     */
+    splitListToParts(head, k) {
+        let length = 0, curr = head;
+        while (curr) {
+            curr = curr.next;
+            length++;
+        }
+
+        let baseLen = Math.floor(length / k), remainder = length % k;
+        let res = new Array(k).fill(null);
+        curr = head;
+
+        for (let i = 0; i < k; i++) {
+            res[i] = curr;
+            for (let j = 0; j < baseLen - 1 + (remainder > 0 ? 1 : 0); j++) {
+                if (!curr) break;
+                curr = curr.next;
+            }
+            if (curr) {
+                let temp = curr.next;
+                curr.next = null;
+                curr = temp;
+            }
+            remainder--;
+        }
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity:
+    * $O(1)$ extra space.
+    * $O(n)$ space for the output array.
\ No newline at end of file
diff --git a/articles/sum-root-to-leaf-numbers.md b/articles/sum-root-to-leaf-numbers.md
new file mode 100644
index 000000000..02bfd196e
--- /dev/null
+++ b/articles/sum-root-to-leaf-numbers.md
@@ -0,0 +1,652 @@
+## 1. Depth First Search
+
+::tabs-start
+
+```python
+# Definition for a binary tree node.
+# class TreeNode:
+#     def __init__(self, val=0, left=None, right=None):
+#         self.val = val
+#         self.left = left
+#         self.right = right
+class Solution:
+    def sumNumbers(self, root: TreeNode) -> int:
+        def dfs(cur, num):
+            if not cur:
+                return 0
+
+            num = num * 10 + cur.val
+            if not cur.left and not cur.right:
+                return num
+            return dfs(cur.left, num) + dfs(cur.right, num)
+
+        return dfs(root, 0)
+```
+
+```java
+/**
+ * Definition for a binary tree node.
+ * public class TreeNode {
+ *     int val;
+ *     TreeNode left;
+ *     TreeNode right;
+ *     TreeNode() {}
+ *     TreeNode(int val) { this.val = val; }
+ *     TreeNode(int val, TreeNode left, TreeNode right) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+public class Solution {
+    public int sumNumbers(TreeNode root) {
+        return dfs(root, 0);
+    }
+
+    private int dfs(TreeNode cur, int num) {
+        if (cur == null) return 0;
+
+        num = num * 10 + cur.val;
+        if (cur.left == null && cur.right == null) return num;
+
+        return dfs(cur.left, num) + dfs(cur.right, num);
+    }
+}
+```
+
+```cpp
+/**
+ * Definition for a binary tree node.
+ * struct TreeNode {
+ *     int val;
+ *     TreeNode *left;
+ *     TreeNode *right;
+ *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
+ * };
+ */
+class Solution {
+public:
+    int sumNumbers(TreeNode* root) {
+        return dfs(root, 0);
+    }
+
+private:
+    int dfs(TreeNode* cur, int num) {
+        if (!cur) return 0;
+
+        num = num * 10 + cur->val;
+        if (!cur->left && !cur->right) return num;
+
+        return dfs(cur->left, num) + dfs(cur->right, num);
+    }
+};
+```
+
+```javascript
+/**
+ * Definition for a binary tree node.
+ * class TreeNode {
+ *     constructor(val = 0, left = null, right = null) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+class Solution {
+    /**
+     * @param {TreeNode} root
+     * @return {number}
+     */
+    sumNumbers(root) {
+        const dfs = (cur, num) => {
+            if (!cur) return 0;
+
+            num = num * 10 + cur.val;
+            if (!cur.left && !cur.right) return num;
+
+            return dfs(cur.left, num) + dfs(cur.right, num);
+        };
+
+        return dfs(root, 0);
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(h)$ for recursion stack.
+
+> Where $n$ is the number of nodes and $h$ is the height of the given tree.
+
+---
+
+## 2. Breadth First Search
+
+::tabs-start
+
+```python
+# Definition for a binary tree node.
+# class TreeNode:
+#     def __init__(self, val=0, left=None, right=None):
+#         self.val = val
+#         self.left = left
+#         self.right = right
+class Solution:
+    def sumNumbers(self, root: TreeNode) -> int:
+        res = 0
+        q = deque([(root, 0)])
+        while q:
+            cur, num = q.popleft()
+            num = num * 10 + cur.val
+            if not cur.left and not cur.right:
+                res += num
+                continue
+
+            if cur.left:
+                q.append((cur.left, num))
+            if cur.right:
+                q.append((cur.right, num))
+
+        return res
+```
+
+```java
+/**
+ * Definition for a binary tree node.
+ * public class TreeNode {
+ *     int val;
+ *     TreeNode left;
+ *     TreeNode right;
+ *     TreeNode() {}
+ *     TreeNode(int val) { this.val = val; }
+ *     TreeNode(int val, TreeNode left, TreeNode right) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+public class Solution {
+    public int sumNumbers(TreeNode root) {
+        int res = 0;
+        Queue<Pair<TreeNode, Integer>> q = new LinkedList<>();
+        q.offer(new Pair<>(root, 0));
+        while (!q.isEmpty()) {
+            Pair<TreeNode, Integer> p = q.poll();
+            TreeNode cur = p.getKey();
+            int num = p.getValue() * 10 + cur.val;
+            if (cur.left == null && cur.right == null) {
+                res += num;
+                continue;
+            }
+
+            if (cur.left != null) q.offer(new Pair<>(cur.left, num));
+            if (cur.right != null) q.offer(new Pair<>(cur.right, num));
+        }
+
+        return res;
+    }
+}
+```
+
+```cpp
+/**
+ * Definition for a binary tree node.
+ * struct TreeNode {
+ *     int val;
+ *     TreeNode *left;
+ *     TreeNode *right;
+ *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
+ * };
+ */
+class Solution {
+public:
+    int sumNumbers(TreeNode* root) {
+        int res = 0;
+        queue<pair<TreeNode*, int>> q;
+        q.push({root, 0});
+        while (!q.empty()) {
+            auto [cur, num] = q.front();q.pop();
+            num = num * 10 + cur->val;
+            if (!cur->left && !cur->right) {
+                res += num;
+                continue;
+            }
+
+            if (cur->left) q.push({cur->left, num});
+            if (cur->right) q.push({cur->right, num});
+        }
+
+        return res;
+    }
+};
+```
+
+```javascript
+/**
+ * Definition for a binary tree node.
+ * class TreeNode {
+ *     constructor(val = 0, left = null, right = null) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+class Solution {
+    /**
+     * @param {TreeNode} root
+     * @return {number}
+     */
+    sumNumbers(root) {
+        let res = 0;
+        const q = new Queue([[root, 0]]);
+        while (!q.isEmpty()) {
+            const [cur, num] = q.pop();
+            const newNum = num * 10 + cur.val;
+            if (!cur.left && !cur.right) {
+                res += newNum;
+                continue;
+            }
+
+            if (cur.left) q.push([cur.left, newNum]);
+            if (cur.right) q.push([cur.right, newNum]);
+        }
+
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(n)$
+
+---
+
+## 3. Iterative DFS
+
+::tabs-start
+
+```python
+# Definition for a binary tree node.
+# class TreeNode:
+#     def __init__(self, val=0, left=None, right=None):
+#         self.val = val
+#         self.left = left
+#         self.right = right
+class Solution:
+    def sumNumbers(self, root: Optional[TreeNode]) -> int:
+        res = 0
+        stack = []
+        cur, num = root, 0
+
+        while cur or stack:
+            if cur:
+                num = num * 10 + cur.val
+                if not cur.left and not cur.right:
+                    res += num
+
+                stack.append((cur.right, num))
+                cur = cur.left
+            else:
+                cur, num = stack.pop()
+
+        return res
+```
+
+```java
+/**
+ * Definition for a binary tree node.
+ * public class TreeNode {
+ *     int val;
+ *     TreeNode left;
+ *     TreeNode right;
+ *     TreeNode() {}
+ *     TreeNode(int val) { this.val = val; }
+ *     TreeNode(int val, TreeNode left, TreeNode right) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+public class Solution {
+    public int sumNumbers(TreeNode root) {
+        int res = 0, num = 0;
+        Stack<Pair<TreeNode, Integer>> stack = new Stack<>();
+        TreeNode cur = root;
+
+        while (cur != null || !stack.isEmpty()) {
+            if (cur != null) {
+                num = num * 10 + cur.val;
+                if (cur.left == null && cur.right == null)
+                    res += num;
+                
+                stack.push(new Pair<>(cur.right, num));
+                cur = cur.left;
+            } else {
+                Pair<TreeNode, Integer> p = stack.pop();
+                cur = p.getKey();
+                num = p.getValue();
+            }
+        }
+        return res;
+    }
+}
+```
+
+```cpp
+/**
+ * Definition for a binary tree node.
+ * struct TreeNode {
+ *     int val;
+ *     TreeNode *left;
+ *     TreeNode *right;
+ *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
+ * };
+ */
+class Solution {
+public:
+    int sumNumbers(TreeNode* root) {
+        int res = 0;
+        stack<pair<TreeNode*, int>> st;
+        TreeNode* cur = root;
+        int num = 0;
+
+        while (cur || !st.empty()) {
+            if (cur) {
+                num = num * 10 + cur->val;
+                if (!cur->left && !cur->right) 
+                    res += num;
+                
+                st.push({cur->right, num});
+                cur = cur->left;
+            } else {
+                cur = st.top().first;
+                num = st.top().second;
+                st.pop();
+            }
+        }
+        return res;
+    }
+};
+```
+
+```javascript
+/**
+ * Definition for a binary tree node.
+ * class TreeNode {
+ *     constructor(val = 0, left = null, right = null) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+class Solution {
+    /**
+     * @param {TreeNode} root
+     * @return {number}
+     */
+    sumNumbers(root) {
+        let res = 0, num = 0;
+        let stack = [];
+        let cur = root;
+
+        while (cur || stack.length) {
+            if (cur) {
+                num = num * 10 + cur.val;
+                if (!cur.left && !cur.right) 
+                    res += num;
+                
+                stack.push([cur.right, num]);
+                cur = cur.left;
+            } else {
+                [cur, num] = stack.pop();
+            }
+        }
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(h)$
+
+> Where $n$ is the number of nodes and $h$ is the height of the given tree.
+
+---
+
+## 4. Morris Travrsal
+
+::tabs-start
+
+```python
+# Definition for a binary tree node.
+# class TreeNode:
+#     def __init__(self, val=0, left=None, right=None):
+#         self.val = val
+#         self.left = left
+#         self.right = right
+class Solution:
+    def sumNumbers(self, root: Optional[TreeNode]) -> int:
+        res = 0
+        cur = root
+        num = 0
+        power = [1] * 10
+        for i in range(1, 10):
+            power[i] *= power[i - 1] * 10
+
+        while cur:
+            if not cur.left:
+                num = num * 10 + cur.val
+                if not cur.right:
+                    res += num
+                cur = cur.right
+            else:
+                prev = cur.left
+                steps = 1
+                while prev.right and prev.right != cur:
+                    prev = prev.right
+                    steps += 1
+
+                if not prev.right:
+                    prev.right = cur
+                    num = num * 10 + cur.val
+                    cur = cur.left
+                else:
+                    prev.right = None
+                    if not prev.left:
+                        res += num
+                    num //= power[steps]
+                    cur = cur.right
+
+        return res
+```
+
+```java
+/**
+ * Definition for a binary tree node.
+ * public class TreeNode {
+ *     int val;
+ *     TreeNode left;
+ *     TreeNode right;
+ *     TreeNode() {}
+ *     TreeNode(int val) { this.val = val; }
+ *     TreeNode(int val, TreeNode left, TreeNode right) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+public class Solution {
+    public int sumNumbers(TreeNode root) {
+        int res = 0, num = 0;
+        int[] power = new int[10];
+        power[0] = 1;
+        for (int i = 1; i < 10; i++) {
+            power[i] = power[i - 1] * 10;
+        }
+
+        TreeNode cur = root;
+        while (cur != null) {
+            if (cur.left == null) {
+                num = num * 10 + cur.val;
+                if (cur.right == null) res += num;
+                cur = cur.right;
+            } else {
+                TreeNode prev = cur.left;
+                int steps = 1;
+                while (prev.right != null && prev.right != cur) {
+                    prev = prev.right;
+                    steps++;
+                }
+
+                if (prev.right == null) {
+                    prev.right = cur;
+                    num = num * 10 + cur.val;
+                    cur = cur.left;
+                } else {
+                    prev.right = null;
+                    if (prev.left == null) res += num;
+                    num /= power[steps];
+                    cur = cur.right;
+                }
+            }
+        }
+        return res;
+    }
+}
+```
+
+```cpp
+/**
+ * Definition for a binary tree node.
+ * struct TreeNode {
+ *     int val;
+ *     TreeNode *left;
+ *     TreeNode *right;
+ *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
+ * };
+ */
+class Solution {
+public:
+    int sumNumbers(TreeNode* root) {
+        int res = 0, num = 0;
+        int power[10] = {1};
+        for (int i = 1; i < 10; i++) {
+            power[i] = power[i - 1] * 10;
+        }
+
+        TreeNode* cur = root;
+        while (cur) {
+            if (!cur->left) {
+                num = num * 10 + cur->val;
+                if (!cur->right) res += num;
+                cur = cur->right;
+            } else {
+                TreeNode* prev = cur->left;
+                int steps = 1;
+                while (prev->right && prev->right != cur) {
+                    prev = prev->right;
+                    steps++;
+                }
+
+                if (!prev->right) {
+                    prev->right = cur;
+                    num = num * 10 + cur->val;
+                    cur = cur->left;
+                } else {
+                    prev->right = nullptr;
+                    if (!prev->left) res += num;
+                    num /= power[steps];
+                    cur = cur->right;
+                }
+            }
+        }
+        return res;
+    }
+};
+```
+
+```javascript
+/**
+ * Definition for a binary tree node.
+ * class TreeNode {
+ *     constructor(val = 0, left = null, right = null) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+class Solution {
+    /**
+     * @param {TreeNode} root
+     * @return {number}
+     */
+    sumNumbers(root) {
+        let res = 0, num = 0;
+        let power = Array(10).fill(1);
+        for (let i = 1; i < 10; i++) {
+            power[i] = power[i - 1] * 10;
+        }
+
+        let cur = root;
+        while (cur) {
+            if (!cur.left) {
+                num = num * 10 + cur.val;
+                if (!cur.right) res += num;
+                cur = cur.right;
+            } else {
+                let prev = cur.left, steps = 1;
+                while (prev.right && prev.right !== cur) {
+                    prev = prev.right;
+                    steps++;
+                }
+
+                if (!prev.right) {
+                    prev.right = cur;
+                    num = num * 10 + cur.val;
+                    cur = cur.left;
+                } else {
+                    prev.right = null;
+                    if (!prev.left) res += num;
+                    num = Math.floor(num / power[steps]);
+                    cur = cur.right;
+                }
+            }
+        }
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(1)$ extra space.
\ No newline at end of file
diff --git a/articles/trim-a-binary-search-tree.md b/articles/trim-a-binary-search-tree.md
new file mode 100644
index 000000000..6a7eb3f21
--- /dev/null
+++ b/articles/trim-a-binary-search-tree.md
@@ -0,0 +1,488 @@
+## 1. Depth First Search
+
+::tabs-start
+
+```python
+# Definition for a binary tree node.
+# class TreeNode:
+#     def __init__(self, val=0, left=None, right=None):
+#         self.val = val
+#         self.left = left
+#         self.right = right
+class Solution:
+    def trimBST(self, root: Optional[TreeNode], low: int, high: int) -> Optional[TreeNode]:
+        if not root:
+            return None
+
+        if root.val > high:
+            return self.trimBST(root.left, low, high)
+        if root.val < low:
+            return self.trimBST(root.right, low, high)
+
+        root.left = self.trimBST(root.left, low, high)
+        root.right = self.trimBST(root.right, low, high)
+        return root
+```
+
+```java
+/**
+ * Definition for a binary tree node.
+ * public class TreeNode {
+ *     int val;
+ *     TreeNode left;
+ *     TreeNode right;
+ *     TreeNode() {}
+ *     TreeNode(int val) { this.val = val; }
+ *     TreeNode(int val, TreeNode left, TreeNode right) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+public class Solution {
+    public TreeNode trimBST(TreeNode root, int low, int high) {
+        if (root == null) {
+            return null;
+        }
+
+        if (root.val > high) {
+            return trimBST(root.left, low, high);
+        }
+        if (root.val < low) {
+            return trimBST(root.right, low, high);
+        }
+
+        root.left = trimBST(root.left, low, high);
+        root.right = trimBST(root.right, low, high);
+        return root;
+    }
+}
+```
+
+```cpp
+/**
+ * Definition for a binary tree node.
+ * struct TreeNode {
+ *     int val;
+ *     TreeNode *left;
+ *     TreeNode *right;
+ *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
+ * };
+ */
+class Solution {
+public:
+    TreeNode* trimBST(TreeNode* root, int low, int high) {
+        if (!root) return nullptr;
+
+        if (root->val > high) {
+            return trimBST(root->left, low, high);
+        }
+        if (root->val < low) {
+            return trimBST(root->right, low, high);
+        }
+
+        root->left = trimBST(root->left, low, high);
+        root->right = trimBST(root->right, low, high);
+        return root;
+    }
+};
+```
+
+```javascript
+/**
+ * Definition for a binary tree node.
+ * class TreeNode {
+ *     constructor(val = 0, left = null, right = null) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+class Solution {
+    /**
+     * @param {TreeNode} root
+     * @param {number} low
+     * @param {number} high
+     * @return {TreeNode}
+     */
+    trimBST(root, low, high) {
+        if (!root) return null;
+
+        if (root.val > high) return this.trimBST(root.left, low, high);
+        if (root.val < low) return this.trimBST(root.right, low, high);
+
+        root.left = this.trimBST(root.left, low, high);
+        root.right = this.trimBST(root.right, low, high);
+        return root;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(n)$ for recursion stack.
+
+---
+
+## 2. Iterative DFS
+
+::tabs-start
+
+```python
+# Definition for a binary tree node.
+# class TreeNode:
+#     def __init__(self, val=0, left=None, right=None):
+#         self.val = val
+#         self.left = left
+#         self.right = right
+class Solution:
+    def trimBST(self, root, low, high):
+        while root and (root.val < low or root.val > high):
+            if root.val < low:
+                root = root.right
+            else:
+                root = root.left
+
+        stack = [root]
+        while stack:
+            node = stack.pop()
+            if not node:
+                continue
+            left_out = node.left and node.left.val < low
+            right_out = node.right and node.right.val > high
+            if left_out:
+                node.left = node.left.right
+            if right_out:
+                node.right = node.right.left
+            if left_out or right_out:
+                stack.append(node)
+            else:
+                if node.left:
+                    stack.append(node.left)
+                if node.right:
+                    stack.append(node.right)
+        return root
+```
+
+```java
+/**
+ * Definition for a binary tree node.
+ * public class TreeNode {
+ *     int val;
+ *     TreeNode left;
+ *     TreeNode right;
+ *     TreeNode() {}
+ *     TreeNode(int val) { this.val = val; }
+ *     TreeNode(int val, TreeNode left, TreeNode right) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+public class Solution {
+    public TreeNode trimBST(TreeNode root, int low, int high) {
+        while (root != null && (root.val < low || root.val > high)) {
+            root = (root.val < low) ? root.right : root.left;
+        }
+
+        Stack<TreeNode> stack = new Stack<>();
+        stack.push(root);
+        
+        while (!stack.isEmpty()) {
+            TreeNode node = stack.pop();
+            if (node == null) continue;
+            
+            boolean leftOut = (node.left != null && node.left.val < low);
+            boolean rightOut = (node.right != null && node.right.val > high);
+            
+            if (leftOut) node.left = node.left.right;
+            if (rightOut) node.right = node.right.left;
+
+            if (leftOut || rightOut) {
+                stack.push(node);
+            } else {
+                if (node.left != null) stack.push(node.left);
+                if (node.right != null) stack.push(node.right);
+            }
+        }
+        
+        return root;
+    }
+}
+```
+
+```cpp
+/**
+ * Definition for a binary tree node.
+ * struct TreeNode {
+ *     int val;
+ *     TreeNode *left;
+ *     TreeNode *right;
+ *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
+ * };
+ */
+class Solution {
+public:
+    TreeNode* trimBST(TreeNode* root, int low, int high) {
+        while (root && (root->val < low || root->val > high)) {
+            root = (root->val < low) ? root->right : root->left;
+        }
+
+        stack<TreeNode*> stack;
+        stack.push(root);
+
+        while (!stack.empty()) {
+            TreeNode* node = stack.top();
+            stack.pop();
+            if (!node) continue;
+
+            bool leftOut = (node->left && node->left->val < low);
+            bool rightOut = (node->right && node->right->val > high);
+
+            if (leftOut) node->left = node->left->right;
+            if (rightOut) node->right = node->right->left;
+
+            if (leftOut || rightOut) {
+                stack.push(node);
+            } else {
+                if (node->left) stack.push(node->left);
+                if (node->right) stack.push(node->right);
+            }
+        }
+
+        return root;
+    }
+};
+```
+
+```javascript
+/**
+ * Definition for a binary tree node.
+ * class TreeNode {
+ *     constructor(val = 0, left = null, right = null) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+class Solution {
+    /**
+     * @param {TreeNode} root
+     * @param {number} low
+     * @param {number} high
+     * @return {TreeNode}
+     */
+    trimBST(root, low, high) {
+        while (root && (root.val < low || root.val > high)) {
+            root = (root.val < low) ? root.right : root.left;
+        }
+
+        const stack = [root];
+
+        while (stack.length > 0) {
+            let node = stack.pop();
+            if (!node) continue;
+
+            let leftOut = node.left && node.left.val < low;
+            let rightOut = node.right && node.right.val > high;
+
+            if (leftOut) node.left = node.left.right;
+            if (rightOut) node.right = node.right.left;
+
+            if (leftOut || rightOut) {
+                stack.push(node);
+            } else {
+                if (node.left) stack.push(node.left);
+                if (node.right) stack.push(node.right);
+            }
+        }
+
+        return root;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(n)$
+
+---
+
+## 3. Iterative DFS (Optimal)
+
+::tabs-start
+
+```python
+# Definition for a binary tree node.
+# class TreeNode:
+#     def __init__(self, val=0, left=None, right=None):
+#         self.val = val
+#         self.left = left
+#         self.right = right
+class Solution:
+    def trimBST(self, root: Optional[TreeNode], low: int, high: int) -> Optional[TreeNode]:
+        while root and (root.val < low or root.val > high):
+            root = root.right if root.val < low else root.left
+
+        tmpRoot = root
+        while root:
+            while root.left and root.left.val < low:
+                root.left = root.left.right
+            root = root.left
+
+        root = tmpRoot
+        while root:
+            while root.right and root.right.val > high:
+                root.right = root.right.left
+            root = root.right
+
+        return tmpRoot
+```
+
+```java
+/**
+ * Definition for a binary tree node.
+ * public class TreeNode {
+ *     int val;
+ *     TreeNode left;
+ *     TreeNode right;
+ *     TreeNode() {}
+ *     TreeNode(int val) { this.val = val; }
+ *     TreeNode(int val, TreeNode left, TreeNode right) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+public class Solution {
+    public TreeNode trimBST(TreeNode root, int low, int high) {
+        while (root != null && (root.val < low || root.val > high)) {
+            root = (root.val < low) ? root.right : root.left;
+        }
+
+        TreeNode tmpRoot = root;
+        while (root != null) {
+            while (root.left != null && root.left.val < low) {
+                root.left = root.left.right;
+            }
+            root = root.left;
+        }
+
+        root = tmpRoot;
+        while (root != null) {
+            while (root.right != null && root.right.val > high) {
+                root.right = root.right.left;
+            }
+            root = root.right;
+        }
+
+        return tmpRoot;
+    }
+}
+```
+
+```cpp
+/**
+ * Definition for a binary tree node.
+ * struct TreeNode {
+ *     int val;
+ *     TreeNode *left;
+ *     TreeNode *right;
+ *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
+ * };
+ */
+class Solution {
+public:
+    TreeNode* trimBST(TreeNode* root, int low, int high) {
+        while (root && (root->val < low || root->val > high)) {
+            root = (root->val < low) ? root->right : root->left;
+        }
+
+        TreeNode* tmpRoot = root;
+        while (root) {
+            while (root->left && root->left->val < low) {
+                root->left = root->left->right;
+            }
+            root = root->left;
+        }
+
+        root = tmpRoot;
+        while (root) {
+            while (root->right && root->right->val > high) {
+                root->right = root->right->left;
+            }
+            root = root->right;
+        }
+
+        return tmpRoot;
+    }
+};
+```
+
+```javascript
+/**
+ * Definition for a binary tree node.
+ * class TreeNode {
+ *     constructor(val = 0, left = null, right = null) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+class Solution {
+    /**
+     * @param {TreeNode} root
+     * @param {number} low
+     * @param {number} high
+     * @return {TreeNode}
+     */
+    trimBST(root, low, high) {
+        while (root && (root.val < low || root.val > high)) {
+            root = (root.val < low) ? root.right : root.left;
+        }
+
+        let tmpRoot = root;
+        while (root) {
+            while (root.left && root.left.val < low) {
+                root.left = root.left.right;
+            }
+            root = root.left;
+        }
+
+        root = tmpRoot;
+        while (root) {
+            while (root.right && root.right.val > high) {
+                root.right = root.right.left;
+            }
+            root = root.right;
+        }
+
+        return tmpRoot;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(1)$ extra space.
\ No newline at end of file
diff --git a/articles/unique-binary-search-trees-ii.md b/articles/unique-binary-search-trees-ii.md
new file mode 100644
index 000000000..3c3a4ccee
--- /dev/null
+++ b/articles/unique-binary-search-trees-ii.md
@@ -0,0 +1,670 @@
+## 1. Recursion
+
+::tabs-start
+
+```python
+# Definition for a binary tree node.
+# class TreeNode:
+#     def __init__(self, val=0, left=None, right=None):
+#         self.val = val
+#         self.left = left
+#         self.right = right
+class Solution:
+    def generateTrees(self, n: int) -> List[Optional[TreeNode]]:
+        def generate(left, right):
+            if left > right:
+                return [None]
+
+            res = []
+            for val in range(left, right + 1):
+                for leftTree in generate(left, val - 1):
+                    for rightTree in generate(val + 1, right):
+                        root = TreeNode(val, leftTree, rightTree)
+                        res.append(root)
+            return res
+
+        return generate(1, n)
+```
+
+```java
+/**
+ * Definition for a binary tree node.
+ * public class TreeNode {
+ *     int val;
+ *     TreeNode left;
+ *     TreeNode right;
+ *     TreeNode() {}
+ *     TreeNode(int val) { this.val = val; }
+ *     TreeNode(int val, TreeNode left, TreeNode right) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+public class Solution {
+    public List<TreeNode> generateTrees(int n) {
+        return generate(1, n);
+    }
+
+    private List<TreeNode> generate(int left, int right) {
+        List<TreeNode> res = new ArrayList<>();
+        if (left > right) {
+            res.add(null);
+            return res;
+        }
+
+        for (int val = left; val <= right; val++) {
+            List<TreeNode> leftTrees = generate(left, val - 1);
+            List<TreeNode> rightTrees = generate(val + 1, right);
+
+            for (TreeNode leftTree : leftTrees) {
+                for (TreeNode rightTree : rightTrees) {
+                    res.add(new TreeNode(val, leftTree, rightTree));
+                }
+            }
+        }
+        return res;
+    }
+}
+```
+
+```cpp
+/**
+ * Definition for a binary tree node.
+ * struct TreeNode {
+ *     int val;
+ *     TreeNode *left;
+ *     TreeNode *right;
+ *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
+ * };
+ */
+class Solution {
+public:
+    vector<TreeNode*> generateTrees(int n) {
+        return generate(1, n);
+    }
+
+private:
+    vector<TreeNode*> generate(int left, int right) {
+        if (left > right) return {nullptr};
+
+        vector<TreeNode*> res;
+        for (int val = left; val <= right; val++) {
+            vector<TreeNode*> leftTrees = generate(left, val - 1);
+            vector<TreeNode*> rightTrees = generate(val + 1, right);
+
+            for (auto& leftTree : leftTrees) {
+                for (auto& rightTree : rightTrees) {
+                    res.push_back(new TreeNode(val, leftTree, rightTree));
+                }
+            }
+        }
+        return res;
+    }
+};
+```
+
+```javascript
+/**
+ * Definition for a binary tree node.
+ * class TreeNode {
+ *     constructor(val = 0, left = null, right = null) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+class Solution {
+    /**
+     * @param {number} n
+     * @return {TreeNode[]}
+     */
+    generateTrees(n) {
+        const generate = (left, right) => {
+            if (left > right) return [null];
+
+            let res = [];
+            for (let val = left; val <= right; val++) {
+                let leftTrees = generate(left, val - 1);
+                let rightTrees = generate(val + 1, right);
+
+                for (let leftTree of leftTrees) {
+                    for (let rightTree of rightTrees) {
+                        res.push(new TreeNode(val, leftTree, rightTree));
+                    }
+                }
+            }
+            return res;
+        };
+
+        return generate(1, n);
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(\frac {4 ^ n}{\sqrt {n}})$
+* Space complexity:
+    * $O(n)$ space for recursion stack.
+    * $O(\frac {4 ^ n}{\sqrt {n}})$ space for the output.
+
+---
+
+## 2. Dynamic Programming (Top-Down)
+
+::tabs-start
+
+```python
+# Definition for a binary tree node.
+# class TreeNode:
+#     def __init__(self, val=0, left=None, right=None):
+#         self.val = val
+#         self.left = left
+#         self.right = right
+class Solution:
+    def generateTrees(self, n: int) -> List[Optional[TreeNode]]:
+        dp = {}
+
+        def generate(left, right):
+            if left > right:
+                return [None]
+            if (left, right) in dp:
+                return dp[(left, right)]
+
+            res = []
+            for val in range(left, right + 1):
+                for leftTree in generate(left, val - 1):
+                    for rightTree in generate(val + 1, right):
+                        root = TreeNode(val, leftTree, rightTree)
+                        res.append(root)
+
+            dp[(left, right)] = res
+            return res
+
+        return generate(1, n)
+```
+
+```java
+/**
+ * Definition for a binary tree node.
+ * public class TreeNode {
+ *     int val;
+ *     TreeNode left;
+ *     TreeNode right;
+ *     TreeNode() {}
+ *     TreeNode(int val) { this.val = val; }
+ *     TreeNode(int val, TreeNode left, TreeNode right) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+public class Solution {
+    private List<TreeNode>[][] dp;
+
+    public List<TreeNode> generateTrees(int n) {
+        dp = new ArrayList[n + 1][n + 1];
+        return generate(1, n);
+    }
+
+    private List<TreeNode> generate(int left, int right) {
+        if (left > right) return Collections.singletonList(null);
+        if (dp[left][right] != null) return dp[left][right];
+
+        List<TreeNode> res = new ArrayList<>();
+        for (int val = left; val <= right; val++) {
+            for (TreeNode leftTree : generate(left, val - 1)) {
+                for (TreeNode rightTree : generate(val + 1, right)) {
+                    res.add(new TreeNode(val, leftTree, rightTree));
+                }
+            }
+        }
+        return dp[left][right] = res;
+    }
+}
+```
+
+```cpp
+/**
+ * Definition for a binary tree node.
+ * struct TreeNode {
+ *     int val;
+ *     TreeNode *left;
+ *     TreeNode *right;
+ *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
+ * };
+ */
+class Solution {
+public:
+    vector<vector<vector<TreeNode*>>> dp;
+
+    vector<TreeNode*> generateTrees(int n) {
+        dp.resize(n + 1, vector<vector<TreeNode*>>(n + 1));
+        return generate(1, n);
+    }
+
+private:
+    vector<TreeNode*> generate(int left, int right) {
+        if (left > right) return {nullptr};
+        if (!dp[left][right].empty()) return dp[left][right];
+
+        vector<TreeNode*> res;
+        for (int val = left; val <= right; val++) {
+            for (auto& leftTree : generate(left, val - 1)) {
+                for (auto& rightTree : generate(val + 1, right)) {
+                    res.push_back(new TreeNode(val, leftTree, rightTree));
+                }
+            }
+        }
+        return dp[left][right] = res;
+    }
+};
+```
+
+```javascript
+/**
+ * Definition for a binary tree node.
+ * class TreeNode {
+ *     constructor(val = 0, left = null, right = null) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+class Solution {
+    /**
+     * @param {number} n
+     * @return {TreeNode[]}
+     */
+    generateTrees(n) {
+        const dp = Array.from({ length: n + 1 }, () => Array(n + 1).fill(null));
+
+        const generate = (left, right) => {
+            if (left > right) return [null];
+            if (dp[left][right]) return dp[left][right];
+
+            let res = [];
+            for (let val = left; val <= right; val++) {
+                for (let leftTree of generate(left, val - 1)) {
+                    for (let rightTree of generate(val + 1, right)) {
+                        res.push(new TreeNode(val, leftTree, rightTree));
+                    }
+                }
+            }
+            return (dp[left][right] = res);
+        };
+
+        return generate(1, n);
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(\frac {4 ^ n}{\sqrt {n}})$
+* Space complexity:
+    * $O(n)$ space for recursion stack.
+    * $O(n ^ 2)$ extra space.
+    * $O(\frac {4 ^ n}{\sqrt {n}})$ space for the output.
+
+---
+
+## 3. Dynamic Programming (Bottom-Up)
+
+::tabs-start
+
+```python
+# Definition for a binary tree node.
+# class TreeNode:
+#     def __init__(self, val=0, left=None, right=None):
+#         self.val = val
+#         self.left = left
+#         self.right = right
+class Solution:
+    def generateTrees(self, n: int) -> List[Optional[TreeNode]]:
+        dp = [[[] for _ in range(n + 2)] for _ in range(n + 2)]
+        for i in range(1, n + 2):
+            dp[i][i - 1] = [None]
+
+        for length in range(1, n + 1):
+            for left in range(1, n - length + 2):
+                right = left + length - 1
+                dp[left][right] = []
+                for val in range(left, right + 1):
+                    for leftTree in dp[left][val - 1]:
+                        for rightTree in dp[val + 1][right]:
+                            root = TreeNode(val, leftTree, rightTree)
+                            dp[left][right].append(root)
+
+        return dp[1][n]
+```
+
+```java
+/**
+ * Definition for a binary tree node.
+ * public class TreeNode {
+ *     int val;
+ *     TreeNode left;
+ *     TreeNode right;
+ *     TreeNode() {}
+ *     TreeNode(int val) { this.val = val; }
+ *     TreeNode(int val, TreeNode left, TreeNode right) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+public class Solution {
+    public List<TreeNode> generateTrees(int n) {
+        List<TreeNode>[][] dp = new ArrayList[n + 2][n + 2];
+        for (int i = 1; i <= n + 1; i++) {
+            dp[i][i - 1] = new ArrayList<>();
+            dp[i][i - 1].add(null);
+        }
+
+        for (int length = 1; length <= n; length++) {
+            for (int left = 1; left + length - 1 <= n; left++) {
+                int right = left + length - 1;
+                dp[left][right] = new ArrayList<>();
+
+                for (int val = left; val <= right; val++) {
+                    for (TreeNode leftTree : dp[left][val - 1]) {
+                        for (TreeNode rightTree : dp[val + 1][right]) {
+                            dp[left][right].add(new TreeNode(val, leftTree, rightTree));
+                        }
+                    }
+                }
+            }
+        }
+        return dp[1][n];
+    }
+}
+```
+
+```cpp
+/**
+ * Definition for a binary tree node.
+ * struct TreeNode {
+ *     int val;
+ *     TreeNode *left;
+ *     TreeNode *right;
+ *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
+ * };
+ */
+class Solution {
+public:
+    vector<TreeNode*> generateTrees(int n) {
+        vector<vector<vector<TreeNode*>>> dp(n + 2, vector<vector<TreeNode*>>(n + 2));
+        for (int i = 1; i <= n + 1; i++) {
+            dp[i][i - 1].push_back(nullptr);
+        }
+
+        for (int length = 1; length <= n; length++) {
+            for (int left = 1; left + length - 1 <= n; left++) {
+                int right = left + length - 1;
+
+                for (int val = left; val <= right; val++) {
+                    for (auto& leftTree : dp[left][val - 1]) {
+                        for (auto& rightTree : dp[val + 1][right]) {
+                            dp[left][right].push_back(new TreeNode(val, leftTree, rightTree));
+                        }
+                    }
+                }
+            }
+        }
+        return dp[1][n];
+    }
+};
+```
+
+```javascript
+/**
+ * Definition for a binary tree node.
+ * class TreeNode {
+ *     constructor(val = 0, left = null, right = null) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+class Solution {
+    /**
+     * @param {number} n
+     * @return {TreeNode[]}
+     */
+    generateTrees(n) {
+        const dp = Array.from({ length: n + 2 }, () => Array(n + 2).fill(null));
+        for (let i = 1; i <= n + 1; i++) {
+            dp[i][i - 1] = [null];
+        }
+
+        for (let length = 1; length <= n; length++) {
+            for (let left = 1; left + length - 1 <= n; left++) {
+                let right = left + length - 1;
+                dp[left][right] = [];
+
+                for (let val = left; val <= right; val++) {
+                    for (let leftTree of dp[left][val - 1]) {
+                        for (let rightTree of dp[val + 1][right]) {
+                            dp[left][right].push(new TreeNode(val, leftTree, rightTree));
+                        }
+                    }
+                }
+            }
+        }
+        return dp[1][n];
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(\frac {4 ^ n}{\sqrt {n}})$
+* Space complexity:
+    * $O(n ^ 2)$ extra space.
+    * $O(\frac {4 ^ n}{\sqrt {n}})$ space for the output.
+
+---
+
+## 4. Dynamic Programming (Space Optimized)
+
+::tabs-start
+
+```python
+# Definition for a binary tree node.
+# class TreeNode:
+#     def __init__(self, val=0, left=None, right=None):
+#         self.val = val
+#         self.left = left
+#         self.right = right
+class Solution:
+    def generateTrees(self, n: int) -> list[Optional[TreeNode]]:
+        dp = [[] for _ in range(n + 1)]
+        dp[0] = [None]
+
+        for length in range(1, n + 1):
+            dp[length] = []
+            for val in range(1, length + 1):
+                for leftTree in dp[val - 1]:
+                    for rightTree in dp[length - val]:
+                        root = TreeNode(val)
+                        root.left = leftTree
+                        root.right = self.shift(rightTree, val)
+                        dp[length].append(root)
+
+        return dp[n]
+
+    def shift(self, node: Optional[TreeNode], offset: int) -> Optional[TreeNode]:
+        if not node:
+            return None
+        root = TreeNode(node.val + offset)
+        root.left = self.shift(node.left, offset)
+        root.right = self.shift(node.right, offset)
+        return root
+```
+
+```java
+/**
+ * Definition for a binary tree node.
+ * public class TreeNode {
+ *     int val;
+ *     TreeNode left;
+ *     TreeNode right;
+ *     TreeNode() {}
+ *     TreeNode(int val) { this.val = val; }
+ *     TreeNode(int val, TreeNode left, TreeNode right) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+public class Solution {
+    public List<TreeNode> generateTrees(int n) {
+        List<TreeNode>[] dp = new ArrayList[n + 1];
+        dp[0] = new ArrayList<>();
+        dp[0].add(null);
+
+        for (int length = 1; length <= n; length++) {
+            dp[length] = new ArrayList<>();
+            for (int val = 1; val <= length; val++) {
+                for (TreeNode leftTree : dp[val - 1]) {
+                    for (TreeNode rightTree : dp[length - val]) {
+                        TreeNode root = new TreeNode(val);
+                        root.left = leftTree;
+                        root.right = shift(rightTree, val);
+                        dp[length].add(root);
+                    }
+                }
+            }
+        }
+        return dp[n];
+    }
+
+    private TreeNode shift(TreeNode node, int offset) {
+        if (node == null) return null;
+        TreeNode root = new TreeNode(node.val + offset);
+        root.left = shift(node.left, offset);
+        root.right = shift(node.right, offset);
+        return root;
+    }
+}
+```
+
+```cpp
+/**
+ * Definition for a binary tree node.
+ * struct TreeNode {
+ *     int val;
+ *     TreeNode *left;
+ *     TreeNode *right;
+ *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
+ *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
+ * };
+ */
+class Solution {
+public:
+    vector<TreeNode*> generateTrees(int n) {
+        vector<vector<TreeNode*>> dp(n + 1);
+        dp[0].push_back(nullptr);
+
+        for (int length = 1; length <= n; length++) {
+            for (int val = 1; val <= length; val++) {
+                for (auto& leftTree : dp[val - 1]) {
+                    for (auto& rightTree : dp[length - val]) {
+                        TreeNode* root = new TreeNode(val);
+                        root->left = leftTree;
+                        root->right = shift(rightTree, val);
+                        dp[length].push_back(root);
+                    }
+                }
+            }
+        }
+        return dp[n];
+    }
+
+private:
+    TreeNode* shift(TreeNode* node, int offset) {
+        if (!node) return nullptr;
+        TreeNode* root = new TreeNode(node->val + offset);
+        root->left = shift(node->left, offset);
+        root->right = shift(node->right, offset);
+        return root;
+    }
+};
+```
+
+```javascript
+/**
+ * Definition for a binary tree node.
+ * class TreeNode {
+ *     constructor(val = 0, left = null, right = null) {
+ *         this.val = val;
+ *         this.left = left;
+ *         this.right = right;
+ *     }
+ * }
+ */
+class Solution {
+    /**
+     * @param {number} n
+     * @return {TreeNode[]}
+     */
+    generateTrees(n) {
+        const shift = (node, offset) => {
+            if (!node) return null;
+            let root = new TreeNode(node.val + offset);
+            root.left = shift(node.left, offset);
+            root.right = shift(node.right, offset);
+            return root;
+        };
+
+        let dp = Array.from({ length: n + 1 }, () => []);
+        dp[0].push(null);
+
+        for (let length = 1; length <= n; length++) {
+            for (let val = 1; val <= length; val++) {
+                for (let leftTree of dp[val - 1]) {
+                    for (let rightTree of dp[length - val]) {
+                        let root = new TreeNode(val);
+                        root.left = leftTree;
+                        root.right = shift(rightTree, val);
+                        dp[length].push(root);
+                    }
+                }
+            }
+        }
+        return dp[n];
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(\frac {4 ^ n}{\sqrt {n}})$
+* Space complexity:
+    * $O(n)$ for the recursion stack.
+    * $O(n)$ extra space.
+    * $O(\frac {4 ^ n}{\sqrt {n}})$ space for the output.
\ No newline at end of file
diff --git a/articles/validate-binary-tree-nodes.md b/articles/validate-binary-tree-nodes.md
new file mode 100644
index 000000000..fe797fbd4
--- /dev/null
+++ b/articles/validate-binary-tree-nodes.md
@@ -0,0 +1,668 @@
+## 1. Depth First Search
+
+::tabs-start
+
+```python
+class Solution:
+    def validateBinaryTreeNodes(self, n: int, leftChild: List[int], rightChild: List[int]) -> bool:
+        hasParent = set(leftChild + rightChild)
+        hasParent.discard(-1)
+        if len(hasParent) == n:
+            return False
+
+        root = -1
+        for i in range(n):
+            if i not in hasParent:
+                root = i
+                break
+
+        visit = set()
+        def dfs(i):
+            if i == -1:
+                return True
+            if i in visit:
+                return False
+            visit.add(i)
+            return dfs(leftChild[i]) and dfs(rightChild[i])
+
+        return dfs(root) and len(visit) == n
+```
+
+```java
+public class Solution {
+    private Set<Integer> visit;
+
+    public boolean validateBinaryTreeNodes(int n, int[] leftChild, int[] rightChild) {
+        Set<Integer> hasParent = new HashSet<>();
+        for (int c : leftChild) if (c != -1) hasParent.add(c);
+        for (int c : rightChild) if (c != -1) hasParent.add(c);
+        if (hasParent.size() == n) return false;
+
+        int root = -1;
+        for (int i = 0; i < n; i++) {
+            if (!hasParent.contains(i)) {
+                root = i;
+                break;
+            }
+        }
+        visit = new HashSet<>();
+        return dfs(root, leftChild, rightChild) && visit.size() == n;
+    }
+
+    private boolean dfs(int i, int[] leftChild, int[] rightChild) {
+        if (i == -1) return true;
+        if (visit.contains(i)) return false;
+        visit.add(i);
+        return dfs(leftChild[i], leftChild, rightChild) && 
+               dfs(rightChild[i], leftChild, rightChild);
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    unordered_set<int> visit;
+
+    bool validateBinaryTreeNodes(int n, vector<int>& leftChild, vector<int>& rightChild) {
+        unordered_set<int> hasParent;
+        for (int c : leftChild) if (c != -1) hasParent.insert(c);
+        for (int c : rightChild) if (c != -1) hasParent.insert(c);
+        if (hasParent.size() == n) return false;
+
+        int root = -1;
+        for (int i = 0; i < n; i++) {
+            if (!hasParent.count(i)) {
+                root = i;
+                break;
+            }
+        }
+        return dfs(root, leftChild, rightChild) && visit.size() == n;
+    }
+
+private:
+    bool dfs(int i, vector<int>& leftChild, vector<int>& rightChild) {
+        if (i == -1) return true;
+        if (visit.count(i)) return false;
+        visit.insert(i);
+        return dfs(leftChild[i], leftChild, rightChild) && 
+               dfs(rightChild[i], leftChild, rightChild);
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number} n
+     * @param {number[]} leftChild
+     * @param {number[]} rightChild
+     * @return {boolean}
+     */
+    validateBinaryTreeNodes(n, leftChild, rightChild) {
+        let hasParent = new Set([...leftChild, ...rightChild].filter(c => c !== -1));
+        if (hasParent.size === n) return false;
+
+        let root = 0;
+        for (let i = 0; i < n; i++) {
+            if (!hasParent.has(i)) {
+                root = i;
+                break;
+            }
+        }
+
+        const visit = new Set();
+        const dfs = (i) => {
+            if (i === -1) return true;
+            if (visit.has(i)) return false;
+            visit.add(i);
+            return dfs(leftChild[i]) && dfs(rightChild[i]);
+        };
+
+        return dfs(root) && visit.size === n;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(n)$
+
+---
+
+## 2. Breadth First Search
+
+::tabs-start
+
+```python
+class Solution:
+    def validateBinaryTreeNodes(self, n: int, leftChild: list[int], rightChild: list[int]) -> bool:
+        indegree = [0] * n
+        for i in range(n):
+            if leftChild[i] != -1:
+                indegree[leftChild[i]] += 1
+                if indegree[leftChild[i]] > 1:
+                    return False
+            if rightChild[i] != -1:
+                indegree[rightChild[i]] += 1
+                if indegree[rightChild[i]] > 1:
+                    return False
+
+        root = -1
+        for i in range(n):
+            if indegree[i] == 0:
+                if root != -1:
+                    return False
+                root = i
+
+        if root == -1:
+            return False
+
+        count = 0
+        q = deque([root])
+        while q:
+            i = q.popleft()
+            count += 1
+            if leftChild[i] != -1:
+                q.append(leftChild[i])
+            if rightChild[i] != -1:
+                q.append(rightChild[i])
+        return count == n
+```
+
+```java
+public class Solution {
+    public boolean validateBinaryTreeNodes(int n, int[] leftChild, int[] rightChild) {
+        int[] indegree = new int[n];
+        for (int i = 0; i < n; i++) {
+            if (leftChild[i] != -1) {
+                if (++indegree[leftChild[i]] > 1) return false;
+            }
+            if (rightChild[i] != -1) {
+                if (++indegree[rightChild[i]] > 1) return false;
+            }
+        }
+
+        int root = -1;
+        for (int i = 0; i < n; i++) {
+            if (indegree[i] == 0) {
+                if (root != -1) return false;
+                root = i;
+            }
+        }
+
+        if (root == -1) return false;
+
+        int count = 0;
+        Queue<Integer> q = new LinkedList<>();
+        q.offer(root);
+
+        while (!q.isEmpty()) {
+            int i = q.poll();
+            count++;
+            if (leftChild[i] != -1) q.offer(leftChild[i]);
+            if (rightChild[i] != -1) q.offer(rightChild[i]);
+        }
+        return count == n;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    bool validateBinaryTreeNodes(int n, vector<int>& leftChild, vector<int>& rightChild) {
+        vector<int> indegree(n, 0);
+        for (int i = 0; i < n; i++) {
+            if (leftChild[i] != -1) {
+                if (++indegree[leftChild[i]] > 1) return false;
+            }
+            if (rightChild[i] != -1) {
+                if (++indegree[rightChild[i]] > 1) return false;
+            }
+        }
+
+        int root = -1;
+        for (int i = 0; i < n; i++) {
+            if (indegree[i] == 0) {
+                if (root != -1) return false;
+                root = i;
+            }
+        }
+
+        if (root == -1) return false;
+
+        int count = 0;
+        queue<int> q;
+        q.push(root);
+
+        while (!q.empty()) {
+            int i = q.front();q.pop();
+            count++;
+            if (leftChild[i] != -1) q.push(leftChild[i]);
+            if (rightChild[i] != -1) q.push(rightChild[i]);
+        }
+        return count == n;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number} n
+     * @param {number[]} leftChild
+     * @param {number[]} rightChild
+     * @return {boolean}
+     */
+    validateBinaryTreeNodes(n, leftChild, rightChild) {
+        let indegree = new Array(n).fill(0);
+        for (let i = 0; i < n; i++) {
+            if (leftChild[i] !== -1) {
+                if (++indegree[leftChild[i]] > 1) return false;
+            }
+            if (rightChild[i] !== -1) {
+                if (++indegree[rightChild[i]] > 1) return false;
+            }
+        }
+
+        let root = -1;
+        for (let i = 0; i < n; i++) {
+            if (indegree[i] === 0) {
+                if (root !== -1) return false;
+                root = i;
+            }
+        }
+
+        if (root === -1) return false;
+
+        let count = 0;
+        let q = new Queue([root]);
+
+        while (!q.isEmpty()) {
+            let i = q.pop();
+            count++;
+            if (leftChild[i] !== -1) q.push(leftChild[i]);
+            if (rightChild[i] !== -1) q.push(rightChild[i]);
+        }
+        return count === n;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(n)$
+
+---
+
+## 3. Iterative DFS
+
+::tabs-start
+
+```python
+class Solution:
+    def validateBinaryTreeNodes(self, n: int, leftChild: list[int], rightChild: list[int]) -> bool:
+        indegree = [0] * n
+        for i in range(n):
+            if leftChild[i] != -1:
+                indegree[leftChild[i]] += 1
+                if indegree[leftChild[i]] > 1:
+                    return False
+            if rightChild[i] != -1:
+                indegree[rightChild[i]] += 1
+                if indegree[rightChild[i]] > 1:
+                    return False
+
+        root = next((i for i in range(n) if indegree[i] == 0), -1)
+        if root == -1:
+            return False
+
+        count, stack = 0, [root]
+        while stack:
+            node = stack.pop()
+            count += 1
+            if leftChild[node] != -1:
+                stack.append(leftChild[node])
+            if rightChild[node] != -1:
+                stack.append(rightChild[node])
+
+        return count == n
+```
+
+```java
+public class Solution {
+    public boolean validateBinaryTreeNodes(int n, int[] leftChild, int[] rightChild) {
+        int[] indegree = new int[n];
+        for (int i = 0; i < n; i++) {
+            if (leftChild[i] != -1) {
+                if (++indegree[leftChild[i]] > 1) return false;
+            }
+            if (rightChild[i] != -1) {
+                if (++indegree[rightChild[i]] > 1) return false;
+            }
+        }
+
+        int root = -1;
+        for (int i = 0; i < n; i++) {
+            if (indegree[i] == 0) {
+                if (root != -1) return false;
+                root = i;
+            }
+        }
+
+        if (root == -1) return false;
+
+        int count = 0;
+        Stack<Integer> stack = new Stack<>();
+        stack.push(root);
+
+        while (!stack.isEmpty()) {
+            int node = stack.pop();
+            count++;
+            if (leftChild[node] != -1) stack.push(leftChild[node]);
+            if (rightChild[node] != -1) stack.push(rightChild[node]);
+        }
+        return count == n;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    bool validateBinaryTreeNodes(int n, vector<int>& leftChild, vector<int>& rightChild) {
+        vector<int> indegree(n, 0);
+        for (int i = 0; i < n; i++) {
+            if (leftChild[i] != -1 && ++indegree[leftChild[i]] > 1) return false;
+            if (rightChild[i] != -1 && ++indegree[rightChild[i]] > 1) return false;
+        }
+
+        int root = -1;
+        for (int i = 0; i < n; i++) {
+            if (indegree[i] == 0) {
+                if (root != -1) return false;
+                root = i;
+            }
+        }
+
+        if (root == -1) return false;
+
+        int count = 0;
+        stack<int> stk;
+        stk.push(root);
+
+        while (!stk.empty()) {
+            int node = stk.top(); stk.pop();
+            count++;
+            if (leftChild[node] != -1) stk.push(leftChild[node]);
+            if (rightChild[node] != -1) stk.push(rightChild[node]);
+        }
+        return count == n;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number} n
+     * @param {number[]} leftChild
+     * @param {number[]} rightChild
+     * @return {boolean}
+     */
+    validateBinaryTreeNodes(n, leftChild, rightChild) {
+        let indegree = new Array(n).fill(0);
+        for (let i = 0; i < n; i++) {
+            if (leftChild[i] !== -1) {
+                if (++indegree[leftChild[i]] > 1) return false;
+            }
+            if (rightChild[i] !== -1) {
+                if (++indegree[rightChild[i]] > 1) return false;
+            }
+        }
+
+        let root = -1;
+        for (let i = 0; i < n; i++) {
+            if (indegree[i] === 0) {
+                if (root !== -1) return false;
+                root = i;
+            }
+        }
+
+        if (root === -1) return false;
+
+        let count = 0;
+        let stack = [root];
+
+        while (stack.length) {
+            let node = stack.pop();
+            count++;
+            if (leftChild[node] !== -1) stack.push(leftChild[node]);
+            if (rightChild[node] !== -1) stack.push(rightChild[node]);
+        }
+        return count === n;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(n)$
+
+---
+
+## 4. Disjoint Set Union
+
+::tabs-start
+
+```python
+class DSU:
+    def __init__(self, n):
+        self.Parent = list(range(n))
+        self.Components = n
+
+    def find(self, node):
+        if self.Parent[node] != node:
+            self.Parent[node] = self.find(self.Parent[node])
+        return self.Parent[node]
+
+    def union(self, parent, child):
+        parentRoot = self.find(parent)
+        childRoot = self.find(child)
+        if childRoot != child or parentRoot == childRoot:
+            return False
+
+        self.Components -= 1
+        self.Parent[childRoot] = parentRoot
+        return True
+
+class Solution:
+    def validateBinaryTreeNodes(self, n: int, leftChild: list[int], rightChild: list[int]) -> bool:
+        dsu = DSU(n)
+
+        for parent in range(n):
+            for child in (leftChild[parent], rightChild[parent]):
+                if child == -1:
+                    continue
+                if not dsu.union(parent, child):
+                    return False
+
+        return dsu.Components == 1
+```
+
+```java
+class DSU {
+    int[] Parent;
+    int Components;
+
+    public DSU(int n) {
+        Parent = new int[n];
+        for (int i = 0; i < n; i++) {
+            Parent[i] = i;
+        }
+        Components = n;
+    }
+
+    public int find(int node) {
+        if (Parent[node] != node) {
+            Parent[node] = find(Parent[node]);
+        }
+        return Parent[node];
+    }
+
+    public boolean union(int parent, int child) {
+        int parentRoot = find(parent);
+        int childRoot = find(child);
+        if (childRoot != child || parentRoot == childRoot) {
+            return false;
+        }
+
+        Components--;
+        Parent[childRoot] = parentRoot;
+        return true;
+    }
+}
+
+class Solution {
+    public boolean validateBinaryTreeNodes(int n, int[] leftChild, int[] rightChild) {
+        DSU dsu = new DSU(n);
+
+        for (int parent = 0; parent < n; parent++) {
+            for (int child : new int[]{leftChild[parent], rightChild[parent]}) {
+                if (child == -1) continue;
+                if (!dsu.union(parent, child)) return false;
+            }
+        }
+
+        return dsu.Components == 1;
+    }
+}
+```
+
+```cpp
+class DSU {
+public:
+    vector<int> Parent;
+    int Components;
+
+    DSU(int n) {
+        Parent.resize(n);
+        iota(Parent.begin(), Parent.end(), 0);
+        Components = n;
+    }
+
+    int find(int node) {
+        if (Parent[node] != node) {
+            Parent[node] = find(Parent[node]);
+        }
+        return Parent[node];
+    }
+
+    bool unionSets(int parent, int child) {
+        int parentRoot = find(parent);
+        int childRoot = find(child);
+        if (childRoot != child || parentRoot == childRoot) {
+            return false;
+        }
+
+        Components--;
+        Parent[childRoot] = parentRoot;
+        return true;
+    }
+};
+
+class Solution {
+public:
+    bool validateBinaryTreeNodes(int n, vector<int>& leftChild, vector<int>& rightChild) {
+        DSU dsu(n);
+
+        for (int parent = 0; parent < n; parent++) {
+            for (int child : {leftChild[parent], rightChild[parent]}) {
+                if (child == -1) continue;
+                if (!dsu.unionSets(parent, child)) return false;
+            }
+        }
+
+        return dsu.Components == 1;
+    }
+};
+```
+
+```javascript
+class DSU {
+    /**
+     * @constructor
+     * @param {number} n
+     */
+    constructor(n) {
+        this.Parent = Array.from({ length: n }, (_, i) => i);
+        this.Components = n;
+    }
+
+    /**
+     * @param {number} node
+     * @return {number}
+     */
+    find(node) {
+        if (this.Parent[node] !== node) {
+            this.Parent[node] = this.find(this.Parent[node]);
+        }
+        return this.Parent[node];
+    }
+
+    /**
+     * @param {number} parent
+     * @param {number} child
+     * @return {boolean}
+     */
+    union(parent, child) {
+        let parentRoot = this.find(parent);
+        let childRoot = this.find(child);
+        if (childRoot !== child || parentRoot === childRoot) {
+            return false;
+        }
+
+        this.Components--;
+        this.Parent[childRoot] = parentRoot;
+        return true;
+    }
+}
+
+class Solution {
+    /**
+     * @param {number} n
+     * @param {number[]} leftChild
+     * @param {number[]} rightChild
+     * @return {boolean}
+     */
+    validateBinaryTreeNodes(n, leftChild, rightChild) {
+        let dsu = new DSU(n);
+
+        for (let parent = 0; parent < n; parent++) {
+            for (let child of [leftChild[parent], rightChild[parent]]) {
+                if (child === -1) continue;
+                if (!dsu.union(parent, child)) return false;
+            }
+        }
+
+        return dsu.Components === 1;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(n)$
\ No newline at end of file
