From 83ae1f728a1545e9244b2128110d0e5788766566 Mon Sep 17 00:00:00 2001
From: Sri Hari <kataresrihari@gmail.com>
Date: Tue, 4 Feb 2025 23:30:43 +0530
Subject: [PATCH 01/13] Batch-5/Neetcode-ALL/Added-articles

---
 articles/detonate-the-maximum-bombs.md        | 522 +++++++++++++++
 articles/is-graph-bipartite.md                | 611 ++++++++++++++++++
 ...largest-color-value-in-a-directed-graph.md | 589 +++++++++++++++++
 ...minimum-number-of-days-to-eat-n-oranges.md | 142 ++++
 ...m-number-of-vertices-to-reach-all-nodes.md | 465 +++++++++++++
 articles/path-with-maximum-gold.md            | 508 +++++++++++++++
 6 files changed, 2837 insertions(+)
 create mode 100644 articles/detonate-the-maximum-bombs.md
 create mode 100644 articles/is-graph-bipartite.md
 create mode 100644 articles/largest-color-value-in-a-directed-graph.md
 create mode 100644 articles/minimum-number-of-days-to-eat-n-oranges.md
 create mode 100644 articles/minimum-number-of-vertices-to-reach-all-nodes.md
 create mode 100644 articles/path-with-maximum-gold.md

diff --git a/articles/detonate-the-maximum-bombs.md b/articles/detonate-the-maximum-bombs.md
new file mode 100644
index 000000000..bc1a75fc9
--- /dev/null
+++ b/articles/detonate-the-maximum-bombs.md
@@ -0,0 +1,522 @@
+## 1. Depth First Search
+
+::tabs-start
+
+```python
+class Solution:
+    def maximumDetonation(self, bombs: list[list[int]]) -> int:
+        adj = [[] for _ in range(len(bombs))]
+
+        for i in range(len(bombs)):
+            x1, y1, r1 = bombs[i]
+            for j in range(i + 1, len(bombs)):
+                x2, y2, r2 = bombs[j]
+                d = (x1 - x2) ** 2 + (y1 - y2) ** 2
+
+                if d <= r1 ** 2:
+                    adj[i].append(j)
+                if d <= r2 ** 2:
+                    adj[j].append(i)
+
+        def dfs(i, visit):
+            if i in visit:
+                return 0
+            visit.add(i)
+            for nei in adj[i]:
+                dfs(nei, visit)
+            return len(visit)
+
+        res = 0
+        for i in range(len(bombs)):
+            res = max(res, dfs(i, set()))
+        return res
+```
+
+```java
+public class Solution {
+    public int maximumDetonation(int[][] bombs) {
+        int n = bombs.length;
+        List<Integer>[] adj = new ArrayList[n];
+        for (int i = 0; i < n; i++) {
+            adj[i] = new ArrayList<>();
+        }
+
+        for (int i = 0; i < n; i++) {
+            for (int j = i + 1; j < n; j++) {
+                int x1 = bombs[i][0], y1 = bombs[i][1], r1 = bombs[i][2];
+                int x2 = bombs[j][0], y2 = bombs[j][1], r2 = bombs[j][2];
+                long d = (long) (x1 - x2) * (x1 - x2) + (long) (y1 - y2) * (y1 - y2);
+
+                if (d <= (long) r1 * r1) {
+                    adj[i].add(j);
+                }
+                if (d <= (long) r2 * r2) {
+                    adj[j].add(i);
+                }
+            }
+        }
+
+        int res = 0;
+        for (int i = 0; i < n; i++) {
+            res = Math.max(res, dfs(i, new HashSet<>(), adj));
+        }
+        return res;
+    }
+
+    private int dfs(int i, Set<Integer> visit, List<Integer>[] adj) {
+        if (!visit.add(i)) return 0;
+        for (int nei : adj[i]) {
+            dfs(nei, visit, adj);
+        }
+        return visit.size();
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int maximumDetonation(vector<vector<int>>& bombs) {
+        int n = bombs.size();
+        vector<vector<int>> adj(n);
+
+        for (int i = 0; i < n; i++) {
+            for (int j = i + 1; j < n; j++) {
+                long long x1 = bombs[i][0], y1 = bombs[i][1], r1 = bombs[i][2];
+                long long x2 = bombs[j][0], y2 = bombs[j][1], r2 = bombs[j][2];
+                long long d = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
+
+                if (d <= r1 * r1) {
+                    adj[i].push_back(j);
+                }
+                if (d <= r2 * r2) {
+                    adj[j].push_back(i);
+                }
+            }
+        }
+
+        int res = 0;
+        for (int i = 0; i < n; i++) {
+            unordered_set<int> visit;
+            res = max(res, dfs(i, visit, adj));
+        }
+        return res;
+    }
+
+private:
+    int dfs(int i, unordered_set<int>& visit, vector<vector<int>>& adj) {
+        if (!visit.insert(i).second) return 0;
+        for (int nei : adj[i]) {
+            dfs(nei, visit, adj);
+        }
+        return visit.size();
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} bombs
+     * @return {number}
+     */
+    maximumDetonation(bombs) {
+        let n = bombs.length;
+        let adj = Array.from({ length: n }, () => []);
+
+        for (let i = 0; i < n; i++) {
+            for (let j = i + 1; j < n; j++) {
+                let [x1, y1, r1] = bombs[i];
+                let [x2, y2, r2] = bombs[j];
+                let d = (x1 - x2) ** 2 + (y1 - y2) ** 2;
+
+                if (d <= r1 ** 2) adj[i].push(j);
+                if (d <= r2 ** 2) adj[j].push(i);
+            }
+        }
+
+        const dfs = (i, visit) => {
+            if (visit.has(i)) return 0;
+            visit.add(i);
+            for (let nei of adj[i]) {
+                dfs(nei, visit);
+            }
+            return visit.size;
+        };
+
+        let res = 0;
+        for (let i = 0; i < n; i++) {
+            res = Math.max(res, dfs(i, new Set()));
+        }
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n ^ 3)$
+* Space complexity: $O(n ^ 2)$
+
+---
+
+## 2. Breadth First Search
+
+::tabs-start
+
+```python
+class Solution:
+    def maximumDetonation(self, bombs: list[list[int]]) -> int:
+        n = len(bombs)
+        adj = [[] for _ in range(n)]
+
+        for i in range(n):
+            x1, y1, r1 = bombs[i]
+            for j in range(i + 1, n):
+                x2, y2, r2 = bombs[j]
+                d = (x1 - x2) ** 2 + (y1 - y2) ** 2
+
+                if d <= r1 ** 2:
+                    adj[i].append(j)
+                if d <= r2 ** 2:
+                    adj[j].append(i)
+
+        res = 0
+        for i in range(n):
+            q = deque([i])
+            visit = [False] * n
+            visit[i] = True
+            count = 1
+            while q:
+                node = q.popleft()
+                for nei in adj[node]:
+                    if not visit[nei]:
+                        visit[nei] = True
+                        count += 1
+                        q.append(nei)
+            res = max(res, count)
+        return res
+```
+
+```java
+public class Solution {
+    public int maximumDetonation(int[][] bombs) {
+        int n = bombs.length;
+        List<Integer>[] adj = new ArrayList[n];
+        for (int i = 0; i < n; i++) {
+            adj[i] = new ArrayList<>();
+        }
+
+        for (int i = 0; i < n; i++) {
+            int x1 = bombs[i][0], y1 = bombs[i][1], r1 = bombs[i][2];
+            for (int j = i + 1; j < n; j++) {
+                int x2 = bombs[j][0], y2 = bombs[j][1], r2 = bombs[j][2];
+                long d = (long) (x1 - x2) * (x1 - x2) + (long) (y1 - y2) * (y1 - y2);
+
+                if (d <= (long) r1 * r1) adj[i].add(j);
+                if (d <= (long) r2 * r2) adj[j].add(i);
+            }
+        }
+
+        int res = 0;
+        for (int i = 0; i < n; i++) {
+            Queue<Integer> q = new LinkedList<>();
+            boolean[] visit = new boolean[n];
+            q.offer(i);
+            visit[i] = true;
+            int count = 1;
+
+            while (!q.isEmpty()) {
+                int node = q.poll();
+                for (int nei : adj[node]) {
+                    if (!visit[nei]) {
+                        visit[nei] = true;
+                        count++;
+                        q.offer(nei);
+                    }
+                }
+            }
+            res = Math.max(res, count);
+        }
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int maximumDetonation(vector<vector<int>>& bombs) {
+        int n = bombs.size();
+        vector<vector<int>> adj(n);
+
+        for (int i = 0; i < n; i++) {
+            int x1 = bombs[i][0], y1 = bombs[i][1], r1 = bombs[i][2];
+            for (int j = i + 1; j < n; j++) {
+                int x2 = bombs[j][0], y2 = bombs[j][1], r2 = bombs[j][2];
+                long long d = (x1 - x2) * 1LL * (x1 - x2) + (y1 - y2) * 1LL * (y1 - y2);
+
+                if (d <= (long long) r1 * r1) adj[i].push_back(j);
+                if (d <= (long long) r2 * r2) adj[j].push_back(i);
+            }
+        }
+
+        int res = 0;
+        for (int i = 0; i < n; i++) {
+            queue<int> q;
+            vector<bool> visit(n, false);
+            q.push(i);
+            visit[i] = true;
+            int count = 1;
+
+            while (!q.empty()) {
+                int node = q.front();q.pop();
+                for (int& nei : adj[node]) {
+                    if (!visit[nei]) {
+                        visit[nei] = true;
+                        count++;
+                        q.push(nei);
+                    }
+                }
+            }
+            res = max(res, count);
+        }
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} bombs
+     * @return {number}
+     */
+    maximumDetonation(bombs) {
+        let n = bombs.length;
+        let adj = Array.from({ length: n }, () => []);
+
+        for (let i = 0; i < n; i++) {
+            let [x1, y1, r1] = bombs[i];
+            for (let j = i + 1; j < n; j++) {
+                let [x2, y2, r2] = bombs[j];
+                let d = (x1 - x2) ** 2 + (y1 - y2) ** 2;
+
+                if (d <= r1 ** 2) adj[i].push(j);
+                if (d <= r2 ** 2) adj[j].push(i);
+            }
+        }
+
+        let res = 0;
+        for (let i = 0; i < n; i++) {
+            let q = new Queue([i]);
+            let visit = new Array(n).fill(false);
+            visit[i] = true;
+            let count = 1;
+
+            while (!q.isEmpty()) {
+                let node = q.pop();
+                for (let nei of adj[node]) {
+                    if (!visit[nei]) {
+                        visit[nei] = true;
+                        count++;
+                        q.push(nei);
+                    }
+                }
+            }
+            res = Math.max(res, count);
+        }
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n ^ 3)$
+* Space complexity: $O(n ^ 2)$
+
+---
+
+## 3. Iterative DFS
+
+::tabs-start
+
+```python
+class Solution:
+    def maximumDetonation(self, bombs: list[list[int]]) -> int:
+        n = len(bombs)
+        adj = [[] for _ in range(n)]
+
+        for i in range(n):
+            x1, y1, r1 = bombs[i]
+            for j in range(i + 1, n):
+                x2, y2, r2 = bombs[j]
+                d = (x1 - x2) ** 2 + (y1 - y2) ** 2
+
+                if d <= r1 ** 2:
+                    adj[i].append(j)
+                if d <= r2 ** 2:
+                    adj[j].append(i)
+
+        res = 0
+        for i in range(n):
+            stack = [i]
+            visit = [False] * n
+            visit[i] = True
+            count = 1
+
+            while stack:
+                node = stack.pop()
+                for nei in adj[node]:
+                    if not visit[nei]:
+                        visit[nei] = True
+                        count += 1
+                        stack.append(nei)
+            res = max(res, count)
+        return res
+```
+
+```java
+public class Solution {
+    public int maximumDetonation(int[][] bombs) {
+        int n = bombs.length;
+        List<Integer>[] adj = new ArrayList[n];
+        for (int i = 0; i < n; i++) {
+            adj[i] = new ArrayList<>();
+        }
+
+        for (int i = 0; i < n; i++) {
+            int x1 = bombs[i][0], y1 = bombs[i][1], r1 = bombs[i][2];
+            for (int j = i + 1; j < n; j++) {
+                int x2 = bombs[j][0], y2 = bombs[j][1], r2 = bombs[j][2];
+                long d = (long) (x1 - x2) * (x1 - x2) + (long) (y1 - y2) * (y1 - y2);
+
+                if (d <= (long) r1 * r1) adj[i].add(j);
+                if (d <= (long) r2 * r2) adj[j].add(i);
+            }
+        }
+
+        int res = 0;
+        for (int i = 0; i < n; i++) {
+            Stack<Integer> stack = new Stack<>();
+            boolean[] visit = new boolean[n];
+            stack.push(i);
+            visit[i] = true;
+            int count = 1;
+
+            while (!stack.isEmpty()) {
+                int node = stack.pop();
+                for (int nei : adj[node]) {
+                    if (!visit[nei]) {
+                        visit[nei] = true;
+                        count++;
+                        stack.push(nei);
+                    }
+                }
+            }
+            res = Math.max(res, count);
+        }
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int maximumDetonation(vector<vector<int>>& bombs) {
+        int n = bombs.size();
+        vector<vector<int>> adj(n);
+
+        for (int i = 0; i < n; i++) {
+            int x1 = bombs[i][0], y1 = bombs[i][1], r1 = bombs[i][2];
+            for (int j = i + 1; j < n; j++) {
+                int x2 = bombs[j][0], y2 = bombs[j][1], r2 = bombs[j][2];
+                long long d = (long long)(x1 - x2) * (x1 - x2) + (long long)(y1 - y2) * (y1 - y2);
+
+                if (d <= (long long) r1 * r1) adj[i].push_back(j);
+                if (d <= (long long) r2 * r2) adj[j].push_back(i);
+            }
+        }
+
+        int res = 0;
+        for (int i = 0; i < n; i++) {
+            stack<int> stk;
+            vector<bool> visit(n, false);
+            stk.push(i);
+            visit[i] = true;
+            int count = 1;
+
+            while (!stk.empty()) {
+                int node = stk.top();stk.pop();
+                for (int& nei : adj[node]) {
+                    if (!visit[nei]) {
+                        visit[nei] = true;
+                        count++;
+                        stk.push(nei);
+                    }
+                }
+            }
+            res = max(res, count);
+        }
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} bombs
+     * @return {number}
+     */
+    maximumDetonation(bombs) {
+        let n = bombs.length;
+        let adj = Array.from({ length: n }, () => []);
+
+        for (let i = 0; i < n; i++) {
+            let [x1, y1, r1] = bombs[i];
+            for (let j = i + 1; j < n; j++) {
+                let [x2, y2, r2] = bombs[j];
+                let d = (x1 - x2) ** 2 + (y1 - y2) ** 2;
+
+                if (d <= r1 ** 2) adj[i].push(j);
+                if (d <= r2 ** 2) adj[j].push(i);
+            }
+        }
+
+        let res = 0;
+        for (let i = 0; i < n; i++) {
+            let stack = [i];
+            let visit = new Array(n).fill(false);
+            visit[i] = true;
+            let count = 1;
+
+            while (stack.length) {
+                let node = stack.pop();
+                for (let nei of adj[node]) {
+                    if (!visit[nei]) {
+                        visit[nei] = true;
+                        count++;
+                        stack.push(nei);
+                    }
+                }
+            }
+            res = Math.max(res, count);
+        }
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n ^ 3)$
+* Space complexity: $O(n ^ 2)$
\ No newline at end of file
diff --git a/articles/is-graph-bipartite.md b/articles/is-graph-bipartite.md
new file mode 100644
index 000000000..2db1c9d94
--- /dev/null
+++ b/articles/is-graph-bipartite.md
@@ -0,0 +1,611 @@
+## 1. Depth First Search
+
+::tabs-start
+
+```python
+class Solution:
+    def isBipartite(self, graph: List[List[int]]) -> bool:
+        color = [0] * len(graph)  # Map node i -> odd=1, even=-1
+
+        def dfs(i, c):
+            color[i] = c
+            for nei in graph[i]:
+                if color[nei] == c:
+                    return False
+                if color[nei] == 0 and not dfs(nei, -c):
+                    return False
+            return True
+
+        for i in range(len(graph)):
+            if color[i] == 0 and not dfs(i, 1):
+                return False
+        return True
+```
+
+```java
+public class Solution {
+    private int[] color;
+
+    public boolean isBipartite(int[][] graph) {
+        int n = graph.length;
+        color = new int[n]; // Map node i -> odd=1, even=-1
+
+        for (int i = 0; i < n; i++) {
+            if (color[i] == 0 && !dfs(graph, i, 1)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private boolean dfs(int[][] graph, int i, int c) {
+        color[i] = c;
+        for (int nei : graph[i]) {
+            if (color[nei] == c) {
+                return false;
+            }
+            if (color[nei] == 0 && !dfs(graph, nei, -c)) {
+                return false;
+            }
+        }
+        return true;
+    }
+}
+```
+
+```cpp
+class Solution {
+private:
+    vector<int> color;
+
+    bool dfs(vector<vector<int>>& graph, int i, int c) {
+        color[i] = c;
+        for (int nei : graph[i]) {
+            if (color[nei] == c) {
+                return false;
+            }
+            if (color[nei] == 0 && !dfs(graph, nei, -c)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+public:
+    bool isBipartite(vector<vector<int>>& graph) {
+        int n = graph.size();
+        color.assign(n, 0); // Map node i -> odd=1, even=-1
+
+        for (int i = 0; i < n; i++) {
+            if (color[i] == 0 && !dfs(graph, i, 1)) {
+                return false;
+            }
+        }
+        return true;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} graph
+     * @return {boolean}
+     */
+    isBipartite(graph) {
+        let n = graph.length;
+        let color = new Array(n).fill(0); // Map node i -> odd=1, even=-1
+
+        const dfs = (i, c) => {
+            color[i] = c;
+            for (let nei of graph[i]) {
+                if (color[nei] === c) {
+                    return false;
+                }
+                if (color[nei] === 0 && !dfs(nei, -c)) {
+                    return false;
+                }
+            }
+            return true;
+        };
+
+        for (let i = 0; i < n; i++) {
+            if (color[i] === 0 && !dfs(i, 1)) {
+                return false;
+            }
+        }
+        return true;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(V + E)$
+* Space complexity: $O(V)$
+
+> Where $V$ is the number of vertices and $E$ is the number of edges.
+
+---
+
+## 2. Breadth First Search
+
+::tabs-start
+
+```python
+class Solution:
+    def isBipartite(self, graph: List[List[int]]) -> bool:
+        color = [0] * len(graph)  # Map node i -> odd=1, even=-1
+
+        def bfs(i):
+            if color[i]:
+                return True
+            q = deque([i])
+            color[i] = -1
+            while q:
+                i = q.popleft()
+                for nei in graph[i]:
+                    if color[i] == color[nei]:
+                        return False
+                    elif not color[nei]:
+                        q.append(nei)
+                        color[nei] = -1 * color[i]
+            return True
+
+        for i in range(len(graph)):
+            if not bfs(i):
+                return False
+        return True
+```
+
+```java
+public class Solution {
+    public boolean isBipartite(int[][] graph) {
+        int n = graph.length;
+        int[] color = new int[n]; // Map node i -> odd=1, even=-1
+
+        for (int i = 0; i < n; i++) {
+            if (color[i] != 0) continue;
+            Queue<Integer> q = new LinkedList<>();
+            q.offer(i);
+            color[i] = -1;
+
+            while (!q.isEmpty()) {
+                int node = q.poll();
+                for (int nei : graph[node]) {
+                    if (color[nei] == color[node]) {
+                        return false;
+                    } else if (color[nei] == 0) {
+                        q.offer(nei);
+                        color[nei] = -color[node];
+                    }
+                }
+            }
+        }
+        return true;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    bool isBipartite(vector<vector<int>>& graph) {
+        int n = graph.size();
+        vector<int> color(n, 0); // Map node i -> odd=1, even=-1
+
+        for (int i = 0; i < n; i++) {
+            if (color[i] != 0) continue;
+            queue<int> q;
+            q.push(i);
+            color[i] = -1;
+
+            while (!q.empty()) {
+                int node = q.front();
+                q.pop();
+                for (int nei : graph[node]) {
+                    if (color[nei] == color[node]) {
+                        return false;
+                    } else if (color[nei] == 0) {
+                        q.push(nei);
+                        color[nei] = -color[node];
+                    }
+                }
+            }
+        }
+        return true;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} graph
+     * @return {boolean}
+     */
+    isBipartite(graph) {
+        let n = graph.length;
+        let color = new Array(n).fill(0); // Map node i -> odd=1, even=-1
+
+        for (let i = 0; i < n; i++) {
+            if (color[i] !== 0) continue;
+            let q = new Queue([i]);
+            color[i] = -1;
+
+            while (!q.isEmpty()) {
+                let node = q.pop();
+                for (let nei of graph[node]) {
+                    if (color[nei] === color[node]) {
+                        return false;
+                    } else if (color[nei] === 0) {
+                        q.push(nei);
+                        color[nei] = -color[node];
+                    }
+                }
+            }
+        }
+        return true;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(V + E)$
+* Space complexity: $O(V)$
+
+> Where $V$ is the number of vertices and $E$ is the number of edges.
+
+---
+
+## 3. Iterative DFS
+
+::tabs-start
+
+```python
+class Solution:
+    def isBipartite(self, graph: List[List[int]]) -> bool:
+        color = [0] * len(graph)  # Map node i -> odd=1, even=-1
+        stack = []
+
+        for i in range(len(graph)):
+            if color[i] != 0:
+                continue
+            color[i] = -1
+            stack.append(i)
+            while stack:
+                node = stack.pop()
+                for nei in graph[node]:
+                    if color[node] == color[nei]:
+                        return False
+                    elif not color[nei]:
+                        stack.append(nei)
+                        color[nei] = -1 * color[node]
+
+        return True
+```
+
+```java
+public class Solution {
+    public boolean isBipartite(int[][] graph) {
+        int n = graph.length;
+        int[] color = new int[n]; // Map node i -> odd=1, even=-1
+        Stack<Integer> stack = new Stack<>();
+
+        for (int i = 0; i < n; i++) {
+            if (color[i] != 0) continue;
+            color[i] = -1;
+            stack.push(i);
+            while (!stack.isEmpty()) {
+                int node = stack.pop();
+                for (int nei : graph[node]) {
+                    if (color[node] == color[nei]) return false;
+                    if (color[nei] == 0) {
+                        stack.push(nei);
+                        color[nei] = -color[node];
+                    }
+                }
+            }
+        }
+        return true;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    bool isBipartite(vector<vector<int>>& graph) {
+        int n = graph.size();
+        vector<int> color(n); // Map node i -> odd=1, even=-1
+        stack<int> stack;
+
+        for (int i = 0; i < n; i++) {
+            if (color[i] != 0) continue;
+            color[i] = -1;
+            stack.push(i);
+            while (!stack.empty()) {
+                int node = stack.top();
+                stack.pop();
+                for (int nei : graph[node]) {
+                    if (color[node] == color[nei]) return false;
+                    if (color[nei] == 0) {
+                        stack.push(nei);
+                        color[nei] = -color[node];
+                    }
+                }
+            }
+        }
+        return true;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} graph
+     * @return {boolean}
+     */
+    isBipartite(graph) {
+        let n = graph.length;
+        let color = new Array(n).fill(0); // Map node i -> odd=1, even=-1
+        let stack = [];
+
+        for (let i = 0; i < n; i++) {
+            if (color[i] !== 0) continue;
+            color[i] = -1;
+            stack.push(i);
+            while (stack.length > 0) {
+                let node = stack.pop();
+                for (let nei of graph[node]) {
+                    if (color[node] === color[nei]) return false;
+                    if (color[nei] === 0) {
+                        stack.push(nei);
+                        color[nei] = -color[node];
+                    }
+                }
+            }
+        }
+        return true;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(V + E)$
+* Space complexity: $O(V)$
+
+> 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))
+        self.Size = [0] * 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, u, v):
+        pu, pv = self.find(u), self.find(v)
+        if pu == pv:
+            return False
+        if self.Size[pu] > self.Size[pv]:
+            self.Parent[pv] = pu
+        elif self.Size[pu] < self.Size[pv]:
+            self.Parent[pu] = pv
+        else:
+            self.Parent[pv] = pu
+            self.Size[pu] += 1
+        return True
+
+class Solution:
+    def isBipartite(self, graph: List[List[int]]) -> bool:
+        n = len(graph)
+        dsu = DSU(n)
+
+        for node in range(n):
+            for nei in graph[node]:
+                if dsu.find(node) == dsu.find(nei):
+                    return False
+                dsu.union(graph[node][0], nei)
+
+        return True
+```
+
+```java
+public class DSU {
+    private int[] Parent, Size;
+
+    public DSU(int n) {
+        Parent = new int[n];
+        Size = new int[n];
+        for (int i = 0; i < n; i++) {
+            Parent[i] = i;
+            Size[i] = 0;
+        }
+    }
+
+    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]) {
+            Parent[pv] = pu;
+        } else if (Size[pu] < Size[pv]) {
+            Parent[pu] = pv;
+        } else {
+            Parent[pv] = pu;
+            Size[pu]++;
+        }
+        return true;
+    }
+}
+
+class Solution {
+    public boolean isBipartite(int[][] graph) {
+        int n = graph.length;
+        DSU dsu = new DSU(n);
+
+        for (int node = 0; node < n; node++) {
+            for (int nei : graph[node]) {
+                if (dsu.find(node) == dsu.find(nei)) {
+                    return false;
+                }
+                dsu.union(graph[node][0], nei);
+            }
+        }
+        return true;
+    }
+}
+```
+
+```cpp
+class DSU {
+private:
+    vector<int> Parent, Size;
+    
+public:
+    DSU(int n) {
+        Parent.resize(n);
+        Size.resize(n, 0);
+        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 unionSet(int u, int v) {
+        int pu = find(u), pv = find(v);
+        if (pu == pv) return false;
+        if (Size[pu] > Size[pv]) {
+            Parent[pv] = pu;
+        } else if (Size[pu] < Size[pv]) {
+            Parent[pu] = pv;
+        } else {
+            Parent[pv] = pu;
+            Size[pu]++;
+        }
+        return true;
+    }
+};
+
+class Solution {
+public:
+    bool isBipartite(vector<vector<int>>& graph) {
+        int n = graph.size();
+        DSU dsu(n);
+
+        for (int node = 0; node < n; node++) {
+            for (int& nei : graph[node]) {
+                if (dsu.find(node) == dsu.find(nei)) {
+                    return false;
+                }
+                dsu.unionSet(graph[node][0], nei);
+            }
+        }
+        return true;
+    }
+};
+```
+
+```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[][]} graph
+     * @return {boolean}
+     */
+    isBipartite(graph) {
+        let n = graph.length;
+        let dsu = new DSU(n);
+
+        for (let node = 0; node < n; node++) {
+            for (let nei of graph[node]) {
+                if (dsu.find(node) === dsu.find(nei)) {
+                    return false;
+                }
+                dsu.union(graph[node][0], nei);
+            }
+        }
+        return true;
+    }
+}
+```
+
+::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. $α()$ is used for amortized complexity.
\ No newline at end of file
diff --git a/articles/largest-color-value-in-a-directed-graph.md b/articles/largest-color-value-in-a-directed-graph.md
new file mode 100644
index 000000000..dcbf467a4
--- /dev/null
+++ b/articles/largest-color-value-in-a-directed-graph.md
@@ -0,0 +1,589 @@
+## 1. Brute Force (DFS)
+
+::tabs-start
+
+```python
+class Solution:
+    def largestPathValue(self, colors: str, edges: list[list[int]]) -> int:
+        n = len(colors)
+        adj = [[] for _ in range(n)]
+        for u, v in edges:
+            adj[u].append(v)
+
+        visit = [False] * n
+        def dfs(node, c):
+            if visit[node]:
+                return float("inf")
+
+            visit[node] = True
+            clrCnt = 0
+            for nei in adj[node]:
+                cur = dfs(nei, c)
+                if cur == float("inf"):
+                    return cur
+                clrCnt = max(clrCnt, cur)
+            visit[node] = False
+            return clrCnt + (c == (ord(colors[node]) - ord('a')))
+
+        res = -1
+        for i in range(n):
+            for c in range(26):
+                cnt = dfs(i, c)
+                if cnt == float("inf"):
+                    return -1
+                res = max(res, cnt)
+        return res
+```
+
+```java
+public class Solution {
+    private int n;
+    private List<Integer>[] adj;
+    private boolean[] visit;
+
+    public int largestPathValue(String colors, int[][] edges) {
+        this.n = colors.length();
+        this.adj = new ArrayList[n];
+        this.visit = new boolean[n];
+
+        for (int i = 0; i < n; i++) {
+            adj[i] = new ArrayList<>();
+        }
+        for (int[] edge : edges) {
+            adj[edge[0]].add(edge[1]);
+        }
+
+        int res = -1;
+        for (int i = 0; i < n; i++) {
+            for (int c = 0; c < 26; c++) {
+                int cnt = dfs(i, c, colors);
+                if (cnt == Integer.MAX_VALUE) return -1;
+                res = Math.max(res, cnt);
+            }
+        }
+        return res;
+    }
+
+    private int dfs(int node, int c, String colors) {
+        if (visit[node]) return Integer.MAX_VALUE;
+
+        visit[node] = true;
+        int clrCnt = 0;
+        for (int nei : adj[node]) {
+            int cur = dfs(nei, c, colors);
+            if (cur == Integer.MAX_VALUE) return cur;
+            clrCnt = Math.max(clrCnt, cur);
+        }
+        visit[node] = false;
+        return clrCnt + ((colors.charAt(node) - 'a') == c ? 1 : 0);
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int n;
+    vector<vector<int>> adj;
+    vector<bool> visit;
+
+    int largestPathValue(string colors, vector<vector<int>>& edges) {
+        n = colors.size();
+        adj.assign(n, vector<int>());
+        visit.assign(n, false);
+
+        for (auto& edge : edges) {
+            adj[edge[0]].push_back(edge[1]);
+        }
+
+        int res = -1;
+        for (int i = 0; i < n; i++) {
+            for (int c = 0; c < 26; c++) {
+                int cnt = dfs(i, c, colors);
+                if (cnt == 1e9) return -1;
+                res = max(res, cnt);
+            }
+        }
+        return res;
+    }
+
+private:
+    int dfs(int node, int c, string& colors) {
+        if (visit[node]) return 1e9;
+
+        visit[node] = true;
+        int clrCnt = 0;
+        for (int nei : adj[node]) {
+            int cur = dfs(nei, c, colors);
+            if (cur == 1e9) return cur;
+            clrCnt = max(clrCnt, cur);
+        }
+        visit[node] = false;
+        return clrCnt + ((colors[node] - 'a') == c ? 1 : 0);
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {string} colors
+     * @param {number[][]} edges
+     * @return {number}
+     */
+    largestPathValue(colors, edges) {
+        const n = colors.length;
+        const adj = Array.from({ length: n }, () => []);
+        for (const [u, v] of edges) {
+            adj[u].push(v);
+        }
+
+        const visit = new Array(n).fill(false);
+        const dfs = (node, c) => {
+            if (visit[node]) return Infinity;
+
+            visit[node] = true;
+            let clrCnt = 0;
+            for (const nei of adj[node]) {
+                const cur = dfs(nei, c);
+                if (cur === Infinity) return cur;
+                clrCnt = Math.max(clrCnt, cur);
+            }
+            visit[node] = false;
+            return clrCnt + (c === colors.charCodeAt(node) - 97 ? 1 : 0);
+        };
+
+        let res = -1;
+        for (let i = 0; i < n; i++) {
+            for (let c = 0; c < 26; c++) {
+                const cnt = dfs(i, c);
+                if (cnt === Infinity) return -1;
+                res = Math.max(res, cnt);
+            }
+        }
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(V * (V + E))$
+* Space complexity: $O(V + E)$
+
+> Where $V$ is the number of verticies and $E$ is the number of edges.
+
+---
+
+## 2. Depth First Search
+
+::tabs-start
+
+```python
+class Solution:
+    def largestPathValue(self, colors: str, edges: list[list[int]]) -> int:
+        adj = defaultdict(list)
+        for src, dst in edges:
+            adj[src].append(dst)
+
+        def dfs(node):
+            if node in path:
+                return float("inf")
+            if node in visit:
+                return 0
+
+            visit.add(node)
+            path.add(node)
+            colorIndex = ord(colors[node]) - ord('a')
+            count[node][colorIndex] = 1
+
+            for nei in adj[node]:
+                if dfs(nei) == float("inf"):
+                    return float("inf")
+                for c in range(26):
+                    count[node][c] = max(
+                        count[node][c], 
+                        (1 if c == colorIndex else 0) + count[nei][c]
+                    )
+
+            path.remove(node)
+            return 0
+
+        n, res = len(colors), 0
+        visit, path = set(), set()
+        count = [[0] * 26 for _ in range(n)]
+
+        for i in range(n):
+            if dfs(i) == float("inf"):
+                return -1
+            res = max(res, max(count[i]))
+
+        return res
+```
+
+```java
+public class Solution {
+    private int n;
+    private List<Integer>[] adj;
+    private boolean[] visit, path;
+    private int[][] count;
+
+    public int largestPathValue(String colors, int[][] edges) {
+        this.n = colors.length();
+        this.adj = new ArrayList[n];
+        this.visit = new boolean[n];
+        this.path = new boolean[n];
+        this.count = new int[n][26];
+
+        for (int i = 0; i < n; i++) {
+            adj[i] = new ArrayList<>();
+        }
+        for (int[] edge : edges) {
+            adj[edge[0]].add(edge[1]);
+        }
+
+        int res = 0;
+        for (int i = 0; i < n; i++) {
+            if (dfs(i, colors) == Integer.MAX_VALUE) return -1;
+            for (int c = 0; c < 26; c++) {
+                res = Math.max(res, count[i][c]);
+            }
+        }
+        return res;
+    }
+
+    private int dfs(int node, String colors) {
+        if (path[node]) return Integer.MAX_VALUE;
+        if (visit[node]) return 0;
+
+        visit[node] = true;
+        path[node] = true;
+        int colorIndex = colors.charAt(node) - 'a';
+        count[node][colorIndex] = 1;
+
+        for (int nei : adj[node]) {
+            if (dfs(nei, colors) == Integer.MAX_VALUE) {
+                return Integer.MAX_VALUE;
+            }
+            for (int c = 0; c < 26; c++) {
+                count[node][c] = Math.max(
+                    count[node][c], 
+                    (c == colorIndex ? 1 : 0) + count[nei][c]
+                );
+            }
+        }
+
+        path[node] = false;
+        return 0;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int n, INF = 1e9;
+    vector<vector<int>> adj;
+    vector<bool> visit, path;
+    vector<vector<int>> count;
+
+    int largestPathValue(string colors, vector<vector<int>>& edges) {
+        this->n = colors.size();
+        adj.resize(n);
+        visit.assign(n, false);
+        path.assign(n, false);
+        count.assign(n, vector<int>(26));
+
+        for (auto& edge : edges) {
+            adj[edge[0]].push_back(edge[1]);
+        }
+
+        int res = 0;
+        for (int i = 0; i < n; i++) {
+            if (dfs(i, colors) == INF) return -1;
+            for (int c = 0; c < 26; c++) {
+                res = max(res, count[i][c]);
+            }
+        }
+        return res;
+    }
+
+private:
+    int dfs(int node, string& colors) {
+        if (path[node]) return INF;
+        if (visit[node]) return 0;
+
+        visit[node] = true;
+        path[node] = true;
+        int colorIndex = colors[node] - 'a';
+        count[node][colorIndex] = 1;
+
+        for (int& nei : adj[node]) {
+            if (dfs(nei, colors) == INF) return INF;
+            for (int c = 0; c < 26; c++) {
+                count[node][c] = max(
+                    count[node][c], 
+                    (c == colorIndex ? 1 : 0) + count[nei][c]
+                );
+            }
+        }
+
+        path[node] = false;
+        return 0;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {string} colors
+     * @param {number[][]} edges
+     * @return {number}
+     */
+    largestPathValue(colors, edges) {
+        const n = colors.length;
+        const adj = Array.from({ length: n }, () => []);
+        for (const [src, dst] of edges) {
+            adj[src].push(dst);
+        }
+
+        const visit = new Array(n).fill(false);
+        const path = new Array(n).fill(false);
+        const count = Array.from({ length: n }, () => new Array(26).fill(0));
+
+        const dfs = (node) => {
+            if (path[node]) return Infinity;
+            if (visit[node]) return 0;
+
+            visit[node] = true;
+            path[node] = true;
+            const colorIndex = colors.charCodeAt(node) - 'a'.charCodeAt(0);
+            count[node][colorIndex] = 1;
+
+            for (const nei of adj[node]) {
+                if (dfs(nei) === Infinity) return Infinity;
+                for (let c = 0; c < 26; c++) {
+                    count[node][c] = Math.max(
+                        count[node][c], 
+                        (c === colorIndex ? 1 : 0) + count[nei][c]
+                    );
+                }
+            }
+
+            path[node] = false;
+            return 0;
+        };
+
+        let res = 0;
+        for (let i = 0; i < n; i++) {
+            if (dfs(i) === Infinity) return -1;
+            for (let c = 0; c < 26; c++) {
+                res = Math.max(res, count[i][c]);
+            }
+        }
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(V + E)$
+* Space complexity: $O(V + E)$
+
+> Where $V$ is the number of verticies and $E$ is the number of edges.
+
+---
+
+## 3. Topological Sort (Kahn's Algorithm)
+
+::tabs-start
+
+```python
+class Solution:
+    def largestPathValue(self, colors: str, edges: list[list[int]]) -> int:
+        n = len(colors)
+        adj = [[] for _ in range(n)]
+        indegree = [0] * n
+        count = [[0] * 26 for _ in range(n)]
+
+        for u, v in edges:
+            adj[u].append(v)
+            indegree[v] += 1
+
+        q = deque()
+        for i in range(n):
+            if indegree[i] == 0:
+                q.append(i)
+
+        visit = res = 0
+        while q:
+            node = q.popleft()
+            visit += 1
+            colorIndex = ord(colors[node]) - ord('a')
+            count[node][colorIndex] += 1
+            res = max(res, count[node][colorIndex])
+
+            for nei in adj[node]:
+                for c in range(26):
+                    count[nei][c] = max(count[nei][c], count[node][c])
+                
+                indegree[nei] -= 1
+                if indegree[nei] == 0:
+                    q.append(nei)
+
+        return res if visit == n else -1
+```
+
+```java
+public class Solution {
+    public int largestPathValue(String colors, int[][] edges) {
+        int n = colors.length();
+        List<Integer>[] adj = new ArrayList[n];
+        int[] indegree = new int[n];
+        int[][] count = new int[n][26];
+
+        for (int i = 0; i < n; i++) {
+            adj[i] = new ArrayList<>();
+        }
+
+        for (int[] edge : edges) {
+            adj[edge[0]].add(edge[1]);
+            indegree[edge[1]]++;
+        }
+
+        Queue<Integer> q = new LinkedList<>();
+        for (int i = 0; i < n; i++) {
+            if (indegree[i] == 0) {
+                q.add(i);
+            }
+        }
+
+        int visit = 0, res = 0;
+        while (!q.isEmpty()) {
+            int node = q.poll();
+            visit++;
+            int colorIndex = colors.charAt(node) - 'a';
+            count[node][colorIndex]++;
+            res = Math.max(res, count[node][colorIndex]);
+
+            for (int nei : adj[node]) {
+                for (int c = 0; c < 26; c++) {
+                    count[nei][c] = Math.max(count[nei][c], count[node][c]);
+                }
+                if (--indegree[nei] == 0) {
+                    q.add(nei);
+                }
+            }
+        }
+
+        return visit == n ? res : -1;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int largestPathValue(string colors, vector<vector<int>>& edges) {
+        int n = colors.size();
+        vector<vector<int>> adj(n);
+        vector<int> indegree(n);
+        vector<vector<int>> count(n, vector<int>(26));
+
+        for (auto& edge : edges) {
+            adj[edge[0]].push_back(edge[1]);
+            indegree[edge[1]]++;
+        }
+
+        queue<int> q;
+        for (int i = 0; i < n; i++) {
+            if (indegree[i] == 0) {
+                q.push(i);
+            }
+        }
+
+        int visit = 0, res = 0;
+        while (!q.empty()) {
+            int node = q.front();q.pop();
+            visit++;
+            int colorIndex = colors[node] - 'a';
+            count[node][colorIndex]++;
+            res = max(res, count[node][colorIndex]);
+
+            for (int& nei : adj[node]) {
+                for (int c = 0; c < 26; c++) {
+                    count[nei][c] = max(count[nei][c], count[node][c]);
+                }
+                if (--indegree[nei] == 0) {
+                    q.push(nei);
+                }
+            }
+        }
+
+        return visit == n ? res : -1;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {string} colors
+     * @param {number[][]} edges
+     * @return {number}
+     */
+    largestPathValue(colors, edges) {
+        const n = colors.length;
+        const adj = Array.from({ length: n }, () => []);
+        const indegree = new Array(n).fill(0);
+        const count = Array.from({ length: n }, () => new Array(26).fill(0));
+
+        for (const [u, v] of edges) {
+            adj[u].push(v);
+            indegree[v]++;
+        }
+
+        const q = new Queue();
+        for (let i = 0; i < n; i++) {
+            if (indegree[i] === 0) {
+                q.push(i);
+            }
+        }
+
+        let visit = 0, res = 0;
+        while (!q.isEmpty()) {
+            const node = q.pop();
+            visit++;
+            const colorIndex = colors.charCodeAt(node) - 'a'.charCodeAt(0);
+            count[node][colorIndex]++;
+            res = Math.max(res, count[node][colorIndex]);
+
+            for (const nei of adj[node]) {
+                for (let c = 0; c < 26; c++) {
+                    count[nei][c] = Math.max(count[nei][c], count[node][c]);
+                }
+                if (--indegree[nei] === 0) {
+                    q.push(nei);
+                }
+            }
+        }
+
+        return visit === n ? res : -1;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(V + E)$
+* Space complexity: $O(V + E)$
+
+> Where $V$ is the number of verticies and $E$ is the number of edges.
\ No newline at end of file
diff --git a/articles/minimum-number-of-days-to-eat-n-oranges.md b/articles/minimum-number-of-days-to-eat-n-oranges.md
new file mode 100644
index 000000000..ca4acc077
--- /dev/null
+++ b/articles/minimum-number-of-days-to-eat-n-oranges.md
@@ -0,0 +1,142 @@
+## 1. Recursion
+
+::tabs-start
+
+```python
+
+```
+
+```java
+
+```
+
+```cpp
+
+```
+
+```javascript
+
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(2 ^ n)$
+* Space complexity: $O(n)$
+
+---
+
+## 2. Dynamic Programming (Top-Down)
+
+::tabs-start
+
+```python
+
+```
+
+```java
+
+```
+
+```cpp
+
+```
+
+```javascript
+
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(n)$
+
+---
+
+## 3. Dynamic Programming (Bottom-Up)
+
+::tabs-start
+
+```python
+
+```
+
+```java
+
+```
+
+```cpp
+
+```
+
+```javascript
+
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(n)$
+
+---
+
+## 4. Dynamic Programming (Space Optimized)
+
+::tabs-start
+
+```python
+
+```
+
+```java
+
+```
+
+```cpp
+
+```
+
+```javascript
+
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(1)$
+
+---
+
+## 5. Dynamic Programming (Optimal)
+
+::tabs-start
+
+```python
+
+```
+
+```java
+
+```
+
+```cpp
+
+```
+
+```javascript
+
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(1)$
\ No newline at end of file
diff --git a/articles/minimum-number-of-vertices-to-reach-all-nodes.md b/articles/minimum-number-of-vertices-to-reach-all-nodes.md
new file mode 100644
index 000000000..aa09f1c80
--- /dev/null
+++ b/articles/minimum-number-of-vertices-to-reach-all-nodes.md
@@ -0,0 +1,465 @@
+## 1. Depth First Search
+
+::tabs-start
+
+```python
+class Solution:
+    def findSmallestSetOfVertices(self, n: int, edges: List[List[int]]) -> List[int]:
+        adj = [[] for _ in range(n)]
+        for u, v in edges:
+            adj[u].append(v)
+
+        res = set(range(n))
+        visited = [False] * n
+
+        def dfs(node):
+            visited[node] = True
+            for nei in adj[node]:
+                if not visited[nei]:
+                    dfs(nei)
+                res.discard(nei)
+
+        for i in range(n):
+            if not visited[i]:
+                dfs(i)
+        return list(res)
+```
+
+```java
+public class Solution {
+    public List<Integer> findSmallestSetOfVertices(int n, List<List<Integer>> edges) {
+        List<Integer>[] adj = new ArrayList[n];
+        for (int i = 0; i < n; i++) adj[i] = new ArrayList<>();
+        for (List<Integer> edge : edges) {
+            adj[edge.get(0)].add(edge.get(1));
+        }
+
+        Set<Integer> res = new HashSet<>();
+        for (int i = 0; i < n; i++) {
+            res.add(i);
+        }
+
+        boolean[] visited = new boolean[n];
+        for (int i = 0; i < n; i++) {
+            dfs(i, adj, visited, res);
+        }
+        return new ArrayList<>(res);
+    }
+
+    private void dfs(int node, List<Integer>[] adj, boolean[] visited, Set<Integer> res) {
+        visited[node] = true;
+        for (int nei : adj[node]) {
+            if (!visited[nei]) dfs(nei, adj, visited, res);
+            res.remove(nei);
+        }
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    vector<int> findSmallestSetOfVertices(int n, vector<vector<int>>& edges) {
+        vector<vector<int>> adj(n);
+        for (auto& edge : edges) {
+            adj[edge[0]].push_back(edge[1]);
+        }
+
+        unordered_set<int> res;
+        vector<bool> visited(n, false);
+        for (int i = 0; i < n; i++) res.insert(i);
+
+        function<void(int)> dfs = [&](int node) {
+            visited[node] = true;
+            for (int& nei : adj[node]) {
+                if (!visited[nei]) dfs(nei);
+                res.erase(nei);
+            }
+        };
+
+        for (int i = 0; i < n; i++) {
+            if (!visited[i]) dfs(i);
+        }
+        return vector<int>(res.begin(), res.end());
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number} n
+     * @param {number[][]} edges
+     * @return {number[]}
+     */
+    findSmallestSetOfVertices(n, edges) {
+        const adj = Array.from({ length: n }, () => []);
+        for (const [u, v] of edges) {
+            adj[u].push(v);
+        }
+
+        const res = new Set(Array.from({ length: n }, (_, i) => i));
+        const visited = new Array(n).fill(false);
+
+        const dfs = (node) => {
+            visited[node] = true;
+            for (const nei of adj[node]) {
+                if (!visited[nei]) dfs(nei);
+                res.delete(nei);
+            }
+        };
+
+        for (let i = 0; i < n; i++) {
+            if (!visited[i]) dfs(i);
+        }
+
+        return Array.from(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. Iterative DFS
+
+::tabs-start
+
+```python
+class Solution:
+    def findSmallestSetOfVertices(self, n: int, edges: List[List[int]]) -> List[int]:
+        adj = [[] for _ in range(n)]
+        for u, v in edges:
+            adj[u].append(v)
+
+        res = [True] * n
+        visited = [False] * n
+        stack = []
+
+        for i in range(n):
+            if not visited[i]:
+                stack.append(i)
+                while stack:
+                    node = stack.pop()
+                    if visited[node]:
+                        continue
+                    visited[node] = True
+                    for nei in adj[node]:
+                        if not visited[nei]:
+                            stack.append(nei)
+                        res[nei] = False
+
+        return [i for i in range(n) if res[i]]
+```
+
+```java
+public class Solution {
+    public List<Integer> findSmallestSetOfVertices(int n, List<List<Integer>> edges) {
+        List<Integer>[] adj = new ArrayList[n];
+        for (int i = 0; i < n; i++) {
+            adj[i] = new ArrayList<>();
+        }
+        for (List<Integer> edge : edges) {
+            adj[edge.get(0)].add(edge.get(1));
+        }
+
+        boolean[] res = new boolean[n];
+        Arrays.fill(res, true);
+        boolean[] visited = new boolean[n];
+        Stack<Integer> stack = new Stack<>();
+
+        for (int i = 0; i < n; i++) {
+            if (!visited[i]) {
+                stack.push(i);
+                while (!stack.isEmpty()) {
+                    int node = stack.pop();
+                    if (visited[node]) continue;
+                    visited[node] = true;
+                    for (int nei : adj[node]) {
+                        if (!visited[nei]) stack.push(nei);
+                        res[nei] = false;
+                    }
+                }
+            }
+        }
+
+        List<Integer> result = new ArrayList<>();
+        for (int i = 0; i < n; i++) {
+            if (res[i]) result.add(i);
+        }
+        return result;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    vector<int> findSmallestSetOfVertices(int n, vector<vector<int>>& edges) {
+        vector<vector<int>> adj(n);
+        for (auto& edge : edges) {
+            adj[edge[0]].push_back(edge[1]);
+        }
+
+        vector<bool> res(n, true), visited(n, false);
+        stack<int> stack;
+
+        for (int i = 0; i < n; i++) {
+            if (!visited[i]) {
+                stack.push(i);
+                while (!stack.empty()) {
+                    int node = stack.top();
+                    stack.pop();
+                    if (visited[node]) continue;
+                    visited[node] = true;
+                    for (int nei : adj[node]) {
+                        if (!visited[nei]) stack.push(nei);
+                        res[nei] = false;
+                    }
+                }
+            }
+        }
+
+        vector<int> result;
+        for (int i = 0; i < n; i++) {
+            if (res[i]) result.push_back(i);
+        }
+        return result;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number} n
+     * @param {number[][]} edges
+     * @return {number[]}
+     */
+    findSmallestSetOfVertices(n, edges) {
+        const adj = Array.from({ length: n }, () => []);
+        for (const [u, v] of edges) {
+            adj[u].push(v);
+        }
+
+        const res = Array(n).fill(true);
+        const visited = Array(n).fill(false);
+        const stack = [];
+
+        for (let i = 0; i < n; i++) {
+            if (!visited[i]) {
+                stack.push(i);
+                while (stack.length) {
+                    const node = stack.pop();
+                    if (visited[node]) continue;
+                    visited[node] = true;
+                    for (const nei of adj[node]) {
+                        if (!visited[nei]) stack.push(nei);
+                        res[nei] = false;
+                    }
+                }
+            }
+        }
+
+        return res.map((val, i) => val ? i : -1).filter(i => i !== -1);
+    }
+}
+```
+
+::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. Indegree Count
+
+::tabs-start
+
+```python
+class Solution:
+    def findSmallestSetOfVertices(self, n: int, edges: List[List[int]]) -> List[int]:
+        incoming = collections.defaultdict(list)
+        for src, dst in edges:
+            incoming[dst].append(src)
+
+        res = []
+        for i in range(n):
+            if not incoming[i]:
+                res.append(i)
+        return res
+```
+
+```java
+public class Solution {
+    public List<Integer> findSmallestSetOfVertices(int n, List<List<Integer>> edges) {
+        List<Integer>[] incoming = new ArrayList[n];
+        for (int i = 0; i < n; i++) {
+            incoming[i] = new ArrayList<>();
+        }
+        for (List<Integer> edge : edges) {
+            incoming[edge.get(1)].add(edge.get(0));
+        }
+
+        List<Integer> res = new ArrayList<>();
+        for (int i = 0; i < n; i++) {
+            if (incoming[i].isEmpty()) {
+                res.add(i);
+            }
+        }
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    vector<int> findSmallestSetOfVertices(int n, vector<vector<int>>& edges) {
+        vector<vector<int>> incoming(n);
+        for (auto& edge : edges) {
+            incoming[edge[1]].push_back(edge[0]);
+        }
+
+        vector<int> res;
+        for (int i = 0; i < n; i++) {
+            if (incoming[i].empty()) {
+                res.push_back(i);
+            }
+        }
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number} n
+     * @param {number[][]} edges
+     * @return {number[]}
+     */
+    findSmallestSetOfVertices(n, edges) {
+        const incoming = Array.from({ length: n }, () => []);
+    
+        for (const [src, dst] of edges) {
+            incoming[dst].push(src);
+        }
+
+        const res = [];
+        for (let i = 0; i < n; i++) {
+            if (incoming[i].length === 0) {
+                res.push(i);
+            }
+        }
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(V + E)$
+* Space complexity: $O(V)$
+
+> Where $V$ is the number of vertices and $E$ is the number of edges.
+
+---
+
+## 4. Indegree Count
+
+::tabs-start
+
+```python
+class Solution:
+    def findSmallestSetOfVertices(self, n: int, edges: List[List[int]]) -> List[int]:
+        indegree = [False] * n
+        for src, dst in edges:
+            indegree[dst] = True
+        return [i for i in range(n) if not indegree[i]]
+```
+
+```java
+public class Solution {
+    public List<Integer> findSmallestSetOfVertices(int n, List<List<Integer>> edges) {
+        boolean[] indegree = new boolean[n];
+        for (List<Integer> edge : edges) {
+            indegree[edge.get(1)] = true;
+        }
+
+        List<Integer> res = new ArrayList<>();
+        for (int i = 0; i < n; i++) {
+            if (!indegree[i]) {
+                res.add(i);
+            }
+        }
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    vector<int> findSmallestSetOfVertices(int n, vector<vector<int>>& edges) {
+        vector<bool> indegree(n, false);
+        for (const auto& edge : edges) {
+            indegree[edge[1]] = true;
+        }
+
+        vector<int> res;
+        for (int i = 0; i < n; i++) {
+            if (!indegree[i]) {
+                res.push_back(i);
+            }
+        }
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number} n
+     * @param {number[][]} edges
+     * @return {number[]}
+     */
+    findSmallestSetOfVertices(n, edges) {
+        const indegree = new Array(n).fill(false);
+        for (const [src, dst] of edges) {
+            indegree[dst] = true;
+        }
+
+        let res = [];
+        for (let i = 0; i < n; i++) {
+            if (!indegree[i]) res.push(i);
+        }
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(V + E)$
+* Space complexity: $O(V)$
+
+> Where $V$ is the number of vertices and $E$ is the number of edges.
\ No newline at end of file
diff --git a/articles/path-with-maximum-gold.md b/articles/path-with-maximum-gold.md
new file mode 100644
index 000000000..81c3d201d
--- /dev/null
+++ b/articles/path-with-maximum-gold.md
@@ -0,0 +1,508 @@
+## 1. Backtracking (DFS) - I
+
+::tabs-start
+
+```python
+class Solution:
+    def getMaximumGold(self, grid: list[list[int]]) -> int:
+        ROWS, COLS = len(grid), len(grid[0])
+        directions = [(1, 0), (-1, 0), (0, 1), (0, -1)]
+
+        def dfs(r, c, visit):
+            if min(r, c) < 0 or r == ROWS or c == COLS or grid[r][c] == 0 or (r, c) in visit:
+                return 0
+
+            visit.add((r, c))
+            res = grid[r][c]
+
+            for dr, dc in directions:
+                res = max(res, grid[r][c] + dfs(r + dr, c + dc, visit))
+
+            visit.remove((r, c))
+            return res
+
+        res = 0
+        for r in range(ROWS):
+            for c in range(COLS):
+                if grid[r][c] != 0:
+                    res = max(res, dfs(r, c, set()))
+        return res
+```
+
+```java
+public class Solution {
+    private int ROWS, COLS;
+    private int[][] directions = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
+
+    public int getMaximumGold(int[][] grid) {
+        ROWS = grid.length;
+        COLS = grid[0].length;
+        int res = 0;
+
+        for (int r = 0; r < ROWS; r++) {
+            for (int c = 0; c < COLS; c++) {
+                if (grid[r][c] != 0) {
+                    res = Math.max(res, dfs(grid, r, c, new boolean[ROWS][COLS]));
+                }
+            }
+        }
+        return res;
+    }
+
+    private int dfs(int[][] grid, int r, int c, boolean[][] visit) {
+        if (r < 0 || c < 0 || r >= ROWS || c >= COLS || 
+            grid[r][c] == 0 || visit[r][c]) {
+            return 0;
+        }
+
+        visit[r][c] = true;
+        int res = grid[r][c];
+
+        for (int[] d : directions) {
+            res = Math.max(res, grid[r][c] + dfs(grid, r + d[0], c + d[1], visit));
+        }
+
+        visit[r][c] = false;
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int ROWS, COLS;
+    vector<vector<int>> directions = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
+
+    int getMaximumGold(vector<vector<int>>& grid) {
+        ROWS = grid.size();
+        COLS = grid[0].size();
+        int res = 0;
+
+        for (int r = 0; r < ROWS; r++) {
+            for (int c = 0; c < COLS; c++) {
+                if (grid[r][c] != 0) {
+                    vector<vector<bool>> visit(ROWS, vector<bool>(COLS, false));
+                    res = max(res, dfs(grid, r, c, visit));
+                }
+            }
+        }
+        return res;
+    }
+
+private:
+    int dfs(vector<vector<int>>& grid, int r, int c, vector<vector<bool>>& visit) {
+        if (r < 0 || c < 0 || r >= ROWS || c >= COLS || grid[r][c] == 0 || visit[r][c]) {
+            return 0;
+        }
+
+        visit[r][c] = true;
+        int res = grid[r][c];
+
+        for (auto& d : directions) {
+            res = max(res, grid[r][c] + dfs(grid, r + d[0], c + d[1], visit));
+        }
+
+        visit[r][c] = false;
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} grid
+     * @return {number}
+     */
+    getMaximumGold(grid) {
+        const ROWS = grid.length, COLS = grid[0].length;
+        const directions = [[1, 0], [-1, 0], [0, 1], [0, -1]];
+
+        const dfs = (r, c, visit) => {
+            if (r < 0 || c < 0 || r >= ROWS || c >= COLS || grid[r][c] === 0 || visit[r][c]) {
+                return 0;
+            }
+
+            visit[r][c] = true;
+            let res = grid[r][c];
+
+            for (const [dr, dc] of directions) {
+                res = Math.max(res, grid[r][c] + dfs(r + dr, c + dc, visit));
+            }
+
+            visit[r][c] = 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) {
+                    let visit = Array.from({ length: ROWS }, () => Array(COLS).fill(false));
+                    res = Math.max(res, dfs(r, c, visit));
+                }
+            }
+        }
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(N * 3 ^ N)$
+* Space complexity: $O(N)$
+
+> Where $N$ is the number of cells which contain gold.
+
+---
+
+## 2. Backtracking (DFS) - II
+
+::tabs-start
+
+```python
+class Solution:
+    def getMaximumGold(self, grid: list[list[int]]) -> int:
+        ROWS, COLS = len(grid), len(grid[0])
+        directions = [(1, 0), (-1, 0), (0, 1), (0, -1)]
+
+        def dfs(r, c):
+            if min(r, c) < 0 or r == ROWS or c == COLS or grid[r][c] == 0:
+                return 0
+            
+            gold = grid[r][c]
+            grid[r][c] = 0
+            res = 0
+
+            for dr, dc in directions:
+                res = max(res, dfs(r + dr, c + dc))
+
+            grid[r][c] = gold
+            return gold + res
+
+        res = 0
+        for r in range(ROWS):
+            for c in range(COLS):
+                if grid[r][c] != 0:
+                    res = max(res, dfs(r, c))
+        return res
+```
+
+```java
+public class Solution {
+    private int ROWS, COLS;
+    private int[][] directions = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
+
+    public int getMaximumGold(int[][] grid) {
+        ROWS = grid.length;
+        COLS = grid[0].length;
+        int res = 0;
+
+        for (int r = 0; r < ROWS; r++) {
+            for (int c = 0; c < COLS; c++) {
+                if (grid[r][c] != 0) {
+                    res = Math.max(res, dfs(grid, r, c));
+                }
+            }
+        }
+        return res;
+    }
+
+    private int dfs(int[][] grid, int r, int c) {
+        if (r < 0 || c < 0 || r >= ROWS || c >= COLS || grid[r][c] == 0) {
+            return 0;
+        }
+
+        int gold = grid[r][c];
+        grid[r][c] = 0;
+        int res = 0;
+
+        for (int[] d : directions) {
+            res = Math.max(res, dfs(grid, r + d[0], c + d[1]));
+        }
+
+        grid[r][c] = gold;
+        return gold + res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int ROWS, COLS;
+    vector<vector<int>> directions = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
+
+    int getMaximumGold(vector<vector<int>>& grid) {
+        ROWS = grid.size();
+        COLS = grid[0].size();
+        int res = 0;
+
+        for (int r = 0; r < ROWS; r++) {
+            for (int c = 0; c < COLS; c++) {
+                if (grid[r][c] != 0) {
+                    res = max(res, dfs(grid, r, c));
+                }
+            }
+        }
+        return res;
+    }
+
+private:
+    int dfs(vector<vector<int>>& grid, int r, int c) {
+        if (r < 0 || c < 0 || r >= ROWS || c >= COLS || grid[r][c] == 0) {
+            return 0;
+        }
+
+        int gold = grid[r][c];
+        grid[r][c] = 0;
+        int res = 0;
+
+        for (auto& d : directions) {
+            res = max(res, dfs(grid, r + d[0], c + d[1]));
+        }
+
+        grid[r][c] = gold;
+        return gold + res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} grid
+     * @return {number}
+     */
+    getMaximumGold(grid) {
+        const ROWS = grid.length, COLS = grid[0].length;
+        const directions = [[1, 0], [-1, 0], [0, 1], [0, -1]];
+
+        const dfs = (r, c) => {
+            if (r < 0 || c < 0 || r >= ROWS || c >= COLS || grid[r][c] === 0) {
+                return 0;
+            }
+
+            let gold = grid[r][c];
+            grid[r][c] = 0;
+            let res = 0;
+
+            for (const [dr, dc] of directions) {
+                res = Math.max(res, dfs(r + dr, c + dc));
+            }
+
+            grid[r][c] = gold;
+            return gold + res;
+        };
+
+        let res = 0;
+        for (let r = 0; r < ROWS; r++) {
+            for (let c = 0; c < COLS; c++) {
+                if (grid[r][c] !== 0) {
+                    res = Math.max(res, dfs(r, c));
+                }
+            }
+        }
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(N * 3 ^ N)$
+* Space complexity: $O(N)$ for recursion stack.
+
+> Where $N$ is the number of cells which contain gold.
+
+---
+
+## 3. Backtracking (BFS)
+
+::tabs-start
+
+```python
+class Solution:
+    def getMaximumGold(self, grid: list[list[int]]) -> int:
+        ROWS, COLS = len(grid), len(grid[0])
+        directions = [1, 0, -1, 0, 1]
+        index = [[0] * COLS for _ in range(ROWS)]
+        idx = 0
+
+        for r in range(ROWS):
+            for c in range(COLS):
+                if grid[r][c] != 0:
+                    index[r][c] = idx
+                    idx += 1
+
+        res = 0
+        for r in range(ROWS):
+            for c in range(COLS):
+                if grid[r][c] > 0:
+                    q = deque([(r, c, grid[r][c], 1 << index[r][c])])
+                    while q:
+                        row, col, gold, mask = q.popleft()
+                        res = max(res, gold)
+
+                        for i in range(4):
+                            nr, nc = row + directions[i], col + directions[i + 1]
+                            if 0 <= nr < ROWS and 0 <= nc < COLS and grid[nr][nc] > 0:
+                                idx = index[nr][nc]
+                                if not (mask & (1 << idx)):
+                                    q.append((nr, nc, gold + grid[nr][nc], mask | (1 << idx)))
+
+        return res
+```
+
+```java
+public class Solution {
+    public int getMaximumGold(int[][] grid) {
+        int ROWS = grid.length, COLS = grid[0].length;
+        int[][] index = new int[ROWS][COLS];
+        int idx = 0;
+        int[] directions = {1, 0, -1, 0, 1};
+
+        for (int r = 0; r < ROWS; r++) {
+            for (int c = 0; c < COLS; c++) {
+                if (grid[r][c] != 0) {
+                    index[r][c] = idx++;
+                }
+            }
+        }
+
+        int res = 0;
+        for (int r = 0; r < ROWS; r++) {
+            for (int c = 0; c < COLS; c++) {
+                if (grid[r][c] > 0) {
+                    Queue<int[]> q = new LinkedList<>();
+                    q.offer(new int[]{r, c, grid[r][c], 1 << index[r][c]});
+
+                    while (!q.isEmpty()) {
+                        int[] cur = q.poll();
+                        int row = cur[0], col = cur[1], gold = cur[2], mask = cur[3];
+                        res = Math.max(res, gold);
+
+                        for (int i = 0; i < 4; i++) {
+                            int nr = row + directions[i], nc = col + directions[i + 1];
+                            if (nr >= 0 && nr < ROWS && nc >= 0 && nc < COLS && grid[nr][nc] > 0) {
+                                int newIdx = index[nr][nc];
+                                if ((mask & (1 << newIdx)) == 0) {
+                                    q.offer(new int[]{nr, nc, gold + grid[nr][nc], mask | (1 << newIdx)});
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int getMaximumGold(vector<vector<int>>& grid) {
+        int ROWS = grid.size(), COLS = grid[0].size();
+        vector<vector<int>> index(ROWS, vector<int>(COLS, 0));
+        int idx = 0;
+        int directions[] = {1, 0, -1, 0, 1};
+
+        for (int r = 0; r < ROWS; r++) {
+            for (int c = 0; c < COLS; c++) {
+                if (grid[r][c] != 0) {
+                    index[r][c] = idx++;
+                }
+            }
+        }
+
+        int res = 0;
+        for (int r = 0; r < ROWS; r++) {
+            for (int c = 0; c < COLS; c++) {
+                if (grid[r][c] > 0) {
+                    queue<tuple<int, int, int, int>> q;
+                    q.push({r, c, grid[r][c], 1 << index[r][c]});
+
+                    while (!q.empty()) {
+                        auto [row, col, gold, mask] = q.front();q.pop();
+                        res = max(res, gold);
+                        for (int i = 0; i < 4; i++) {
+                            int nr = row + directions[i], nc = col + directions[i + 1];
+                            if (nr >= 0 && nr < ROWS && nc >= 0 && nc < COLS && grid[nr][nc] > 0) {
+                                int newIdx = index[nr][nc];
+                                if ((mask & (1 << newIdx)) == 0) {
+                                    q.push({nr, nc, gold + grid[nr][nc], mask | (1 << newIdx)});
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} grid
+     * @return {number}
+     */
+    getMaximumGold(grid) {
+        const ROWS = grid.length, COLS = grid[0].length;
+        const index = Array.from({ length: ROWS }, () => Array(COLS).fill(0));
+        let idx = 0;
+        const directions = [1, 0, -1, 0, 1];
+
+        for (let r = 0; r < ROWS; r++) {
+            for (let c = 0; c < COLS; c++) {
+                if (grid[r][c] !== 0) {
+                    index[r][c] = idx++;
+                }
+            }
+        }
+
+        let res = 0;
+        for (let r = 0; r < ROWS; r++) {
+            for (let c = 0; c < COLS; c++) {
+                if (grid[r][c] > 0) {
+                    const q = new Queue([[r, c, grid[r][c], 1 << index[r][c]]]);
+
+                    while (!q.isEmpty()) {
+                        const [row, col, gold, mask] = q.pop();
+                        res = Math.max(res, gold);
+                        for (let i = 0; i < 4; i++) {
+                            const nr = row + directions[i], nc = col + directions[i + 1];
+                            if (nr >= 0 && nr < ROWS && nc >= 0 && nc < COLS && grid[nr][nc] > 0) {
+                                const newIdx = index[nr][nc];
+                                if (!(mask & (1 << newIdx))) {
+                                    q.push([nr, nc, gold + grid[nr][nc], mask | (1 << newIdx)]);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(N * 3 ^ N)$
+* Space complexity: $O(N)$
+
+> Where $N$ is the number of cells which contain gold.
\ No newline at end of file

From 29bbb485fbb8778981a4d9dc04a229f22f2285e5 Mon Sep 17 00:00:00 2001
From: Sri Hari <kataresrihari@gmail.com>
Date: Wed, 5 Feb 2025 21:15:31 +0530
Subject: [PATCH 02/13] Batch-5/Neetcode-ALL/Added-articles

---
 articles/design-browser-history.md            | 640 ++++++++++++++
 articles/find-all-people-with-secret.md       | 834 ++++++++++++++++++
 ...minimum-number-of-days-to-eat-n-oranges.md | 340 +++++--
 articles/parallel-courses-iii.md              | 481 ++++++++++
 4 files changed, 2231 insertions(+), 64 deletions(-)
 create mode 100644 articles/design-browser-history.md
 create mode 100644 articles/find-all-people-with-secret.md
 create mode 100644 articles/parallel-courses-iii.md

diff --git a/articles/design-browser-history.md b/articles/design-browser-history.md
new file mode 100644
index 000000000..a557f9151
--- /dev/null
+++ b/articles/design-browser-history.md
@@ -0,0 +1,640 @@
+## 1. Two Stacks
+
+::tabs-start
+
+```python
+class BrowserHistory:
+
+    def __init__(self, homepage: str):
+        self.back_history = [homepage]
+        self.front_history = []
+
+    def visit(self, url: str) -> None:
+        self.back_history.append(url)
+        self.front_history = []
+
+    def back(self, steps: int) -> str:
+        while steps and len(self.back_history) > 1:
+            self.front_history.append(self.back_history.pop())
+            steps -= 1
+        return self.back_history[-1]
+
+    def forward(self, steps: int) -> str:
+        while steps and self.front_history:
+            self.back_history.append(self.front_history.pop())
+            steps -= 1
+        return self.back_history[-1]
+```
+
+```java
+public class BrowserHistory {
+    private Stack<String> backHistory;
+    private Stack<String> frontHistory;
+
+    public BrowserHistory(String homepage) {
+        backHistory = new Stack<>();
+        frontHistory = new Stack<>();
+        backHistory.push(homepage);
+    }
+
+    public void visit(String url) {
+        backHistory.push(url);
+        frontHistory = new Stack<>();
+    }
+
+    public String back(int steps) {
+        while (steps > 0 && backHistory.size() > 1) {
+            frontHistory.push(backHistory.pop());
+            steps--;
+        }
+        return backHistory.peek();
+    }
+
+    public String forward(int steps) {
+        while (steps > 0 && !frontHistory.isEmpty()) {
+            backHistory.push(frontHistory.pop());
+            steps--;
+        }
+        return backHistory.peek();
+    }
+}
+```
+
+```cpp
+class BrowserHistory {
+private:
+    stack<string> backHistory, frontHistory;
+
+public:
+    BrowserHistory(string homepage) {
+        backHistory.push(homepage);
+    }
+
+    void visit(string url) {
+        backHistory.push(url);
+        frontHistory = stack<string>();
+    }
+
+    string back(int steps) {
+        while (steps-- && backHistory.size() > 1) {
+            frontHistory.push(backHistory.top());
+            backHistory.pop();
+        }
+        return backHistory.top();
+    }
+
+    string forward(int steps) {
+        while (steps-- && !frontHistory.empty()) {
+            backHistory.push(frontHistory.top());
+            frontHistory.pop();
+        }
+        return backHistory.top();
+    }
+};
+```
+
+```javascript
+class BrowserHistory {
+    /**
+     * @constructor
+     * @param {string} homepage
+     */
+    constructor(homepage) {
+        this.backHistory = [homepage];
+        this.frontHistory = [];
+    }
+
+    /** 
+     * @param {string} url
+     * @return {void}
+     */
+    visit(url) {
+        this.backHistory.push(url);
+        this.frontHistory = [];
+    }
+
+    /** 
+     * @param {number} steps
+     * @return {string}
+     */
+    back(steps) {
+        while (steps-- > 0 && this.backHistory.length > 1) {
+            this.frontHistory.push(this.backHistory.pop());
+        }
+        return this.backHistory[this.backHistory.length - 1];
+    }
+
+    /** 
+     * @param {number} steps
+     * @return {string}
+     */
+    forward(steps) {
+        while (steps-- > 0 && this.frontHistory.length > 0) {
+            this.backHistory.push(this.frontHistory.pop());
+        }
+        return this.backHistory[this.backHistory.length - 1];
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity:
+    * $O(1)$ time for initialization.
+    * $O(1)$ time for each $visit()$ function call.
+    * $O(min(n, steps))$ time for each $back()$ and $forward()$ function calls.
+* Space complexity: $O(m * n)$
+
+> Where $n$ is the number of visited urls, $m$ is the average length of each url, and $steps$ is the number of steps we go forward or back.
+
+---
+
+## 2. Dynamic Array
+
+::tabs-start
+
+```python
+class BrowserHistory:
+
+    def __init__(self, homepage: str):
+        self.history = [homepage]
+        self.cur = 0
+
+    def visit(self, url: str) -> None:
+        self.cur += 1
+        self.history = self.history[:self.cur]
+        self.history.append(url)
+
+    def back(self, steps: int) -> str:
+        self.cur = max(0, self.cur - steps)
+        return self.history[self.cur]
+
+    def forward(self, steps: int) -> str:
+        self.cur = min(len(self.history) - 1, self.cur + steps)
+        return self.history[self.cur]
+```
+
+```java
+public class BrowserHistory {
+    private List<String> history;
+    private int cur;
+
+    public BrowserHistory(String homepage) {
+        history = new ArrayList<>();
+        history.add(homepage);
+        cur = 0;
+    }
+
+    public void visit(String url) {
+        cur++;
+        history = history.subList(0, cur);
+        history.add(url);
+    }
+
+    public String back(int steps) {
+        cur = Math.max(0, cur - steps);
+        return history.get(cur);
+    }
+
+    public String forward(int steps) {
+        cur = Math.min(history.size() - 1, cur + steps);
+        return history.get(cur);
+    }
+}
+```
+
+```cpp
+class BrowserHistory {
+private:
+    vector<string> history;
+    int cur;
+
+public:
+    BrowserHistory(string homepage) {
+        history.push_back(homepage);
+        cur = 0;
+    }
+
+    void visit(string url) {
+        cur++;
+        history.resize(cur);
+        history.push_back(url);
+    }
+
+    string back(int steps) {
+        cur = max(0, cur - steps);
+        return history[cur];
+    }
+
+    string forward(int steps) {
+        cur = min((int)history.size() - 1, cur + steps);
+        return history[cur];
+    }
+};
+```
+
+```javascript
+class BrowserHistory {
+    /**
+     * @constructor
+     * @param {string} homepage
+     */
+    constructor(homepage) {
+        this.history = [homepage];
+        this.cur = 0;
+    }
+
+    /** 
+     * @param {string} url
+     * @return {void}
+     */
+    visit(url) {
+        this.cur++;
+        this.history = this.history.slice(0, this.cur);
+        this.history.push(url);
+    }
+
+    /** 
+     * @param {number} steps
+     * @return {string}
+     */
+    back(steps) {
+        this.cur = Math.max(0, this.cur - steps);
+        return this.history[this.cur];
+    }
+
+    /** 
+     * @param {number} steps
+     * @return {string}
+     */
+    forward(steps) {
+        this.cur = Math.min(this.history.length - 1, this.cur + steps);
+        return this.history[this.cur];
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity:
+    * $O(1)$ time for initialization.
+    * $O(n)$ time for each $visit()$ function call.
+    * $O(1)$ time for each $back()$ and $forward()$ function calls.
+* Space complexity: $O(m * n)$
+
+> Where $n$ is the number of visited urls and $m$ is the average length of each url.
+
+---
+
+## 3. Dynamic Array (Optimal)
+
+::tabs-start
+
+```python
+class BrowserHistory:
+
+    def __init__(self, homepage: str):
+        self.history = [homepage]
+        self.cur = 0
+        self.n = 1
+
+    def visit(self, url: str) -> None:
+        self.cur += 1
+        if self.cur == len(self.history):
+            self.history.append(url)
+            self.n += 1
+        else:
+            self.history[self.cur] = url
+            self.n = self.cur + 1
+
+    def back(self, steps: int) -> str:
+        self.cur = max(0, self.cur - steps)
+        return self.history[self.cur]
+
+    def forward(self, steps: int) -> str:
+        self.cur = min(self.n - 1, self.cur + steps)
+        return self.history[self.cur]
+```
+
+```java
+public class BrowserHistory {
+    private List<String> history;
+    private int cur;
+    private int n;
+
+    public BrowserHistory(String homepage) {
+        history = new ArrayList<>();
+        history.add(homepage);
+        cur = 0;
+        n = 1;
+    }
+
+    public void visit(String url) {
+        cur++;
+        if (cur == history.size()) {
+            history.add(url);
+            n++;
+        } else {
+            history.set(cur, url);
+            n = cur + 1;
+        }
+    }
+
+    public String back(int steps) {
+        cur = Math.max(0, cur - steps);
+        return history.get(cur);
+    }
+
+    public String forward(int steps) {
+        cur = Math.min(n - 1, cur + steps);
+        return history.get(cur);
+    }
+}
+```
+
+```cpp
+class BrowserHistory {
+private:
+    vector<string> history;
+    int cur, n;
+
+public:
+    BrowserHistory(string homepage) {
+        history.push_back(homepage);
+        cur = 0;
+        n = 1;
+    }
+
+    void visit(string url) {
+        cur++;
+        if (cur == history.size()) {
+            history.push_back(url);
+            n++;
+        } else {
+            history[cur] = url;
+            n = cur + 1;
+        }
+    }
+
+    string back(int steps) {
+        cur = max(0, cur - steps);
+        return history[cur];
+    }
+
+    string forward(int steps) {
+        cur = min(n - 1, cur + steps);
+        return history[cur];
+    }
+};
+```
+
+```javascript
+class BrowserHistory {
+    /**
+     * @constructor
+     * @param {string} homepage
+     */
+    constructor(homepage) {
+        this.history = [homepage];
+        this.cur = 0;
+        this.n = 1;
+    }
+
+    /** 
+     * @param {string} url
+     * @return {void}
+     */
+    visit(url) {
+        this.cur++;
+        if (this.cur === this.history.length) {
+            this.history.push(url);
+            this.n++;
+        } else {
+            this.history[this.cur] = url;
+            this.n = this.cur + 1;
+        }
+    }
+
+    /** 
+     * @param {number} steps
+     * @return {string}
+     */
+    back(steps) {
+        this.cur = Math.max(0, this.cur - steps);
+        return this.history[this.cur];
+    }
+
+    /** 
+     * @param {number} steps
+     * @return {string}
+     */
+    forward(steps) {
+        this.cur = Math.min(this.n - 1, this.cur + steps);
+        return this.history[this.cur];
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity:
+    * $O(1)$ time for initialization.
+    * $O(1)$ time for each $visit()$ function call.
+    * $O(1)$ time for each $back()$ and $forward()$ function calls.
+* Space complexity: $O(m * n)$
+
+> Where $n$ is the number of visited urls and $m$ is the average length of each url.
+
+---
+
+## 4. Doubly Linked List
+
+::tabs-start
+
+```python
+class ListNode:
+    def __init__(self, val, prev=None, next=None):
+        self.val = val
+        self.prev = prev
+        self.next = next
+
+class BrowserHistory:
+
+    def __init__(self, homepage: str):
+        self.cur = ListNode(homepage)
+
+    def visit(self, url: str) -> None:
+        self.cur.next = ListNode(url, self.cur)
+        self.cur = self.cur.next
+
+    def back(self, steps: int) -> str:
+        while self.cur.prev and steps > 0:
+            self.cur = self.cur.prev
+            steps -= 1
+        return self.cur.val
+
+    def forward(self, steps: int) -> str:
+        while self.cur.next and steps > 0:
+            self.cur = self.cur.next
+            steps -= 1
+        return self.cur.val
+```
+
+```java
+class ListNode {
+    String val;
+    ListNode prev, next;
+
+    public ListNode(String val, ListNode prev, ListNode next) {
+        this.val = val;
+        this.prev = prev;
+        this.next = next;
+    }
+
+    public ListNode(String val) {
+        this(val, null, null);
+    }
+}
+
+public class BrowserHistory {
+    private ListNode cur;
+
+    public BrowserHistory(String homepage) {
+        cur = new ListNode(homepage);
+    }
+
+    public void visit(String url) {
+        cur.next = new ListNode(url, cur, null);
+        cur = cur.next;
+    }
+
+    public String back(int steps) {
+        while (cur.prev != null && steps > 0) {
+            cur = cur.prev;
+            steps--;
+        }
+        return cur.val;
+    }
+
+    public String forward(int steps) {
+        while (cur.next != null && steps > 0) {
+            cur = cur.next;
+            steps--;
+        }
+        return cur.val;
+    }
+}
+```
+
+```cpp
+class BrowserHistory {
+    struct ListNode {
+    public:
+        string val;
+        ListNode* prev;
+        ListNode* next;
+
+        ListNode(string val, ListNode* prev = nullptr, ListNode* next = nullptr) 
+            : val(val), prev(prev), next(next) {}
+    };
+
+    ListNode* cur;
+
+public:
+    BrowserHistory(string homepage) {
+        cur = new ListNode(homepage);
+    }
+
+    void visit(string url) {
+        cur->next = new ListNode(url, cur, nullptr);
+        cur = cur->next;
+    }
+
+    string back(int steps) {
+        while (cur->prev != nullptr && steps > 0) {
+            cur = cur->prev;
+            steps--;
+        }
+        return cur->val;
+    }
+
+    string forward(int steps) {
+        while (cur->next != nullptr && steps > 0) {
+            cur = cur->next;
+            steps--;
+        }
+        return cur->val;
+    }
+};
+```
+
+```javascript
+class ListNode {
+    constructor(val, prev = null, next = null) {
+        this.val = val;
+        this.prev = prev;
+        this.next = next;
+    }
+}
+
+class BrowserHistory {
+    /**
+     * @constructor
+     * @param {string} homepage
+     */
+    constructor(homepage) {
+        this.cur = new ListNode(homepage);
+    }
+
+    /** 
+     * @param {string} url
+     * @return {void}
+     */
+    visit(url) {
+        this.cur.next = new ListNode(url, this.cur, null);
+        this.cur = this.cur.next;
+    }
+
+    /** 
+     * @param {number} steps
+     * @return {string}
+     */
+    back(steps) {
+        while (this.cur.prev !== null && steps > 0) {
+            this.cur = this.cur.prev;
+            steps--;
+        }
+        return this.cur.val;
+    }
+
+    /** 
+     * @param {number} steps
+     * @return {string}
+     */
+    forward(steps) {
+        while (this.cur.next !== null && steps > 0) {
+            this.cur = this.cur.next;
+            steps--;
+        }
+        return this.cur.val;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity:
+    * $O(1)$ time for initialization.
+    * $O(1)$ time for each $visit()$ function call.
+    * $O(min(n, steps))$ time for each $back()$ and $forward()$ function calls.
+* Space complexity: $O(m * n)$
+
+> Where $n$ is the number of visited urls, $m$ is the average length of each url, and $steps$ is the number of steps we go forward or back.
\ No newline at end of file
diff --git a/articles/find-all-people-with-secret.md b/articles/find-all-people-with-secret.md
new file mode 100644
index 000000000..1d1b58e20
--- /dev/null
+++ b/articles/find-all-people-with-secret.md
@@ -0,0 +1,834 @@
+## 1. Depth First Search
+
+::tabs-start
+
+```python
+class Solution:
+    def findAllPeople(self, n: int, meetings: list[list[int]], firstPerson: int) -> list[int]:
+        secrets = set([0, firstPerson])  # People with secret
+        time_map = {}  # time -> adjacency list meetings
+
+        for src, dst, t in meetings:
+            if t not in time_map:
+                time_map[t] = defaultdict(list)
+            time_map[t][src].append(dst)
+            time_map[t][dst].append(src)
+
+        def dfs(src, adj):
+            if src in visit:
+                return
+            visit.add(src)
+            secrets.add(src)
+            for nei in adj[src]:
+                dfs(nei, adj)
+
+        for t in sorted(time_map.keys()):
+            visit = set()
+            for src in time_map[t]:
+                if src in secrets:
+                    dfs(src, time_map[t])
+
+        return list(secrets)
+```
+
+```java
+public class Solution {
+    private Set<Integer> secrets, visit;
+
+    public List<Integer> findAllPeople(int n, int[][] meetings, int firstPerson) {
+        secrets = new HashSet<>();
+        visit = new HashSet<>();
+        secrets.add(0);
+        secrets.add(firstPerson);
+        Map<Integer, Map<Integer, List<Integer>>> time_map = new HashMap<>();
+
+        for (int[] meet : meetings) {
+            int src = meet[0], dst = meet[1], t = meet[2];
+            time_map.putIfAbsent(t, new HashMap<>());
+            time_map.get(t).putIfAbsent(src, new ArrayList<>());
+            time_map.get(t).putIfAbsent(dst, new ArrayList<>());
+            time_map.get(t).get(src).add(dst);
+            time_map.get(t).get(dst).add(src);
+        }
+
+        List<Integer> timeKeys = new ArrayList<>(time_map.keySet());
+        Collections.sort(timeKeys);
+        for (int t : timeKeys) {
+            visit = new HashSet<>();
+            for (int src : time_map.get(t).keySet()) {
+                if (secrets.contains(src)) {
+                    dfs(src, time_map.get(t));
+                }
+            }
+        }
+        return new ArrayList<>(secrets);
+    }
+
+    private void dfs(int src, Map<Integer, List<Integer>> adj) {
+        if (!visit.add(src)) return;
+        secrets.add(src);
+        for (int nei : adj.getOrDefault(src, new ArrayList<>())) {
+            dfs(nei, adj);
+        }
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    unordered_set<int> secrets, visit;
+
+    vector<int> findAllPeople(int n, vector<vector<int>>& meetings, int firstPerson) {
+        secrets = {0, firstPerson};
+        unordered_map<int, unordered_map<int, vector<int>>> time_map;
+
+        for (auto& meet : meetings) {
+            int src = meet[0], dst = meet[1], t = meet[2];
+            time_map[t][src].push_back(dst);
+            time_map[t][dst].push_back(src);
+        }
+
+        vector<int> timeKeys;
+        for (auto& [t, _] : time_map) {
+            timeKeys.push_back(t);
+        }
+        sort(timeKeys.begin(), timeKeys.end());
+
+        for (int& t : timeKeys) {
+            visit.clear();
+            for (auto& [src, _] : time_map[t]) {
+                if (secrets.count(src)) {
+                    dfs(src, time_map[t]);
+                }
+            }
+        }
+
+        return vector<int>(secrets.begin(), secrets.end());
+    }
+
+private:
+    void dfs(int src, unordered_map<int, vector<int>>& adj) {
+        if (!visit.insert(src).second) return;
+        secrets.insert(src);
+        for (int& nei : adj[src]) {
+            dfs(nei, adj);
+        }
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number} n
+     * @param {number[][]} meetings
+     * @param {number} firstPerson
+     * @return {number[]}
+     */
+    findAllPeople(n, meetings, firstPerson) {
+        const secrets = new Set([0, firstPerson]);
+        let visit = new Set();
+        let time_map = new Map();
+
+        for (let [src, dst, t] of meetings) {
+            if (!time_map.has(t)) time_map.set(t, new Map());
+            if (!time_map.get(t).has(src)) time_map.get(t).set(src, []);
+            if (!time_map.get(t).has(dst)) time_map.get(t).set(dst, []);
+            time_map.get(t).get(src).push(dst);
+            time_map.get(t).get(dst).push(src);
+        }
+        const dfs = (src, adj) => {
+            if (visit.has(src)) return;
+            visit.add(src);
+            secrets.add(src);
+            for (let nei of (adj.get(src) || [])) {
+                dfs(nei, adj);
+            }
+        };
+
+        let timeKeys = [...time_map.keys()].sort((a, b) => a - b);
+        for (let t of timeKeys) {
+            visit.clear();
+            for (let src of time_map.get(t).keys()) {
+                if (secrets.has(src)) {
+                    dfs(src, time_map.get(t));
+                }
+            }
+        }
+
+        return [...secrets];
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(m \log m + n)$
+* Space complexity: $O(m + n)$
+
+> Where $m$ is the number of meetings and $n$ is the number of people.
+
+---
+
+## 2. Breadth First Search
+
+::tabs-start
+
+```python
+class Solution:
+    def findAllPeople(self, n: int, meetings: list[list[int]], firstPerson: int) -> list[int]:
+        secrets = set([0, firstPerson])  # People with secret
+        time_map = {}  # time -> adjacency list meetings
+
+        for src, dst, t in meetings:
+            if t not in time_map:
+                time_map[t] = defaultdict(list)
+            time_map[t][src].append(dst)
+            time_map[t][dst].append(src)
+
+        for t in sorted(time_map.keys()):
+            visit = set()
+            q = deque()
+
+            for src in time_map[t]:
+                if src in secrets:
+                    q.append(src)
+                    visit.add(src)
+
+            while q:
+                node = q.popleft()
+                secrets.add(node)
+                for nei in time_map[t][node]:
+                    if nei not in visit:
+                        visit.add(nei)
+                        q.append(nei)
+
+        return list(secrets)
+```
+
+```java
+public class Solution {
+    public List<Integer> findAllPeople(int n, int[][] meetings, int firstPerson) {
+        Set<Integer> secrets = new HashSet<>();
+        secrets.add(0);
+        secrets.add(firstPerson);
+        TreeMap<Integer, Map<Integer, List<Integer>>> time_map = new TreeMap<>();
+
+        for (int[] meet : meetings) {
+            int src = meet[0], dst = meet[1], t = meet[2];
+            time_map.putIfAbsent(t, new HashMap<>());
+            time_map.get(t).putIfAbsent(src, new ArrayList<>());
+            time_map.get(t).putIfAbsent(dst, new ArrayList<>());
+            time_map.get(t).get(src).add(dst);
+            time_map.get(t).get(dst).add(src);
+        }
+
+        for (int t : time_map.keySet()) {
+            Set<Integer> visit = new HashSet<>();
+            Queue<Integer> q = new LinkedList<>();
+
+            for (int src : time_map.get(t).keySet()) {
+                if (secrets.contains(src)) {
+                    q.offer(src);
+                    visit.add(src);
+                }
+            }
+
+            while (!q.isEmpty()) {
+                int node = q.poll();
+                secrets.add(node);
+                for (int nei : time_map.get(t).get(node)) {
+                    if (!visit.contains(nei)) {
+                        visit.add(nei);
+                        q.offer(nei);
+                    }
+                }
+            }
+        }
+
+        return new ArrayList<>(secrets);
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    vector<int> findAllPeople(int n, vector<vector<int>>& meetings, int firstPerson) {
+        unordered_set<int> secrets = {0, firstPerson};
+        map<int, unordered_map<int, vector<int>>> time_map;
+
+        for (auto& meet : meetings) {
+            int src = meet[0], dst = meet[1], t = meet[2];
+            time_map[t][src].push_back(dst);
+            time_map[t][dst].push_back(src);
+        }
+
+        for (auto& [t, adj] : time_map) {
+            unordered_set<int> visit;
+            queue<int> q;
+
+            for (auto& [src, _] : adj) {
+                if (secrets.count(src)) {
+                    q.push(src);
+                    visit.insert(src);
+                }
+            }
+
+            while (!q.empty()) {
+                int node = q.front();
+                q.pop();
+                secrets.insert(node);
+                for (int nei : adj[node]) {
+                    if (!visit.count(nei)) {
+                        visit.insert(nei);
+                        q.push(nei);
+                    }
+                }
+            }
+        }
+
+        return vector<int>(secrets.begin(), secrets.end());
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number} n
+     * @param {number[][]} meetings
+     * @param {number} firstPerson
+     * @return {number[]}
+     */
+    findAllPeople(n, meetings, firstPerson) {
+        const secrets = new Set([0, firstPerson]);
+        const time_map = new Map();
+
+        for (let [src, dst, t] of meetings) {
+            if (!time_map.has(t)) time_map.set(t, new Map());
+            if (!time_map.get(t).has(src)) time_map.get(t).set(src, []);
+            if (!time_map.get(t).has(dst)) time_map.get(t).set(dst, []);
+            time_map.get(t).get(src).push(dst);
+            time_map.get(t).get(dst).push(src);
+        }
+
+        for (let t of [...time_map.keys()].sort((a, b) => a - b)) {
+            let visit = new Set();
+            const q = new Queue();
+
+            for (let src of time_map.get(t).keys()) {
+                if (secrets.has(src)) {
+                    q.push(src);
+                    visit.add(src);
+                }
+            }
+
+            while (!q.isEmpty()) {
+                let node = q.pop();
+                secrets.add(node);
+                for (let nei of time_map.get(t).get(node)) {
+                    if (!visit.has(nei)) {
+                        visit.add(nei);
+                        q.push(nei);
+                    }
+                }
+            }
+        }
+
+        return [...secrets];
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(m \log m + n)$
+* Space complexity: $O(m + n)$
+
+> Where $m$ is the number of meetings and $n$ is the number of people.
+
+---
+
+## 3. Iterative DFS
+
+::tabs-start
+
+```python
+class Solution:
+    def findAllPeople(self, n: int, meetings: list[list[int]], firstPerson: int) -> list[int]:
+        meetings.sort(key=lambda x: x[2])  # Sort by time
+        secrets = [False] * n
+        secrets[0] = secrets[firstPerson] = True
+
+        for _, group in groupby(meetings, key=lambda x: x[2]):
+            adj = defaultdict(list)
+            visited = set()
+
+            for u, v, _ in group:
+                adj[u].append(v)
+                adj[v].append(u)
+                if secrets[u]:
+                    visited.add(u)
+                if secrets[v]:
+                    visited.add(v)
+
+            stack = list(visited)
+            while stack:
+                node = stack.pop()
+                for nei in adj[node]:
+                    if nei not in visited:
+                        visited.add(nei)
+                        stack.append(nei)
+                        secrets[nei] = True
+
+        return [i for i in range(n) if secrets[i]]
+```
+
+```java
+public class Solution {
+    public List<Integer> findAllPeople(int n, int[][] meetings, int firstPerson) {
+        Arrays.sort(meetings, Comparator.comparingInt(a -> a[2]));
+        boolean[] secrets = new boolean[n];
+        secrets[0] = secrets[firstPerson] = true;
+
+        int i = 0, m = meetings.length;
+        while (i < m) {
+            int time = meetings[i][2];
+            Map<Integer, List<Integer>> adj = new HashMap<>();
+            Set<Integer> visited = new HashSet<>();
+
+            while (i < m && meetings[i][2] == time) {
+                int u = meetings[i][0], v = meetings[i][1];
+                adj.computeIfAbsent(u, k -> new ArrayList<>()).add(v);
+                adj.computeIfAbsent(v, k -> new ArrayList<>()).add(u);
+                if (secrets[u]) visited.add(u);
+                if (secrets[v]) visited.add(v);
+                i++;
+            }
+
+            Stack<Integer> stack = new Stack<>();
+            stack.addAll(visited);
+            while (!stack.isEmpty()) {
+                int node = stack.pop();
+                for (int nei : adj.getOrDefault(node, Collections.emptyList())) {
+                    if (!visited.contains(nei)) {
+                        visited.add(nei);
+                        stack.push(nei);
+                        secrets[nei] = true;
+                    }
+                }
+            }
+        }
+
+        List<Integer> res = new ArrayList<>();
+        for (int j = 0; j < n; j++) {
+            if (secrets[j]) res.add(j);
+        }
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    vector<int> findAllPeople(int n, vector<vector<int>>& meetings, int firstPerson) {
+        sort(meetings.begin(), meetings.end(), [](auto& a, auto& b) {
+            return a[2] < b[2];
+        });
+
+        vector<bool> secrets(n, false);
+        secrets[0] = secrets[firstPerson] = true;
+
+        int i = 0, m = meetings.size();
+        while (i < m) {
+            int time = meetings[i][2];
+            unordered_map<int, vector<int>> adj;
+            unordered_set<int> visited;
+
+            while (i < m && meetings[i][2] == time) {
+                int u = meetings[i][0], v = meetings[i][1];
+                adj[u].push_back(v);
+                adj[v].push_back(u);
+                if (secrets[u]) visited.insert(u);
+                if (secrets[v]) visited.insert(v);
+                i++;
+            }
+
+            stack<int> stack(visited.begin(), visited.end());
+            while (!stack.empty()) {
+                int node = stack.top(); stack.pop();
+                for (int& nei : adj[node]) {
+                    if (!visited.count(nei)) {
+                        visited.insert(nei);
+                        stack.push(nei);
+                        secrets[nei] = true;
+                    }
+                }
+            }
+        }
+
+        vector<int> res;
+        for (int j = 0; j < n; j++) {
+            if (secrets[j]) res.push_back(j);
+        }
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number} n
+     * @param {number[][]} meetings
+     * @param {number} firstPerson
+     * @return {number[]}
+     */
+    findAllPeople(n, meetings, firstPerson) {
+        meetings.sort((a, b) => a[2] - b[2]);
+        const secrets = new Array(n).fill(false);
+        secrets[0] = secrets[firstPerson] = true;
+
+        let i = 0, m = meetings.length;
+        while (i < m) {
+            const time = meetings[i][2];
+            const adj = new Map();
+            const visited = new Set();
+
+            while (i < m && meetings[i][2] === time) {
+                const [u, v] = meetings[i];
+                if (!adj.has(u)) adj.set(u, []);
+                if (!adj.has(v)) adj.set(v, []);
+                adj.get(u).push(v);
+                adj.get(v).push(u);
+                if (secrets[u]) visited.add(u);
+                if (secrets[v]) visited.add(v);
+                i++;
+            }
+
+            const stack = [...visited];
+            while (stack.length) {
+                const node = stack.pop();
+                for (const nei of (adj.get(node) || [])) {
+                    if (!visited.has(nei)) {
+                        visited.add(nei);
+                        stack.push(nei);
+                        secrets[nei] = true;
+                    }
+                }
+            }
+        }
+
+        let res = [];
+        for (let i = 0; i < n; i++) {
+            if (secrets[i]) res.push(i);
+        }
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(m \log m + n)$
+* Space complexity: $O(m + n)$
+
+> Where $m$ is the number of meetings and $n$ is the number of people.
+
+---
+
+## 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]:
+            pu, pv = pv, pu
+        self.Size[pu] += self.Size[pv]
+        self.Parent[pv] = pu
+        return True
+
+    def reset(self, node):
+        self.Parent[node] = node
+        self.Size[node] = 1
+
+class Solution:
+    def findAllPeople(self, n: int, meetings: list[list[int]], firstPerson: int) -> list[int]:
+        meetings.sort(key=lambda x: x[2])  # Sort by time
+        dsu = DSU(n)
+        dsu.union(0, firstPerson)
+
+        for _, group in groupby(meetings, key=lambda x: x[2]):
+            group_nodes = set()
+            for u, v, _ in group:
+                dsu.union(u, v)
+                group_nodes.add(u)
+                group_nodes.add(v)
+
+            for node in group_nodes:
+                if dsu.find(node) != dsu.find(0):
+                    dsu.reset(node)
+
+        return [i for i in range(n) if dsu.find(i) == dsu.find(0)]
+```
+
+```java
+class DSU {
+    int[] Parent, Size;
+
+    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;
+        }
+    }
+
+    int find(int node) {
+        if (Parent[node] != node) {
+            Parent[node] = find(Parent[node]);
+        }
+        return Parent[node];
+    }
+
+    void union(int u, int v) {
+        int pu = find(u), pv = find(v);
+        if (pu == pv) return;
+        if (Size[pu] < Size[pv]) {
+            int temp = pu;
+            pu = pv;
+            pv = temp;
+        }
+        Size[pu] += Size[pv];
+        Parent[pv] = pu;
+    }
+
+    void reset(int node) {
+        Parent[node] = node;
+        Size[node] = 1;
+    }
+}
+
+public class Solution {
+    public List<Integer> findAllPeople(int n, int[][] meetings, int firstPerson) {
+        Arrays.sort(meetings, Comparator.comparingInt(a -> a[2]));
+        DSU dsu = new DSU(n);
+        dsu.union(0, firstPerson);
+
+        for (int i = 0; i < meetings.length; ) {
+            int time = meetings[i][2];
+            Set<Integer> group = new HashSet<>();
+
+            for (; i < meetings.length && meetings[i][2] == time; i++) {
+                int u = meetings[i][0], v = meetings[i][1];
+                dsu.union(u, v);
+                group.add(u);
+                group.add(v);
+            }
+
+            for (int node : group) {
+                if (dsu.find(node) != dsu.find(0)) {
+                    dsu.reset(node);
+                }
+            }
+        }
+
+        List<Integer> result = new ArrayList<>();
+        for (int i = 0; i < n; i++) {
+            if (dsu.find(i) == dsu.find(0)) result.add(i);
+        }
+        return result;
+    }
+}
+```
+
+```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];
+    }
+
+    void unionSets(int u, int v) {
+        int pu = find(u), pv = find(v);
+        if (pu == pv) return;
+        if (Size[pu] < Size[pv]) swap(pu, pv);
+        Size[pu] += Size[pv];
+        Parent[pv] = pu;
+    }
+
+    void reset(int node) {
+        Parent[node] = node;
+        Size[node] = 1;
+    }
+};
+
+class Solution {
+public:
+    vector<int> findAllPeople(int n, vector<vector<int>>& meetings, int firstPerson) {
+        sort(meetings.begin(), meetings.end(), [](auto &a, auto &b) {
+            return a[2] < b[2];
+        });
+        DSU dsu(n);
+        dsu.unionSets(0, firstPerson);
+
+        for (int i = 0; i < meetings.size(); ) {
+            int time = meetings[i][2];
+            unordered_set<int> group;
+
+            for (; i < meetings.size() && meetings[i][2] == time; i++) {
+                int u = meetings[i][0], v = meetings[i][1];
+                dsu.unionSets(u, v);
+                group.insert(u);
+                group.insert(v);
+            }
+
+            for (int node : group) {
+                if (dsu.find(node) != dsu.find(0)) {
+                    dsu.reset(node);
+                }
+            }
+        }
+
+        vector<int> result;
+        for (int i = 0; i < n; i++) {
+            if (dsu.find(i) == dsu.find(0)) result.push_back(i);
+        }
+        return result;
+    }
+};
+```
+
+```javascript
+class DSU {
+    /**
+     * @constructor
+     * @param {number} n
+     */
+    constructor(n) {
+        this.Parent = Array.from({ length: n + 1 }, (_, i) => i);
+        this.Size = 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} v
+     * @return {boolean}
+     */
+    union(u, v) {
+        let pu = this.find(u);
+        let 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;
+    }
+
+    /**
+     * @param {number} node
+     * @return {void}
+     */
+    reset(node) {
+        this.Parent[node] = node;
+        this.Size[node] = 1;
+    }
+}
+
+class Solution {
+    /**
+     * @param {number} n
+     * @param {number[][]} meetings
+     * @param {number} firstPerson
+     * @return {number[]}
+     */
+    findAllPeople(n, meetings, firstPerson) {
+        meetings.sort((a, b) => a[2] - b[2]);
+        let dsu = new DSU(n);
+        dsu.union(0, firstPerson);
+
+        for (let i = 0; i < meetings.length; ) {
+            let time = meetings[i][2];
+            let group = new Set();
+
+            for (; i < meetings.length && meetings[i][2] === time; i++) {
+                let [u, v] = meetings[i];
+                dsu.union(u, v);
+                group.add(u);
+                group.add(v);
+            }
+
+            group.forEach(node => {
+                if (dsu.find(node) !== dsu.find(0)) {
+                    dsu.reset(node);
+                }
+            });
+        }
+
+        return [...Array(n).keys()].filter(i => dsu.find(i) === dsu.find(0));
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(m \log m + (m * α(n)))$
+* Space complexity:
+    * $O(n)$ extra space.
+    * $O(m)$ space depending on the sorting algorithm.
+
+> Where $m$ is the number of meetings and $n$ is the number of people.
\ No newline at end of file
diff --git a/articles/minimum-number-of-days-to-eat-n-oranges.md b/articles/minimum-number-of-days-to-eat-n-oranges.md
index ca4acc077..115da181e 100644
--- a/articles/minimum-number-of-days-to-eat-n-oranges.md
+++ b/articles/minimum-number-of-days-to-eat-n-oranges.md
@@ -1,50 +1,98 @@
-## 1. Recursion
+## 1. Dynamic Programming (Top-Down)
 
 ::tabs-start
 
 ```python
-
+class Solution:
+    def minDays(self, n: int) -> int:
+        dp = {}
+
+        def dfs(n):
+            if n == 0:
+                return 0
+            if n in dp:
+                return dp[n]
+            
+            res = 1 + dfs(n - 1)
+            if n % 3 == 0:
+                res = min(res, 1 + dfs(n // 3))
+            if n % 2 == 0:
+                res = min(res, 1 + dfs(n // 2))
+
+            dp[n] = res
+            return res
+
+        return dfs(n)
 ```
 
 ```java
+public class Solution {
+    private Map<Integer, Integer> dp = new HashMap<>();
 
-```
-
-```cpp
+    public int minDays(int n) {
+        return dfs(n);
+    }
 
-```
+    private int dfs(int n) {
+        if (n == 0) return 0;
+        if (dp.containsKey(n)) return dp.get(n);
 
-```javascript
+        int res = 1 + dfs(n - 1);
+        if (n % 3 == 0) res = Math.min(res, 1 + dfs(n / 3));
+        if (n % 2 == 0) res = Math.min(res, 1 + dfs(n / 2));
 
+        dp.put(n, res);
+        return res;
+    }
+}
 ```
 
-::tabs-end
-
-### Time & Space Complexity
-
-* Time complexity: $O(2 ^ n)$
-* Space complexity: $O(n)$
-
----
-
-## 2. Dynamic Programming (Top-Down)
-
-::tabs-start
-
-```python
-
-```
+```cpp
+class Solution {
+public:
+    unordered_map<int, int> dp;
 
-```java
+    int minDays(int n) {
+        return dfs(n);
+    }
 
-```
+    int dfs(int n) {
+        if (n == 0) return 0;
+        if (dp.count(n)) return dp[n];
 
-```cpp
+        int res = 1 + dfs(n - 1);
+        if (n % 3 == 0) res = min(res, 1 + dfs(n / 3));
+        if (n % 2 == 0) res = min(res, 1 + dfs(n / 2));
 
+        return dp[n] = res;
+    }
+};
 ```
 
 ```javascript
-
+class Solution {
+    /**
+     * @param {number} n
+     * @return {number}
+     */
+    minDays(n) {
+        const dp = new Map();
+
+        const dfs = (n) => {
+            if (n === 0) return 0;
+            if (dp.has(n)) return dp.get(n);
+
+            let res = 1 + dfs(n - 1);
+            if (n % 3 === 0) res = Math.min(res, 1 + dfs(n / 3));
+            if (n % 2 === 0) res = Math.min(res, 1 + dfs(n / 2));
+
+            dp.set(n, res);
+            return res;
+        };
+
+        return dfs(n);
+    }
+}
 ```
 
 ::tabs-end
@@ -56,87 +104,251 @@
 
 ---
 
-## 3. Dynamic Programming (Bottom-Up)
+## 2. Greedy + Dynamic Programming (Top-Down)
 
 ::tabs-start
 
 ```python
+class Solution:
+    def minDays(self, n: int) -> int:
+        dp = {0: 0, 1: 1}
 
-```
-
-```java
-
-```
-
-```cpp
-
-```
+        def dfs(n):
+            if n in dp:
+                return dp[n]
 
-```javascript
+            res = 1 + (n % 2) + dfs(n // 2)
+            res = min(res, 1 + (n % 3) + dfs(n // 3))
+            dp[n] = res
+            return res
 
+        return dfs(n)
 ```
 
-::tabs-end
-
-### Time & Space Complexity
-
-* Time complexity: $O(n)$
-* Space complexity: $O(n)$
-
----
-
-## 4. Dynamic Programming (Space Optimized)
+```java
+public class Solution {
+    private Map<Integer, Integer> dp = new HashMap<>();
 
-::tabs-start
+    public int minDays(int n) {
+        dp.put(0, 0);
+        dp.put(1, 1);
+        return dfs(n);
+    }
 
-```python
+    private int dfs(int n) {
+        if (dp.containsKey(n)) return dp.get(n);
 
-```
-
-```java
+        int res = 1 + (n % 2) + dfs(n / 2);
+        res = Math.min(res, 1 + (n % 3) + dfs(n / 3));
 
+        dp.put(n, res);
+        return res;
+    }
+}
 ```
 
 ```cpp
-
+class Solution {
+public:
+    unordered_map<int, int> dp;
+
+    int minDays(int n) {
+        dp[0] = 0;
+        dp[1] = 1;
+        return dfs(n);
+    }
+
+private:
+    int dfs(int n) {
+        if (dp.count(n)) return dp[n];
+
+        int res = 1 + (n % 2) + dfs(n / 2);
+        res = min(res, 1 + (n % 3) + dfs(n / 3));
+
+        return dp[n] = res;
+    }
+};
 ```
 
 ```javascript
-
+class Solution {
+    /**
+     * @param {number} n
+     * @return {number}
+     */
+    minDays(n) {
+        const dp = new Map();
+        dp.set(0, 0);
+        dp.set(1, 1);
+
+        const dfs = (n) => {
+            if (dp.has(n)) return dp.get(n);
+
+            let res = 1 + (n % 2) + dfs(Math.floor(n / 2));
+            res = Math.min(res, 1 + (n % 3) + dfs(Math.floor(n / 3)));
+
+            dp.set(n, res);
+            return res;
+        };
+
+        return dfs(n);
+    }
+}
 ```
 
 ::tabs-end
 
 ### Time & Space Complexity
 
-* Time complexity: $O(n)$
-* Space complexity: $O(1)$
+* Time complexity: $O(\log n)$
+* Space complexity: $O(\log n)$
 
 ---
 
-## 5. Dynamic Programming (Optimal)
+## 3. Breadth First Search
 
 ::tabs-start
 
 ```python
-
+class Solution:
+    def minDays(self, n: int) -> int:
+        q = deque([n])
+        visit = set()
+        res = 0
+
+        while q:
+            res += 1
+            for _ in range(len(q)):
+                node = q.popleft()
+                nei = node - 1
+                if nei == 0:
+                    return res
+                if nei not in visit:
+                    visit.add(nei)
+                    q.append(nei)
+                for d in range(2, 4):
+                    if node % d == 0:
+                        nei = node // d
+                        if nei == 0:
+                            return res
+                        if nei not in visit:
+                            visit.add(nei)
+                            q.append(nei)
+        return res
 ```
 
 ```java
-
+public class Solution {
+    public int minDays(int n) {
+        Queue<Integer> q = new LinkedList<>();
+        Set<Integer> visit = new HashSet<>();
+        q.offer(n);
+        int res = 0;
+
+        while (!q.isEmpty()) {
+            res++;
+            for (int i = q.size(); i > 0; i--) {
+                int node = q.poll();
+                int nei = node - 1;
+                if (nei == 0) return res;
+                if (!visit.contains(nei)) {
+                    visit.add(nei);
+                    q.offer(nei);
+                }
+                for (int d = 2; d <= 3; d++) {
+                    if (node % d == 0) {
+                        nei = node / d;
+                        if (nei == 0) return res;
+                        if (!visit.contains(nei)) {
+                            visit.add(nei);
+                            q.offer(nei);
+                        }
+                    }
+                }
+            }
+        }
+        return res;
+    }
+}
 ```
 
 ```cpp
-
+class Solution {
+public:
+    int minDays(int n) {
+        queue<int> q;
+        unordered_set<int> visit;
+        q.push(n);
+        int res = 0;
+
+        while (!q.empty()) {
+            res++;
+            for (int i = q.size(); i > 0; i--) {
+                int node = q.front(); q.pop();
+                int nei = node - 1;
+                if (nei == 0) return res;
+                if (visit.find(nei) == visit.end()) {
+                    visit.insert(nei);
+                    q.push(nei);
+                }
+                for (int d = 2; d <= 3; d++) {
+                    if (node % d == 0) {
+                        nei = node / d;
+                        if (nei == 0) return res;
+                        if (visit.find(nei) == visit.end()) {
+                            visit.insert(nei);
+                            q.push(nei);
+                        }
+                    }
+                }
+            }
+        }
+        return res;
+    }
+};
 ```
 
 ```javascript
-
+class Solution {
+    /**
+     * @param {number} n
+     * @return {number}
+     */
+    minDays(n) {
+        const q = new Queue([n]);
+        const visit = new Set();
+        let res = 0;
+
+        while (!q.isEmpty()) {
+            res++;
+            for (let i = q.size(); i > 0; i--) {
+                let node = q.pop();
+                let nei = node - 1;
+                if (nei === 0) return res;
+                if (!visit.has(nei)) {
+                    visit.add(nei);
+                    q.push(nei);
+                }
+                for (let d = 2; d <= 3; d++) {
+                    if (node % d === 0) {
+                        nei = Math.floor(node / d);
+                        if (nei === 0) return res;
+                        if (!visit.has(nei)) {
+                            visit.add(nei);
+                            q.push(nei);
+                        }
+                    }
+                }
+            }
+        }
+        return res;
+    }
+}
 ```
 
 ::tabs-end
 
 ### Time & Space Complexity
 
-* Time complexity: $O(n)$
-* Space complexity: $O(1)$
\ No newline at end of file
+* Time complexity: $O(\log n)$
+* Space complexity: $O(\log n)$
\ No newline at end of file
diff --git a/articles/parallel-courses-iii.md b/articles/parallel-courses-iii.md
new file mode 100644
index 000000000..ca66a0769
--- /dev/null
+++ b/articles/parallel-courses-iii.md
@@ -0,0 +1,481 @@
+## 1. Depth First Search
+
+::tabs-start
+
+```python
+class Solution:
+    def minimumTime(self, n: int, relations: list[list[int]], time: list[int]) -> int:
+        adj = defaultdict(list)
+        for src, dst in relations:
+            adj[src].append(dst)
+
+        max_time = {}
+
+        def dfs(src):
+            if src in max_time:
+                return max_time[src]
+            res = time[src - 1]
+            for nei in adj[src]:
+                res = max(res, time[src - 1] + dfs(nei))
+            max_time[src] = res
+            return res
+
+        for i in range(1, n + 1):
+            dfs(i)
+
+        return max(max_time.values())
+```
+
+```java
+public class Solution {
+    private Map<Integer, Integer> maxTime;
+    private List<Integer>[] adj;
+    private int[] time;
+
+    public int minimumTime(int n, int[][] relations, int[] time) {
+        this.time = time;
+        this.maxTime = new HashMap<>();
+        this.adj = new ArrayList[n + 1];
+
+        for (int i = 1; i <= n; i++) {
+            adj[i] = new ArrayList<>();
+        }
+        for (int[] relation : relations) {
+            adj[relation[0]].add(relation[1]);
+        }
+
+        for (int i = 1; i <= n; i++) {
+            dfs(i);
+        }
+
+        return Collections.max(maxTime.values());
+    }
+
+    private int dfs(int src) {
+        if (maxTime.containsKey(src)) {
+            return maxTime.get(src);
+        }
+
+        int res = time[src - 1];
+        for (int nei : adj[src]) {
+            res = Math.max(res, time[src - 1] + dfs(nei));
+        }
+        maxTime.put(src, res);
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    unordered_map<int, int> maxTime;
+    vector<vector<int>> adj;
+    vector<int> time;
+
+    int minimumTime(int n, vector<vector<int>>& relations, vector<int>& time) {
+        this->time = time;
+        adj.resize(n + 1);
+
+        for (auto& relation : relations) {
+            adj[relation[0]].push_back(relation[1]);
+        }
+
+        for (int i = 1; i <= n; i++) {
+            dfs(i);
+        }
+
+        int res = 0;
+        for (auto& [key, value] : maxTime) {
+            res = max(res, value);
+        }
+        return res;
+    }
+
+private:
+    int dfs(int src) {
+        if (maxTime.count(src)) {
+            return maxTime[src];
+        }
+
+        int res = time[src - 1];
+        for (int nei : adj[src]) {
+            res = max(res, time[src - 1] + dfs(nei));
+        }
+        maxTime[src] = res;
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number} n
+     * @param {number[][]} relations
+     * @param {number[]} time
+     * @return {number}
+     */
+    minimumTime(n, relations, time) {
+        let adj = Array.from({ length: n + 1 }, () => []);
+        let maxTime = new Map();
+
+        for (let [src, dst] of relations) {
+            adj[src].push(dst);
+        }
+
+        const dfs = (src) => {
+            if (maxTime.has(src)) {
+                return maxTime.get(src);
+            }
+
+            let res = time[src - 1];
+            for (let nei of adj[src]) {
+                res = Math.max(res, time[src - 1] + dfs(nei));
+            }
+            maxTime.set(src, res);
+            return res;
+        };
+
+        for (let i = 1; i <= n; i++) {
+            dfs(i);
+        }
+
+        return Math.max(...maxTime.values());
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(V + E)$
+* Space complexity: $O(V + E)$
+
+> Where $V$ is the number of courses and $E$ is the number of prerequisites.
+
+---
+
+## 2. Iterative DFS
+
+::tabs-start
+
+```python
+class Solution:
+    def minimumTime(self, n: int, relations: list[list[int]], time: list[int]) -> int:
+        adj = [[] for _ in range(n)]
+        for src, dst in relations:
+            adj[src - 1].append(dst - 1)
+
+        maxTime = [-1] * n
+        processed = [False] * n
+
+        for i in range(n):
+            if maxTime[i] == -1:
+                stack = [i]
+                while stack:
+                    node = stack.pop()
+                    if processed[node]:
+                        best = 0
+                        for nei in adj[node]:
+                            best = max(best, maxTime[nei])
+                        maxTime[node] = time[node] + best
+                    else:
+                        processed[node] = True
+                        stack.append(node)
+                        for nei in adj[node]:
+                            if maxTime[nei] == -1:
+                                stack.append(nei)
+        return max(maxTime)
+```
+
+```java
+public class Solution {
+    public int minimumTime(int n, int[][] relations, int[] time) {
+        List<Integer>[] adj = new ArrayList[n];
+        for (int i = 0; i < n; i++) adj[i] = new ArrayList<>();
+        for (int[] rel : relations) {
+            adj[rel[0] - 1].add(rel[1] - 1);
+        }
+
+        int[] maxTime = new int[n];
+        Arrays.fill(maxTime, -1);
+        boolean[] processed = new boolean[n];
+
+        for (int i = 0; i < n; i++) {
+            if (maxTime[i] == -1) {
+                Stack<Integer> stack = new Stack<>();
+                stack.push(i);
+                while (!stack.isEmpty()) {
+                    int node = stack.pop();
+                    if (processed[node]) {
+                        int best = 0;
+                        for (int nei : adj[node]) {
+                            best = Math.max(best, maxTime[nei]);
+                        }
+                        maxTime[node] = time[node] + best;
+                    } else {
+                        processed[node] = true;
+                        stack.push(node);
+                        for (int nei : adj[node]) {
+                            if (maxTime[nei] == -1) {
+                                stack.push(nei);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return Arrays.stream(maxTime).max().getAsInt();
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int minimumTime(int n, vector<vector<int>>& relations, vector<int>& time) {
+        vector<vector<int>> adj(n);
+        for (auto& rel : relations) {
+            adj[rel[0] - 1].push_back(rel[1] - 1);
+        }
+
+        vector<int> maxTime(n, -1);
+        vector<bool> processed(n, false);
+
+        for (int i = 0; i < n; i++) {
+            if (maxTime[i] == -1) {
+                stack<int> stk;
+                stk.push(i);
+                while (!stk.empty()) {
+                    int node = stk.top(); stk.pop();
+                    if (processed[node]) {
+                        int best = 0;
+                        for (int nei : adj[node]) {
+                            best = max(best, maxTime[nei]);
+                        }
+                        maxTime[node] = time[node] + best;
+                    } else {
+                        processed[node] = true;
+                        stk.push(node);
+                        for (int nei : adj[node]) {
+                            if (maxTime[nei] == -1) {
+                                stk.push(nei);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return *max_element(maxTime.begin(), maxTime.end());
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number} n
+     * @param {number[][]} relations
+     * @param {number[]} time
+     * @return {number}
+     */
+    minimumTime(n, relations, time) {
+        let adj = Array.from({ length: n }, () => []);
+        for (let [src, dst] of relations) {
+            adj[src - 1].push(dst - 1);
+        }
+
+        let maxTime = Array(n).fill(-1);
+        let processed = Array(n).fill(false);
+
+        for (let i = 0; i < n; i++) {
+            if (maxTime[i] === -1) {
+                let stack = [i];
+                while (stack.length > 0) {
+                    let node = stack.pop();
+                    if (processed[node]) {
+                        let best = 0;
+                        for (let nei of adj[node]) {
+                            best = Math.max(best, maxTime[nei]);
+                        }
+                        maxTime[node] = time[node] + best;
+                    } else {
+                        processed[node] = true;
+                        stack.push(node);
+                        for (let nei of adj[node]) {
+                            if (maxTime[nei] === -1) {
+                                stack.push(nei);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return Math.max(...maxTime);
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(V + E)$
+* Space complexity: $O(V + E)$
+
+> Where $V$ is the number of courses and $E$ is the number of prerequisites.
+
+---
+
+## 3. Topological Sort (Kahn's Algorithm)
+
+::tabs-start
+
+```python
+class Solution:
+    def minimumTime(self, n: int, relations: list[list[int]], time: list[int]) -> int:
+        adj = [[] for _ in range(n)]
+        indegree = [0] * n
+        maxTime = time[:]
+
+        for src, dst in relations:
+            adj[src - 1].append(dst - 1)
+            indegree[dst - 1] += 1
+
+        queue = deque([i for i in range(n) if indegree[i] == 0])
+        while queue:
+            node = queue.popleft()
+            for nei in adj[node]:
+                maxTime[nei] = max(maxTime[nei], maxTime[node] + time[nei])
+                indegree[nei] -= 1
+                if indegree[nei] == 0:
+                    queue.append(nei)
+
+        return max(maxTime)
+```
+
+```java
+public class Solution {
+    public int minimumTime(int n, int[][] relations, int[] time) {
+        List<List<Integer>> adj = new ArrayList<>();
+        int[] indegree = new int[n];
+        int[] maxTime = Arrays.copyOf(time, n);
+
+        for (int i = 0; i < n; i++) {
+            adj.add(new ArrayList<>());
+        }
+
+        for (int[] relation : relations) {
+            int src = relation[0] - 1, dst = relation[1] - 1;
+            adj.get(src).add(dst);
+            indegree[dst]++;
+        }
+
+        Queue<Integer> queue = new LinkedList<>();
+        for (int i = 0; i < n; i++) {
+            if (indegree[i] == 0) {
+                queue.add(i);
+            }
+        }
+
+        while (!queue.isEmpty()) {
+            int node = queue.poll();
+            for (int nei : adj.get(node)) {
+                maxTime[nei] = Math.max(maxTime[nei], maxTime[node] + time[nei]);
+                if (--indegree[nei] == 0) {
+                    queue.add(nei);
+                }
+            }
+        }
+
+        return Arrays.stream(maxTime).max().getAsInt();
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int minimumTime(int n, vector<vector<int>>& relations, vector<int>& time) {
+        vector<vector<int>> adj(n);
+        vector<int> indegree(n, 0);
+        vector<int> maxTime(time.begin(), time.end());
+
+        for (auto& relation : relations) {
+            int src = relation[0] - 1, dst = relation[1] - 1;
+            adj[src].push_back(dst);
+            indegree[dst]++;
+        }
+
+        queue<int> queue;
+        for (int i = 0; i < n; i++) {
+            if (indegree[i] == 0) {
+                queue.push(i);
+            }
+        }
+
+        while (!queue.empty()) {
+            int node = queue.front(); queue.pop();
+            for (int nei : adj[node]) {
+                maxTime[nei] = max(maxTime[nei], maxTime[node] + time[nei]);
+                if (--indegree[nei] == 0) {
+                    queue.push(nei);
+                }
+            }
+        }
+
+        return *max_element(maxTime.begin(), maxTime.end());
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number} n
+     * @param {number[][]} relations
+     * @param {number[]} time
+     * @return {number}
+     */
+    minimumTime(n, relations, time) {
+        let adj = Array.from({ length: n }, () => []);
+        let indegree = Array(n).fill(0);
+        let maxTime = [...time];
+
+        for (let [src, dst] of relations) {
+            adj[src - 1].push(dst - 1);
+            indegree[dst - 1]++;
+        }
+
+        let queue = new Queue();
+        for (let i = 0; i < n; i++) {
+            if (indegree[i] === 0) {
+                queue.push(i);
+            }
+        }
+
+        while (!queue.isEmpty()) {
+            let node = queue.pop();
+            for (let nei of adj[node]) {
+                maxTime[nei] = Math.max(maxTime[nei], maxTime[node] + time[nei]);
+                if (--indegree[nei] === 0) {
+                    queue.push(nei);
+                }
+            }
+        }
+
+        return Math.max(...maxTime);
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(V + E)$
+* Space complexity: $O(V + E)$
+
+> Where $V$ is the number of courses and $E$ is the number of prerequisites.
\ No newline at end of file

From f011e900343efdb96fa98818af423719107eccfa Mon Sep 17 00:00:00 2001
From: Sri Hari <kataresrihari@gmail.com>
Date: Thu, 6 Feb 2025 17:54:58 +0530
Subject: [PATCH 03/13] Batch-5/Neetcode-ALL/Added-articles

---
 articles/all-possible-full-binary-trees.md  | 693 +++++++++++++++++
 articles/binary-search-tree-iterator.md     | 699 +++++++++++++++++
 articles/distribute-coins-in-binary-tree.md | 723 ++++++++++++++++++
 articles/operations-on-tree.md              | 806 ++++++++++++++++++++
 articles/rotate-list.md                     | 486 ++++++++++++
 5 files changed, 3407 insertions(+)
 create mode 100644 articles/all-possible-full-binary-trees.md
 create mode 100644 articles/binary-search-tree-iterator.md
 create mode 100644 articles/distribute-coins-in-binary-tree.md
 create mode 100644 articles/operations-on-tree.md
 create mode 100644 articles/rotate-list.md

diff --git a/articles/all-possible-full-binary-trees.md b/articles/all-possible-full-binary-trees.md
new file mode 100644
index 000000000..1e75b0293
--- /dev/null
+++ b/articles/all-possible-full-binary-trees.md
@@ -0,0 +1,693 @@
+## 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 allPossibleFBT(self, n: int) -> List[Optional[TreeNode]]:
+        def backtrack(n):
+            if n == 0:
+                return []
+            if n == 1:
+                return [TreeNode(0)]
+
+            res = []
+            for l in range(n):
+                r = n - 1 - l
+                leftTrees, rightTrees = backtrack(l), backtrack(r)
+
+                for t1 in leftTrees:
+                    for t2 in rightTrees:
+                        res.append(TreeNode(0, t1, t2))
+            return res
+
+        return backtrack(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> allPossibleFBT(int n) {
+        return backtrack(n);
+    }
+
+    private List<TreeNode> backtrack(int n) {
+        if (n == 0) {
+            return new ArrayList<>();
+        }
+        if (n == 1) {
+            return Arrays.asList(new TreeNode(0));
+        }
+
+        List<TreeNode> res = new ArrayList<>();
+        for (int l = 0; l < n; l++) {
+            int r = n - 1 - l;
+            List<TreeNode> leftTrees = backtrack(l);
+            List<TreeNode> rightTrees = backtrack(r);
+
+            for (TreeNode t1 : leftTrees) {
+                for (TreeNode t2 : rightTrees) {
+                    res.add(new TreeNode(0, t1, t2));
+                }
+            }
+        }
+        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*> allPossibleFBT(int n) {
+        return backtrack(n);
+    }
+
+private:
+    vector<TreeNode*> backtrack(int n) {
+        if (n == 0) {
+            return {};
+        }
+        if (n == 1) {
+            return {new TreeNode(0)};
+        }
+
+        vector<TreeNode*> res;
+        for (int l = 0; l < n; l++) {
+            int r = n - 1 - l;
+            vector<TreeNode*> leftTrees = backtrack(l);
+            vector<TreeNode*> rightTrees = backtrack(r);
+
+            for (auto& t1 : leftTrees) {
+                for (auto& t2 : rightTrees) {
+                    res.push_back(new TreeNode(0, t1, t2));
+                }
+            }
+        }
+        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[]}
+     */
+    allPossibleFBT(n) {
+        const backtrack = (n) => {
+            if (n === 0) {
+                return [];
+            }
+            if (n === 1) {
+                return [new TreeNode(0)];
+            }
+
+            let res = [];
+            for (let l = 0; l < n; l++) {
+                let r = n - 1 - l;
+                let leftTrees = backtrack(l);
+                let rightTrees = backtrack(r);
+
+                for (let t1 of leftTrees) {
+                    for (let t2 of rightTrees) {
+                        res.push(new TreeNode(0, t1, t2));
+                    }
+                }
+            }
+            return res;
+        };
+
+        return backtrack(n);
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(2 ^ n)$
+* Space complexity: $O(n * 2 ^ n)$
+
+---
+
+## 2. Recursion (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 allPossibleFBT(self, n: int) -> List[Optional[TreeNode]]:
+        if n % 2 == 0:
+            return []
+        if n == 1:
+            return [TreeNode(0)]
+
+        res = []
+        for left in range(1, n, 2):
+            leftSubTree = self.allPossibleFBT(left)
+            rightSubTree = self.allPossibleFBT(n - 1 - left)
+            for l in leftSubTree:
+                for r in rightSubTree:
+                    root = TreeNode(0, l, r)
+                    res.append(root)
+        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<TreeNode> allPossibleFBT(int n) {
+        if (n % 2 == 0) {
+            return new ArrayList<>();
+        }
+        if (n == 1) {
+            return Arrays.asList(new TreeNode(0));
+        }
+
+        List<TreeNode> res = new ArrayList<>();
+        for (int left = 1; left < n; left += 2) {
+            List<TreeNode> leftSubTree = allPossibleFBT(left);
+            List<TreeNode> rightSubTree = allPossibleFBT(n - 1 - left);
+            for (TreeNode l : leftSubTree) {
+                for (TreeNode r : rightSubTree) {
+                    TreeNode root = new TreeNode(0, l, r);
+                    res.add(root);
+                }
+            }
+        }
+        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*> allPossibleFBT(int n) {
+        if (n % 2 == 0) {
+            return {};
+        }
+        if (n == 1) {
+            return {new TreeNode(0)};
+        }
+
+        vector<TreeNode*> res;
+        for (int left = 1; left < n; left += 2) {
+            vector<TreeNode*> leftSubTree = allPossibleFBT(left);
+            vector<TreeNode*> rightSubTree = allPossibleFBT(n - 1 - left);
+            for (auto& l : leftSubTree) {
+                for (auto& r : rightSubTree) {
+                    TreeNode* root = new TreeNode(0, l, r);
+                    res.push_back(root);
+                }
+            }
+        }
+        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[]}
+     */
+    allPossibleFBT(n) {
+        if (n % 2 === 0) {
+            return [];
+        }
+        if (n === 1) {
+            return [new TreeNode(0)];
+        }
+
+        let res = [];
+        for (let left = 1; left < n; left += 2) {
+            let leftSubTree = this.allPossibleFBT(left);
+            let rightSubTree = this.allPossibleFBT(n - 1 - left);
+            for (let l of leftSubTree) {
+                for (let r of rightSubTree) {
+                    let root = new TreeNode(0, l, r);
+                    res.push(root);
+                }
+            }
+        }
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(2 ^ n)$
+* Space complexity: $O(n * 2 ^ n)$
+
+---
+
+## 3. 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 allPossibleFBT(self, n: int) -> List[Optional[TreeNode]]:
+        dp = {}
+
+        def dfs(n):
+            if n % 2 == 0:
+                return []
+            if n == 1:
+                return [TreeNode(0)]
+            if n in dp:
+                return dp[n]
+
+            res = []
+            for left in range(1, n, 2):
+                leftSubTree = dfs(left)
+                rightSubTree = dfs(n - 1 - left)
+                for l in leftSubTree:
+                    for r in rightSubTree:
+                        res.append(TreeNode(0, l, r))
+
+            dp[n] = res
+            return res
+        
+        return dfs(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> allPossibleFBT(int n) {
+        dp = new ArrayList[n + 1];
+        return dfs(n);
+    }
+
+    private List<TreeNode> dfs(int n) {
+        if (n % 2 == 0) {
+            return new ArrayList<>();
+        }
+        if (n == 1) {
+            return Arrays.asList(new TreeNode(0));
+        }
+        if (dp[n] != null) {
+            return dp[n];
+        }
+
+        List<TreeNode> res = new ArrayList<>();
+        for (int left = 1; left < n; left += 2) {
+            List<TreeNode> leftSubTree = dfs(left);
+            List<TreeNode> rightSubTree = dfs(n - 1 - left);
+            for (TreeNode l : leftSubTree) {
+                for (TreeNode r : rightSubTree) {
+                    res.add(new TreeNode(0, l, r));
+                }
+            }
+        }
+
+        return dp[n] = 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 {
+private:
+    vector<vector<TreeNode*>> dp;
+
+public:
+    vector<TreeNode*> allPossibleFBT(int n) {
+        dp.resize(n + 1);
+        return dfs(n);
+    }
+
+    vector<TreeNode*> dfs(int n) {
+        if (n % 2 == 0) {
+            return {};
+        }
+        if (n == 1) {
+            return {new TreeNode(0)};
+        }
+        if (!dp[n].empty()) {
+            return dp[n];
+        }
+
+        vector<TreeNode*> res;
+        for (int left = 1; left < n; left += 2) {
+            vector<TreeNode*> leftSubTree = dfs(left);
+            vector<TreeNode*> rightSubTree = dfs(n - 1 - left);
+            for (auto& l : leftSubTree) {
+                for (auto& r : rightSubTree) {
+                    res.push_back(new TreeNode(0, l, r));
+                }
+            }
+        }
+
+        return dp[n] = 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[]}
+     */
+    allPossibleFBT(n) {
+        let dp = new Array(n + 1);
+
+        const dfs = (n) => {
+            if (n % 2 === 0) {
+                return [];
+            }
+            if (n === 1) {
+                return [new TreeNode(0)];
+            }
+            if (dp[n]) {
+                return dp[n];
+            }
+
+            let res = [];
+            for (let left = 1; left < n; left += 2) {
+                let leftSubTree = dfs(left);
+                let rightSubTree = dfs(n - 1 - left);
+                for (let t1 of leftSubTree) {
+                    for (let t2 of rightSubTree) {
+                        res.push(new TreeNode(0, t1, t2));
+                    }
+                }
+            }
+
+            return (dp[n] = res);
+        };
+
+        return dfs(n);
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(2 ^ n)$
+* Space complexity: $O(n * 2 ^ n)$
+
+---
+
+## 4. 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 allPossibleFBT(self, n: int) -> List[Optional[TreeNode]]:
+        if n % 2 == 0:
+            return []
+        
+        dp = [[] for _ in range(n + 1)]
+        dp[1] = [TreeNode(0)]
+
+        for nodes in range(3, n + 1, 2):
+            res = []
+            for left in range(1, nodes, 2):
+                right = nodes - 1 - left
+                for t1 in dp[left]:
+                    for t2 in dp[right]:
+                        res.append(TreeNode(0, t1, t2))
+            dp[nodes] = res
+
+        return dp[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> allPossibleFBT(int n) {
+        if (n % 2 == 0) {
+            return new ArrayList<>();
+        }
+
+        List<TreeNode>[] dp = new ArrayList[n + 1];
+        for (int i = 0; i <= n; i++) {
+            dp[i] = new ArrayList<>();
+        }
+        dp[1].add(new TreeNode(0));
+
+        for (int nodes = 3; nodes <= n; nodes += 2) {
+            List<TreeNode> res = new ArrayList<>();
+            for (int left = 1; left < nodes; left += 2) {
+                int right = nodes - 1 - left;
+                for (TreeNode t1 : dp[left]) {
+                    for (TreeNode t2 : dp[right]) {
+                        res.add(new TreeNode(0, t1, t2));
+                    }
+                }
+            }
+            dp[nodes] = res;
+        }
+
+        return dp[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*> allPossibleFBT(int n) {
+        if (n % 2 == 0) {
+            return {};
+        }
+
+        vector<vector<TreeNode*>> dp(n + 1);
+        dp[1].push_back(new TreeNode(0));
+
+        for (int nodes = 3; nodes <= n; nodes += 2) {
+            vector<TreeNode*> res;
+            for (int left = 1; left < nodes; left += 2) {
+                int right = nodes - 1 - left;
+                for (auto& t1 : dp[left]) {
+                    for (auto& t2 : dp[right]) {
+                        res.push_back(new TreeNode(0, t1, t2));
+                    }
+                }
+            }
+            dp[nodes] = res;
+        }
+
+        return dp[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[]}
+     */
+    allPossibleFBT(n) {
+        if (n % 2 === 0) {
+            return [];
+        }
+
+        let dp = Array.from({ length: n + 1 }, () => []);
+        dp[1] = [new TreeNode(0)];
+
+        for (let nodes = 3; nodes <= n; nodes += 2) {
+            let res = [];
+            for (let left = 1; left < nodes; left += 2) {
+                let right = nodes - 1 - left;
+                for (let t1 of dp[left]) {
+                    for (let t2 of dp[right]) {
+                        res.push(new TreeNode(0, t1, t2));
+                    }
+                }
+            }
+            dp[nodes] = res;
+        }
+
+        return dp[n];
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(2 ^ n)$
+* Space complexity: $O(n * 2 ^ n)$
\ No newline at end of file
diff --git a/articles/binary-search-tree-iterator.md b/articles/binary-search-tree-iterator.md
new file mode 100644
index 000000000..873698c70
--- /dev/null
+++ b/articles/binary-search-tree-iterator.md
@@ -0,0 +1,699 @@
+## 1. Flattening the BST (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 BSTIterator:
+
+    def __init__(self, root: Optional[TreeNode]):
+        self.arr = []
+        self.itr = 0
+
+        def dfs(node):
+            if not node:
+                return
+            dfs(node.left)
+            self.arr.append(node.val)
+            dfs(node.right)
+        
+        dfs(root)
+
+    def next(self) -> int:
+        val = self.arr[self.itr]
+        self.itr += 1
+        return val
+
+    def hasNext(self) -> bool:
+        return self.itr < len(self.arr)
+```
+
+```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 BSTIterator {
+    private List<Integer> arr;
+    private int itr;
+
+    public BSTIterator(TreeNode root) {
+        arr = new ArrayList<>();
+        itr = 0;
+        dfs(root);
+    }
+
+    private void dfs(TreeNode node) {
+        if (node == null) {
+            return;
+        }
+        dfs(node.left);
+        arr.add(node.val);
+        dfs(node.right);
+    }
+
+    public int next() {
+        return arr.get(itr++);
+    }
+
+    public boolean hasNext() {
+        return itr < arr.size();
+    }
+}
+```
+
+```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 BSTIterator {
+private:
+    vector<int> arr;
+    int itr;
+
+    void dfs(TreeNode* node) {
+        if (!node) {
+            return;
+        }
+        dfs(node->left);
+        arr.push_back(node->val);
+        dfs(node->right);
+    }
+
+public:
+    BSTIterator(TreeNode* root) {
+        itr = 0;
+        dfs(root);
+    }
+
+    int next() {
+        return arr[itr++];
+    }
+
+    bool hasNext() {
+        return itr < arr.size();
+    }
+};
+```
+
+```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 BSTIterator {
+    /**
+     * @constructor
+     * @param {TreeNode} root
+     */
+    constructor(root) {
+        this.arr = [];
+        this.itr = 0;
+
+        const dfs = (node) => {
+            if (!node) {
+                return;
+            }
+            dfs(node.left);
+            this.arr.push(node.val);
+            dfs(node.right);
+        };
+
+        dfs(root);
+    }
+
+    /**
+     * @return {number}
+     */
+    next() {
+        return this.arr[this.itr++];
+    }
+
+    /**
+     * @return {boolean}
+     */
+    hasNext() {
+        return this.itr < this.arr.length;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity:
+    * $O(n)$ time for initialization.
+    * $O(n)$ time for each $next()$ and $hasNext()$ function calls.
+* Space complexity: $O(n)$
+
+---
+
+## 2. Flatten the BST (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 BSTIterator:
+
+    def __init__(self, root: Optional[TreeNode]):
+        self.arr = []
+        self.itr = 0
+
+        stack = []
+        while root or stack:
+            while root:
+                stack.append(root)
+                root = root.left
+            root = stack.pop()
+            self.arr.append(root.val)
+            root = root.right
+
+    def next(self) -> int:
+        val = self.arr[self.itr]
+        self.itr += 1
+        return val
+
+    def hasNext(self) -> bool:
+        return self.itr < len(self.arr)
+```
+
+```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 BSTIterator {
+    private List<Integer> arr;
+    private int itr;
+
+    public BSTIterator(TreeNode root) {
+        arr = new ArrayList<>();
+        itr = 0;
+        Stack<TreeNode> stack = new Stack<>();
+        while (root != null || !stack.isEmpty()) {
+            while (root != null) {
+                stack.push(root);
+                root = root.left;
+            }
+            root = stack.pop();
+            arr.add(root.val);
+            root = root.right;
+        }
+    }
+
+    public int next() {
+        return arr.get(itr++);
+    }
+
+    public boolean hasNext() {
+        return itr < arr.size();
+    }
+}
+```
+
+```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 BSTIterator {
+private:
+    vector<int> arr;
+    int itr;
+
+public:
+    BSTIterator(TreeNode* root) {
+        itr = 0;
+        stack<TreeNode*> stack;
+        while (root || !stack.empty()) {
+            while (root) {
+                stack.push(root);
+                root = root->left;
+            }
+            root = stack.top();
+            stack.pop();
+            arr.push_back(root->val);
+            root = root->right;
+        }
+    }
+
+    int next() {
+        return arr[itr++];
+    }
+
+    bool hasNext() {
+        return itr < arr.size();
+    }
+};
+```
+
+```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 BSTIterator {
+    /**
+     * @constructor
+     * @param {TreeNode} root
+     */
+    constructor(root) {
+        this.arr = [];
+        this.itr = 0;
+
+        let stack = [];
+        while (root || stack.length) {
+            while (root) {
+                stack.push(root);
+                root = root.left;
+            }
+            root = stack.pop();
+            this.arr.push(root.val);
+            root = root.right;
+        }
+    }
+
+    /**
+     * @return {number}
+     */
+    next() {
+        return this.arr[this.itr++];
+    }
+
+    /**
+     * @return {boolean}
+     */
+    hasNext() {
+        return this.itr < this.arr.length;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity:
+    * $O(n)$ time for initialization.
+    * $O(n)$ time for each $next()$ and $hasNext()$ function calls.
+* Space complexity: $O(n)$
+
+---
+
+## 3. Iterative DFS - I
+
+::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 BSTIterator:
+
+    def __init__(self, root: Optional[TreeNode]):
+        self.stack = []
+        while root:
+            self.stack.append(root)
+            root = root.left
+
+    def next(self) -> int:
+        res = self.stack.pop()
+        cur = res.right
+        while cur:
+            self.stack.append(cur)
+            cur = cur.left
+        return res.val
+
+    def hasNext(self) -> bool:
+        return bool(self.stack)
+```
+
+```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 BSTIterator {
+    private Stack<TreeNode> stack;
+
+    public BSTIterator(TreeNode root) {
+        stack = new Stack<>();
+        while (root != null) {
+            stack.push(root);
+            root = root.left;
+        }
+    }
+
+    public int next() {
+        TreeNode res = stack.pop();
+        TreeNode cur = res.right;
+        while (cur != null) {
+            stack.push(cur);
+            cur = cur.left;
+        }
+        return res.val;
+    }
+
+    public boolean hasNext() {
+        return !stack.isEmpty();
+    }
+}
+```
+
+```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 BSTIterator {
+private:
+    stack<TreeNode*> stack;
+
+public:
+    BSTIterator(TreeNode* root) {
+        while (root) {
+            stack.push(root);
+            root = root->left;
+        }
+    }
+
+    int next() {
+        TreeNode* res = stack.top();
+        stack.pop();
+        TreeNode* cur = res->right;
+        while (cur) {
+            stack.push(cur);
+            cur = cur->left;
+        }
+        return res->val;
+    }
+
+    bool hasNext() {
+        return !stack.empty();
+    }
+};
+```
+
+```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 BSTIterator {
+    /**
+     * @constructor
+     * @param {TreeNode} root
+     */
+    constructor(root) {
+        this.stack = [];
+        while (root) {
+            this.stack.push(root);
+            root = root.left;
+        }
+    }
+
+    /**
+     * @return {number}
+     */
+    next() {
+        let res = this.stack.pop();
+        let cur = res.right;
+        while (cur) {
+            this.stack.push(cur);
+            cur = cur.left;
+        }
+        return res.val;
+    }
+
+    /**
+     * @return {boolean}
+     */
+    hasNext() {
+        return this.stack.length > 0;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(1)$ in average for each function call.
+* Space complexity: $O(h)$
+
+> Where $n$ is the number of nodes and $h$ is the height of the given tree.
+
+---
+
+## 4. Iterative DFS - II
+
+::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 BSTIterator:
+
+    def __init__(self, root: Optional[TreeNode]):
+        self.cur = root
+        self.stack = []
+
+    def next(self) -> int:
+        while self.cur:
+            self.stack.append(self.cur)
+            self.cur = self.cur.left
+        
+        node = self.stack.pop()
+        self.cur = node.right
+        return node.val
+
+    def hasNext(self) -> bool:
+        return bool(self.cur) or bool(self.stack)
+```
+
+```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 BSTIterator {
+    private TreeNode cur;
+    private Stack<TreeNode> stack;
+
+    public BSTIterator(TreeNode root) {
+        cur = root;
+        stack = new Stack<>();
+    }
+
+    public int next() {
+        while (cur != null) {
+            stack.push(cur);
+            cur = cur.left;
+        }
+        
+        TreeNode node = stack.pop();
+        cur = node.right;
+        return node.val;
+    }
+
+    public boolean hasNext() {
+        return cur != null || !stack.isEmpty();
+    }
+}
+```
+
+```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 BSTIterator {
+private:
+    TreeNode* cur;
+    stack<TreeNode*> stack;
+
+public:
+    BSTIterator(TreeNode* root) {
+        cur = root;
+    }
+
+    int next() {
+        while (cur) {
+            stack.push(cur);
+            cur = cur->left;
+        }
+        
+        TreeNode* node = stack.top();
+        stack.pop();
+        cur = node->right;
+        return node->val;
+    }
+
+    bool hasNext() {
+        return cur || !stack.empty();
+    }
+};
+```
+
+```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 BSTIterator {
+    /**
+     * @constructor
+     * @param {TreeNode} root
+     */
+    constructor(root) {
+        this.cur = root;
+        this.stack = [];
+    }
+
+    /**
+     * @return {number}
+     */
+    next() {
+        while (this.cur) {
+            this.stack.push(this.cur);
+            this.cur = this.cur.left;
+        }
+
+        let node = this.stack.pop();
+        this.cur = node.right;
+        return node.val;
+    }
+
+    /**
+     * @return {boolean}
+     */
+    hasNext() {
+        return this.cur !== null || this.stack.length > 0;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(1)$ in average for each function call.
+* 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/distribute-coins-in-binary-tree.md b/articles/distribute-coins-in-binary-tree.md
new file mode 100644
index 000000000..4e26d25e9
--- /dev/null
+++ b/articles/distribute-coins-in-binary-tree.md
@@ -0,0 +1,723 @@
+## 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 distributeCoins(self, root: Optional[TreeNode]) -> int:
+        self.res = 0
+
+        def dfs(cur):
+            if not cur:
+                return [0, 0]  # [size, coins]
+
+            l_size, l_coins = dfs(cur.left)
+            r_size, r_coins = dfs(cur.right)
+
+            size = 1 + l_size + r_size
+            coins = cur.val + l_coins + r_coins
+            self.res += abs(size - coins)
+
+            return [size, coins]
+
+        dfs(root)
+        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 res;
+
+    public int distributeCoins(TreeNode root) {
+        res = 0;
+        dfs(root);
+        return res;
+    }
+
+    private int[] dfs(TreeNode cur) {
+        if (cur == null) {
+            return new int[]{0, 0}; // [size, coins]
+        }
+
+        int[] left = dfs(cur.left);
+        int[] right = dfs(cur.right);
+
+        int size = 1 + left[0] + right[0];
+        int coins = cur.val + left[1] + right[1];
+        res += Math.abs(size - coins);
+
+        return new int[]{size, coins};
+    }
+}
+```
+
+```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 {
+private:
+    int res;
+
+    vector<int> dfs(TreeNode* cur) {
+        if (!cur) {
+            return {0, 0}; // [size, coins]
+        }
+
+        vector<int> left = dfs(cur->left);
+        vector<int> right = dfs(cur->right);
+
+        int size = 1 + left[0] + right[0];
+        int coins = cur->val + left[1] + right[1];
+        res += abs(size - coins);
+
+        return {size, coins};
+    }
+
+public:
+    int distributeCoins(TreeNode* root) {
+        res = 0;
+        dfs(root);
+        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}
+     */
+    distributeCoins(root) {
+        let res = 0;
+
+        const dfs = (cur) => {
+            if (!cur) {
+                return [0, 0]; // [size, coins]
+            }
+
+            let [lSize, lCoins] = dfs(cur.left);
+            let [rSize, rCoins] = dfs(cur.right);
+
+            let size = 1 + lSize + rSize;
+            let coins = cur.val + lCoins + rCoins;
+            res += Math.abs(size - coins);
+
+            return [size, coins];
+        };
+
+        dfs(root);
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(n)$ for recursion stack.
+
+---
+
+## 2. Depth First Search (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 distributeCoins(self, root: Optional[TreeNode]) -> int:
+        self.res = 0
+
+        def dfs(cur):
+            if not cur:
+                return 0  # extra_coins
+
+            l_extra = dfs(cur.left)
+            r_extra = dfs(cur.right)
+
+            extra_coins = cur.val - 1 + l_extra + r_extra
+            self.res += abs(extra_coins)
+            return extra_coins
+
+        dfs(root)
+        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 res;
+
+    public int distributeCoins(TreeNode root) {
+        res = 0;
+        dfs(root);
+        return res;
+    }
+
+    private int dfs(TreeNode cur) {
+        if (cur == null) {
+            return 0; // extra_coins
+        }
+
+        int lExtra = dfs(cur.left);
+        int rExtra = dfs(cur.right);
+
+        int extraCoins = cur.val - 1 + lExtra + rExtra;
+        res += Math.abs(extraCoins);
+        return extraCoins;
+    }
+}
+```
+
+```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 {
+private:
+    int res;
+
+    int dfs(TreeNode* cur) {
+        if (!cur) {
+            return 0; // extra_coins
+        }
+
+        int lExtra = dfs(cur->left);
+        int rExtra = dfs(cur->right);
+
+        int extraCoins = cur->val - 1 + lExtra + rExtra;
+        res += abs(extraCoins);
+        return extraCoins;
+    }
+
+public:
+    int distributeCoins(TreeNode* root) {
+        res = 0;
+        dfs(root);
+        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}
+     */
+    distributeCoins(root) {
+        let res = 0;
+
+        const dfs = (cur) => {
+            if (!cur) {
+                return 0; // extra_coins
+            }
+
+            let lExtra = dfs(cur.left);
+            let rExtra = dfs(cur.right);
+
+            let extraCoins = cur.val - 1 + lExtra + rExtra;
+            res += Math.abs(extraCoins);
+            return extraCoins;
+        };
+
+        dfs(root);
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(n)$ fo recursion stack.
+
+---
+
+## 3. 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 distributeCoins(self, root: Optional[TreeNode]) -> int:
+        res = 0
+        q = deque([root])
+        parent_map = {}
+
+        nodes = []
+        while q:
+            node = q.popleft()
+            nodes.append(node)
+            if node.left:
+                parent_map[node.left] = node
+                q.append(node.left)
+            if node.right:
+                parent_map[node.right] = node
+                q.append(node.right)
+
+        while nodes:
+            node = nodes.pop()
+            if node in parent_map:
+                parent = parent_map[node]
+                parent.val += node.val - 1
+                res += abs(node.val - 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 distributeCoins(TreeNode root) {
+        int res = 0;
+        Queue<TreeNode> q = new LinkedList<>();
+        Map<TreeNode, TreeNode> parentMap = new HashMap<>();
+        List<TreeNode> nodes = new ArrayList<>();
+
+        q.offer(root);
+        while (!q.isEmpty()) {
+            TreeNode node = q.poll();
+            nodes.add(node);
+            if (node.left != null) {
+                parentMap.put(node.left, node);
+                q.offer(node.left);
+            }
+            if (node.right != null) {
+                parentMap.put(node.right, node);
+                q.offer(node.right);
+            }
+        }
+
+        for (int i = nodes.size() - 1; i >= 0; i--) {
+            TreeNode node = nodes.get(i);
+            if (parentMap.containsKey(node)) {
+                TreeNode parent = parentMap.get(node);
+                parent.val += node.val - 1;
+                res += Math.abs(node.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 distributeCoins(TreeNode* root) {
+        int res = 0;
+        queue<TreeNode*> q;
+        unordered_map<TreeNode*, TreeNode*> parentMap;
+        vector<TreeNode*> nodes;
+
+        q.push(root);
+        while (!q.empty()) {
+            TreeNode* node = q.front();
+            q.pop();
+            nodes.push_back(node);
+            if (node->left) {
+                parentMap[node->left] = node;
+                q.push(node->left);
+            }
+            if (node->right) {
+                parentMap[node->right] = node;
+                q.push(node->right);
+            }
+        }
+
+        for (int i = nodes.size() - 1; i >= 0; i--) {
+            TreeNode* node = nodes[i];
+            if (parentMap.count(node)) {
+                TreeNode* parent = parentMap[node];
+                parent->val += node->val - 1;
+                res += abs(node->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}
+     */
+    distributeCoins(root) {
+        let res = 0;
+        let q = new Queue();
+        let parentMap = new Map();
+        let nodes = [];
+
+        q.push(root);
+        while (!q.isEmpty()) {
+            let node = q.pop();
+            nodes.push(node);
+            if (node.left) {
+                parentMap.set(node.left, node);
+                q.push(node.left);
+            }
+            if (node.right) {
+                parentMap.set(node.right, node);
+                q.push(node.right);
+            }
+        }
+
+        for (let i = nodes.length - 1; i >= 0; i--) {
+            let node = nodes[i];
+            if (parentMap.has(node)) {
+                let parent = parentMap.get(node);
+                parent.val += node.val - 1;
+                res += Math.abs(node.val - 1);
+            }
+        }
+
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(n)$
+
+---
+
+## 4. 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 distributeCoins(self, root: Optional[TreeNode]) -> int:
+        stack = [root]
+        res = 0
+        visit = set()
+
+        while stack:
+            node = stack.pop()
+
+            if node not in visit:
+                stack.append(node)
+                visit.add(node)
+
+                if node.right:
+                    stack.append(node.right)
+                if node.left:
+                    stack.append(node.left)
+            else:
+                if node.left:
+                    node.val += node.left.val
+                if node.right:
+                    node.val += node.right.val
+
+                node.val -= 1
+                res += abs(node.val)
+                visit.remove(node)
+
+        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 distributeCoins(TreeNode root) {
+        Stack<TreeNode> stack = new Stack<>();
+        Set<TreeNode> visit = new HashSet<>();
+        stack.push(root);
+        int res = 0;
+
+        while (!stack.isEmpty()) {
+            TreeNode node = stack.pop();
+
+            if (!visit.contains(node)) {
+                stack.push(node);
+                visit.add(node);
+
+                if (node.right != null) {
+                    stack.push(node.right);
+                }
+                if (node.left != null) {
+                    stack.push(node.left);
+                }
+            } else {
+                if (node.left != null) {
+                    node.val += node.left.val;
+                }
+                if (node.right != null) {
+                    node.val += node.right.val;
+                }
+
+                node.val -= 1;
+                res += Math.abs(node.val);
+                visit.remove(node);
+            }
+        }
+
+        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 distributeCoins(TreeNode* root) {
+        stack<TreeNode*> stack;
+        unordered_set<TreeNode*> visit;
+        stack.push(root);
+        int res = 0;
+
+        while (!stack.empty()) {
+            TreeNode* node = stack.top();
+            stack.pop();
+
+            if (visit.find(node) == visit.end()) {
+                stack.push(node);
+                visit.insert(node);
+
+                if (node->right) {
+                    stack.push(node->right);
+                }
+                if (node->left) {
+                    stack.push(node->left);
+                }
+            } else {
+                if (node->left) {
+                    node->val += node->left->val;
+                }
+                if (node->right) {
+                    node->val += node->right->val;
+                }
+
+                visit.erase(node);
+                node->val -= 1;
+                res += abs(node->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}
+     */
+    distributeCoins(root) {
+        let stack = [root];
+        let visit = new Set();
+        let res = 0;
+
+        while (stack.length) {
+            let node = stack.pop();
+
+            if (!visit.has(node)) {
+                stack.push(node);
+                visit.add(node);
+
+                if (node.right) {
+                    stack.push(node.right);
+                }
+                if (node.left) {
+                    stack.push(node.left);
+                }
+            } else {
+                if (node.left) {
+                    node.val += node.left.val;
+                }
+                if (node.right) {
+                    node.val += node.right.val;
+                }
+
+                visit.delete(node);
+                node.val -= 1;
+                res += Math.abs(node.val);
+            }
+        }
+
+        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/operations-on-tree.md b/articles/operations-on-tree.md
new file mode 100644
index 000000000..682f18874
--- /dev/null
+++ b/articles/operations-on-tree.md
@@ -0,0 +1,806 @@
+## 1. Depth First Search
+
+::tabs-start
+
+```python
+class LockingTree:
+
+    def __init__(self, parent: List[int]):
+        self.parent = parent
+        self.child = [[] for _ in range(len(parent))]
+        self.locked = [0] * len(parent)
+        for node in range(1, len(parent)):
+            self.child[parent[node]].append(node)
+
+    def lock(self, num: int, user: int) -> bool:
+        if self.locked[num]:
+            return False
+        self.locked[num] = user
+        return True
+
+    def unlock(self, num: int, user: int) -> bool:
+        if self.locked[num] != user:
+            return False
+        self.locked[num] = 0
+        return True
+
+    def upgrade(self, num: int, user: int) -> bool:
+        node = num
+        while node != -1:
+            if self.locked[node]:
+                return False
+            node = self.parent[node]
+
+        def dfs(node):
+            lockedCount = 0
+            if self.locked[node]:
+                lockedCount += 1
+                self.locked[node] = 0
+
+            for nei in self.child[node]:
+                lockedCount += dfs(nei)
+            return lockedCount
+
+        if dfs(num) > 0:
+            self.locked[num] = user
+            return True
+        return False
+```
+
+```java
+public class LockingTree {
+    private int[] parent;
+    private List<Integer>[] child;
+    private int[] locked;
+
+    public LockingTree(int[] parent) {
+        this.parent = parent;
+        int n = parent.length;
+        child = new ArrayList[n];
+        locked = new int[n];
+
+        for (int i = 0; i < n; i++) {
+            child[i] = new ArrayList<>();
+        }
+        for (int node = 1; node < n; node++) {
+            child[parent[node]].add(node);
+        }
+    }
+
+    public boolean lock(int num, int user) {
+        if (locked[num] != 0) {
+            return false;
+        }
+        locked[num] = user;
+        return true;
+    }
+
+    public boolean unlock(int num, int user) {
+        if (locked[num] != user) {
+            return false;
+        }
+        locked[num] = 0;
+        return true;
+    }
+
+    public boolean upgrade(int num, int user) {
+        int node = num;
+        while (node != -1) {
+            if (locked[node] != 0) {
+                return false;
+            }
+            node = parent[node];
+        }
+
+        int lockedCount = dfs(num);
+        if (lockedCount > 0) {
+            locked[num] = user;
+            return true;
+        }
+        return false;
+    }
+
+    private int dfs(int node) {
+        int lockedCount = 0;
+        if (locked[node] != 0) {
+            lockedCount++;
+            locked[node] = 0;
+        }
+        for (int nei : child[node]) {
+            lockedCount += dfs(nei);
+        }
+        return lockedCount;
+    }
+}
+```
+
+```cpp
+class LockingTree {
+private:
+    vector<int> parent;
+    vector<vector<int>> child;
+    vector<int> locked;
+
+public:
+    LockingTree(vector<int>& parent) : parent(parent), locked(parent.size()) {
+        int n = parent.size();
+        child.resize(n);
+        for (int node = 1; node < n; node++) {
+            child[parent[node]].push_back(node);
+        }
+    }
+
+    bool lock(int num, int user) {
+        if (locked[num]) {
+            return false;
+        }
+        locked[num] = user;
+        return true;
+    }
+
+    bool unlock(int num, int user) {
+        if (locked[num] != user) {
+            return false;
+        }
+        locked[num] = 0;
+        return true;
+    }
+
+    bool upgrade(int num, int user) {
+        int node = num;
+        while (node != -1) {
+            if (locked[node]) {
+                return false;
+            }
+            node = parent[node];
+        }
+
+        int lockedCount = dfs(num);
+        if (lockedCount > 0) {
+            locked[num] = user;
+            return true;
+        }
+        return false;
+    }
+
+private:
+    int dfs(int node) {
+        int lockedCount = 0;
+        if (locked[node]) {
+            lockedCount++;
+            locked[node] = 0;
+        }
+        for (int& nei : child[node]) {
+            lockedCount += dfs(nei);
+        }
+        return lockedCount;
+    }
+};
+```
+
+```javascript
+class LockingTree {
+    /**
+     * @constructor
+     * @param {number[]} parent
+     */
+    constructor(parent) {
+        this.parent = parent;
+        this.child = Array.from({ length: parent.length }, () => []);
+        this.locked = new Array(parent.length).fill(0);
+
+        for (let node = 1; node < parent.length; node++) {
+            this.child[parent[node]].push(node);
+        }
+    }
+
+    /** 
+     * @param {number} num 
+     * @param {number} user 
+     * @return {boolean} 
+     */
+    lock(num, user) {
+        if (this.locked[num] !== 0) {
+            return false;
+        }
+        this.locked[num] = user;
+        return true;
+    }
+
+    /** 
+     * @param {number} num
+     * @param {number} user
+     * @return {boolean}
+     */
+    unlock(num, user) {
+        if (this.locked[num] !== user) {
+            return false;
+        }
+        this.locked[num] = 0;
+        return true;
+    }
+
+    /** 
+     * @param {number} num
+     * @param {number} user 
+     * @return {boolean} 
+     */
+    upgrade(num, user) {
+        let node = num;
+        while (node !== -1) {
+            if (this.locked[node] !== 0) {
+                return false;
+            }
+            node = this.parent[node];
+        }
+
+        const dfs = (node) => {
+            let lockedCount = 0;
+            if (this.locked[node] !== 0) {
+                lockedCount++;
+                this.locked[node] = 0;
+            }
+            for (let nei of this.child[node]) {
+                lockedCount += dfs(nei);
+            }
+            return lockedCount;
+        };
+
+        if (dfs(num) > 0) {
+            this.locked[num] = user;
+            return true;
+        }
+        return false;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity:
+    * $O(n)$ time for initialization.
+    * $O(1)$ time for each $lock()$ and $unlock()$ function call.
+    * $O(n)$ time for each $upgrade()$ function call.
+* Space complexity: $O(n)$
+
+---
+
+## 2. Breadth First Search
+
+::tabs-start
+
+```python
+class LockingTree:
+
+    def __init__(self, parent: List[int]):
+        self.parent = parent
+        self.child = [[] for _ in range(len(parent))]
+        self.locked = [0] * len(parent)
+        for node in range(1, len(parent)):
+            self.child[parent[node]].append(node)
+
+    def lock(self, num: int, user: int) -> bool:
+        if self.locked[num]:
+            return False
+        self.locked[num] = user
+        return True
+
+    def unlock(self, num: int, user: int) -> bool:
+        if self.locked[num] != user:
+            return False
+        self.locked[num] = 0
+        return True
+
+    def upgrade(self, num: int, user: int) -> bool:
+        node = num
+        while node != -1:
+            if self.locked[node]:
+                return False
+            node = self.parent[node]
+
+        lockedCount, q = 0, deque([num])
+        while q:
+            node = q.popleft()
+            if self.locked[node]:
+                self.locked[node] = 0
+                lockedCount += 1
+            q.extend(self.child[node])
+
+        if lockedCount:
+            self.locked[num] = user
+            return True
+        return False
+```
+
+```java
+public class LockingTree {
+    private int[] parent;
+    private List<Integer>[] child;
+    private int[] locked;
+
+    public LockingTree(int[] parent) {
+        this.parent = parent;
+        int n = parent.length;
+        child = new ArrayList[n];
+        locked = new int[n];
+
+        for (int i = 0; i < n; i++) {
+            child[i] = new ArrayList<>();
+        }
+        for (int node = 1; node < n; node++) {
+            child[parent[node]].add(node);
+        }
+    }
+
+    public boolean lock(int num, int user) {
+        if (locked[num] != 0) {
+            return false;
+        }
+        locked[num] = user;
+        return true;
+    }
+
+    public boolean unlock(int num, int user) {
+        if (locked[num] != user) {
+            return false;
+        }
+        locked[num] = 0;
+        return true;
+    }
+
+    public boolean upgrade(int num, int user) {
+        int node = num;
+        while (node != -1) {
+            if (locked[node] != 0) {
+                return false;
+            }
+            node = parent[node];
+        }
+
+        int lockedCount = 0;
+        Queue<Integer> q = new LinkedList<>();
+        q.offer(num);
+
+        while (!q.isEmpty()) {
+            node = q.poll();
+            if (locked[node] != 0) {
+                locked[node] = 0;
+                lockedCount++;
+            }
+            q.addAll(child[node]);
+        }
+
+        if (lockedCount > 0) {
+            locked[num] = user;
+            return true;
+        }
+        return false;
+    }
+}
+```
+
+```cpp
+class LockingTree {
+private:
+    vector<int> parent;
+    vector<vector<int>> child;
+    vector<int> locked;
+
+public:
+    LockingTree(vector<int>& parent) : parent(parent), locked(parent.size()) {
+        int n = parent.size();
+        child.resize(n);
+        for (int node = 1; node < n; node++) {
+            child[parent[node]].push_back(node);
+        }
+    }
+
+    bool lock(int num, int user) {
+        if (locked[num]) {
+            return false;
+        }
+        locked[num] = user;
+        return true;
+    }
+
+    bool unlock(int num, int user) {
+        if (locked[num] != user) {
+            return false;
+        }
+        locked[num] = 0;
+        return true;
+    }
+
+    bool upgrade(int num, int user) {
+        int node = num;
+        while (node != -1) {
+            if (locked[node]) {
+                return false;
+            }
+            node = parent[node];
+        }
+
+        int lockedCount = 0;
+        queue<int> q;
+        q.push(num);
+
+        while (!q.empty()) {
+            node = q.front(); q.pop();
+            if (locked[node]) {
+                locked[node] = 0;
+                lockedCount++;
+            }
+            for (int nei : child[node]) {
+                q.push(nei);
+            }
+        }
+
+        if (lockedCount > 0) {
+            locked[num] = user;
+            return true;
+        }
+        return false;
+    }
+};
+```
+
+```javascript
+class LockingTree {
+    /**
+     * @constructor
+     * @param {number[]} parent
+     */
+    constructor(parent) {
+        this.parent = parent;
+        this.child = Array.from({ length: parent.length }, () => []);
+        this.locked = new Array(parent.length).fill(0);
+
+        for (let node = 1; node < parent.length; node++) {
+            this.child[parent[node]].push(node);
+        }
+    }
+
+    /** 
+     * @param {number} num 
+     * @param {number} user 
+     * @return {boolean} 
+     */
+    lock(num, user) {
+        if (this.locked[num] !== 0) {
+            return false;
+        }
+        this.locked[num] = user;
+        return true;
+    }
+
+    /** 
+     * @param {number} num
+     * @param {number} user
+     * @return {boolean}
+     */
+    unlock(num, user) {
+        if (this.locked[num] !== user) {
+            return false;
+        }
+        this.locked[num] = 0;
+        return true;
+    }
+
+    /** 
+     * @param {number} num
+     * @param {number} user 
+     * @return {boolean} 
+     */
+    upgrade(num, user) {
+        let node = num;
+        while (node !== -1) {
+            if (this.locked[node] !== 0) {
+                return false;
+            }
+            node = this.parent[node];
+        }
+
+        let lockedCount = 0;
+        const q = new Queue([num]);
+
+        while (!q.isEmpty()) {
+            node = q.pop();
+            if (this.locked[node]) {
+                this.locked[node] = 0;
+                lockedCount++;
+            }
+            for (let nei of this.child[node]) {
+                q.push(nei);
+            }
+        }
+
+        if (lockedCount > 0) {
+            this.locked[num] = user;
+            return true;
+        }
+        return false;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity:
+    * $O(n)$ time for initialization.
+    * $O(1)$ time for each $lock()$ and $unlock()$ function call.
+    * $O(n)$ time for each $upgrade()$ function call.
+* Space complexity: $O(n)$
+
+---
+
+## 3. Iterative DFS
+
+::tabs-start
+
+```python
+class LockingTree:
+
+    def __init__(self, parent: List[int]):
+        self.parent = parent
+        self.child = [[] for _ in range(len(parent))]
+        self.locked = [0] * len(parent)
+        for node in range(1, len(parent)):
+            self.child[parent[node]].append(node)
+
+    def lock(self, num: int, user: int) -> bool:
+        if self.locked[num]:
+            return False
+        self.locked[num] = user
+        return True
+
+    def unlock(self, num: int, user: int) -> bool:
+        if self.locked[num] != user:
+            return False
+        self.locked[num] = 0
+        return True
+
+    def upgrade(self, num: int, user: int) -> bool:
+        node = num
+        while node != -1:
+            if self.locked[node]:
+                return False
+            node = self.parent[node]
+
+        lockedCount, stack = 0, [num]
+        while stack:
+            node = stack.pop()
+            if self.locked[node]:
+                self.locked[node] = 0
+                lockedCount += 1
+            stack.extend(self.child[node])
+
+        if lockedCount:
+            self.locked[num] = user
+            return True
+        return False
+```
+
+```java
+public class LockingTree {
+    private int[] parent;
+    private List<Integer>[] child;
+    private int[] locked;
+
+    public LockingTree(int[] parent) {
+        this.parent = parent;
+        int n = parent.length;
+        child = new ArrayList[n];
+        locked = new int[n];
+
+        for (int i = 0; i < n; i++) {
+            child[i] = new ArrayList<>();
+        }
+        for (int node = 1; node < n; node++) {
+            child[parent[node]].add(node);
+        }
+    }
+
+    public boolean lock(int num, int user) {
+        if (locked[num] != 0) {
+            return false;
+        }
+        locked[num] = user;
+        return true;
+    }
+
+    public boolean unlock(int num, int user) {
+        if (locked[num] != user) {
+            return false;
+        }
+        locked[num] = 0;
+        return true;
+    }
+
+    public boolean upgrade(int num, int user) {
+        int node = num;
+        while (node != -1) {
+            if (locked[node] != 0) {
+                return false;
+            }
+            node = parent[node];
+        }
+
+        int lockedCount = 0;
+        Stack<Integer> stack = new Stack<>();
+        stack.push(num);
+
+        while (!stack.isEmpty()) {
+            node = stack.pop();
+            if (locked[node] != 0) {
+                locked[node] = 0;
+                lockedCount++;
+            }
+            for (int nei : child[node]) {
+                stack.push(nei);
+            }
+        }
+
+        if (lockedCount > 0) {
+            locked[num] = user;
+            return true;
+        }
+        return false;
+    }
+}
+```
+
+```cpp
+class LockingTree {
+private:
+    vector<int> parent;
+    vector<vector<int>> child;
+    vector<int> locked;
+
+public:
+    LockingTree(vector<int>& parent) : parent(parent), locked(parent.size()) {
+        int n = parent.size();
+        child.resize(n);
+        for (int node = 1; node < n; node++) {
+            child[parent[node]].push_back(node);
+        }
+    }
+
+    bool lock(int num, int user) {
+        if (locked[num]) {
+            return false;
+        }
+        locked[num] = user;
+        return true;
+    }
+
+    bool unlock(int num, int user) {
+        if (locked[num] != user) {
+            return false;
+        }
+        locked[num] = 0;
+        return true;
+    }
+
+    bool upgrade(int num, int user) {
+        int node = num;
+        while (node != -1) {
+            if (locked[node]) {
+                return false;
+            }
+            node = parent[node];
+        }
+
+        int lockedCount = 0;
+        stack<int> stk;
+        stk.push(num);
+
+        while (!stk.empty()) {
+            node = stk.top(); stk.pop();
+            if (locked[node]) {
+                locked[node] = 0;
+                lockedCount++;
+            }
+            for (int& nei : child[node]) {
+                stk.push(nei);
+            }
+        }
+
+        if (lockedCount > 0) {
+            locked[num] = user;
+            return true;
+        }
+        return false;
+    }
+};
+```
+
+```javascript
+class LockingTree {
+    /**
+     * @constructor
+     * @param {number[]} parent
+     */
+    constructor(parent) {
+        this.parent = parent;
+        this.child = Array.from({ length: parent.length }, () => []);
+        this.locked = new Array(parent.length).fill(0);
+
+        for (let node = 1; node < parent.length; node++) {
+            this.child[parent[node]].push(node);
+        }
+    }
+
+    /** 
+     * @param {number} num 
+     * @param {number} user 
+     * @return {boolean} 
+     */
+    lock(num, user) {
+        if (this.locked[num] !== 0) {
+            return false;
+        }
+        this.locked[num] = user;
+        return true;
+    }
+
+    /** 
+     * @param {number} num
+     * @param {number} user
+     * @return {boolean}
+     */
+    unlock(num, user) {
+        if (this.locked[num] !== user) {
+            return false;
+        }
+        this.locked[num] = 0;
+        return true;
+    }
+
+    /** 
+     * @param {number} num
+     * @param {number} user 
+     * @return {boolean} 
+     */
+    upgrade(num, user) {
+        let node = num;
+        while (node !== -1) {
+            if (this.locked[node] !== 0) {
+                return false;
+            }
+            node = this.parent[node];
+        }
+
+        let lockedCount = 0;
+        let stack = [num];
+
+        while (stack.length) {
+            node = stack.pop();
+            if (this.locked[node]) {
+                this.locked[node] = 0;
+                lockedCount++;
+            }
+            stack.push(...this.child[node]);
+        }
+
+        if (lockedCount > 0) {
+            this.locked[num] = user;
+            return true;
+        }
+        return false;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity:
+    * $O(n)$ time for initialization.
+    * $O(1)$ time for each $lock()$ and $unlock()$ function call.
+    * $O(n)$ time for each $upgrade()$ function call.
+* Space complexity: $O(n)$
\ No newline at end of file
diff --git a/articles/rotate-list.md b/articles/rotate-list.md
new file mode 100644
index 000000000..675821f82
--- /dev/null
+++ b/articles/rotate-list.md
@@ -0,0 +1,486 @@
+## 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 rotateRight(self, head: Optional[ListNode], k: int) -> Optional[ListNode]:
+        if not head:
+            return None
+
+        arr, cur = [], head
+        while cur:
+            arr.append(cur.val)
+            cur = cur.next
+
+        n = len(arr)
+        k %= n
+        cur = head
+        for i in range(n - k, n):
+            cur.val = arr[i]
+            cur = cur.next
+
+        for i in range(n - k):
+            cur.val = arr[i]
+            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 rotateRight(ListNode head, int k) {
+        if (head == null) return null;
+
+        ArrayList<Integer> arr = new ArrayList<>();
+        ListNode cur = head;
+        while (cur != null) {
+            arr.add(cur.val);
+            cur = cur.next;
+        }
+
+        int n = arr.size();
+        k %= n;
+        cur = head;
+        for (int i = n - k; i < n; i++) {
+            cur.val = arr.get(i);
+            cur = cur.next;
+        }
+        for (int i = 0; i < n - k; i++) {
+            cur.val = arr.get(i);
+            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* rotateRight(ListNode* head, int k) {
+        if (!head) return nullptr;
+
+        vector<int> arr;
+        ListNode* cur = head;
+        while (cur) {
+            arr.push_back(cur->val);
+            cur = cur->next;
+        }
+
+        int n = arr.size();
+        k %= n;
+        cur = head;
+        for (int i = n - k; i < n; i++) {
+            cur->val = arr[i];
+            cur = cur->next;
+        }
+        for (int i = 0; i < n - k; i++) {
+            cur->val = arr[i];
+            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
+     * @param {number} k
+     * @return {ListNode}
+     */
+    rotateRight(head, k) {
+        if (!head) return null;
+
+        let arr = [];
+        let cur = head;
+        while (cur) {
+            arr.push(cur.val);
+            cur = cur.next;
+        }
+
+        let n = arr.length;
+        k %= n;
+        cur = head;
+        for (let i = n - k; i < n; i++) {
+            cur.val = arr[i];
+            cur = cur.next;
+        }
+        for (let i = 0; i < n - k; i++) {
+            cur.val = arr[i];
+            cur = cur.next;
+        }
+        return head;
+    }
+}
+```
+
+::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 rotateRight(self, head: ListNode, k: int) -> ListNode:
+        if not head:
+            return head
+
+        length, tail = 1, head
+        while tail.next:
+            tail = tail.next
+            length += 1
+
+        k = k % length
+        if k == 0:
+            return head
+
+        cur = head
+        for i in range(length - k - 1):
+            cur = cur.next
+        newHead = cur.next
+        cur.next = None
+        tail.next = head
+
+        return newHead
+```
+
+```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 rotateRight(ListNode head, int k) {
+        if (head == null) {
+            return head;
+        }
+
+        int length = 1;
+        ListNode tail = head;
+        while (tail.next != null) {
+            tail = tail.next;
+            length++;
+        }
+
+        k = k % length;
+        if (k == 0) {
+            return head;
+        }
+
+        ListNode cur = head;
+        for (int i = 0; i < length - k - 1; i++) {
+            cur = cur.next;
+        }
+        ListNode newHead = cur.next;
+        cur.next = null;
+        tail.next = head;
+
+        return newHead;
+    }
+}
+```
+
+```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* rotateRight(ListNode* head, int k) {
+        if (!head) {
+            return head;
+        }
+
+        int length = 1;
+        ListNode* tail = head;
+        while (tail->next) {
+            tail = tail->next;
+            length++;
+        }
+
+        k = k % length;
+        if (k == 0) {
+            return head;
+        }
+
+        ListNode* cur = head;
+        for (int i = 0; i < length - k - 1; i++) {
+            cur = cur->next;
+        }
+        ListNode* newHead = cur->next;
+        cur->next = nullptr;
+        tail->next = head;
+
+        return newHead;
+    }
+};
+```
+
+```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}
+     */
+    rotateRight(head, k) {
+        if (!head) {
+            return head;
+        }
+
+        let length = 1, tail = head;
+        while (tail.next) {
+            tail = tail.next;
+            length++;
+        }
+
+        k = k % length;
+        if (k === 0) {
+            return head;
+        }
+
+        let cur = head;
+        for (let i = 0; i < length - k - 1; i++) {
+            cur = cur.next;
+        }
+        let newHead = cur.next;
+        cur.next = null;
+        tail.next = head;
+
+        return newHead;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(1)$ extra space.
+
+---
+
+## 3. Iteration (Using One Pointer)
+
+::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 rotateRight(self, head: ListNode, k: int) -> ListNode:
+        if not head:
+            return head
+
+        cur, n = head, 1
+        while cur.next:
+            n += 1
+            cur = cur.next
+
+        cur.next = head
+        k %= n
+        for i in range(n - k):
+            cur = cur.next
+
+        head = cur.next
+        cur.next = None
+        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 rotateRight(ListNode head, int k) {
+        if (head == null) {
+            return head;
+        }
+
+        ListNode cur = head;
+        int n = 1;
+        while (cur.next != null) {
+            n++;
+            cur = cur.next;
+        }
+
+        cur.next = head;
+        k %= n;
+        for (int i = 0; i < n - k; i++) {
+            cur = cur.next;
+        }
+
+        head = cur.next;
+        cur.next = null;
+        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* rotateRight(ListNode* head, int k) {
+        if (!head) {
+            return head;
+        }
+
+        ListNode* cur = head;
+        int n = 1;
+        while (cur->next) {
+            n++;
+            cur = cur->next;
+        }
+
+        cur->next = head;
+        k %= n;
+        for (int i = 0; i < n - k; i++) {
+            cur = cur->next;
+        }
+
+        head = cur->next;
+        cur->next = nullptr;
+        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
+     * @param {number} k
+     * @return {ListNode}
+     */
+    rotateRight(head, k) {
+        if (!head) {
+            return head;
+        }
+
+        let cur = head, n = 1;
+        while (cur.next) {
+            n++;
+            cur = cur.next;
+        }
+
+        cur.next = head;
+        k %= n;
+        for (let i = 0; i < n - k; i++) {
+            cur = cur.next;
+        }
+
+        head = cur.next;
+        cur.next = null;
+        return head;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(1)$ extra space.
\ No newline at end of file

From aca35fe57da5460761a957a94a4f67a30f9b9acf Mon Sep 17 00:00:00 2001
From: Sri Hari <kataresrihari@gmail.com>
Date: Fri, 7 Feb 2025 08:41:16 +0530
Subject: [PATCH 04/13] Batch-5/Neetcode-ALL/Added-articles

---
 .../eliminate-maximum-number-of-monsters.md   | 298 ++++++++
 ...aximum-nesting-depth-of-the-parentheses.md | 305 ++++++++
 ...aximum-points-you-can-obtain-from-cards.md | 462 ++++++++++++
 articles/minimize-maximum-of-array.md         | 210 ++++++
 articles/two-city-scheduling.md               | 683 ++++++++++++++++++
 5 files changed, 1958 insertions(+)
 create mode 100644 articles/eliminate-maximum-number-of-monsters.md
 create mode 100644 articles/maximum-nesting-depth-of-the-parentheses.md
 create mode 100644 articles/maximum-points-you-can-obtain-from-cards.md
 create mode 100644 articles/minimize-maximum-of-array.md
 create mode 100644 articles/two-city-scheduling.md

diff --git a/articles/eliminate-maximum-number-of-monsters.md b/articles/eliminate-maximum-number-of-monsters.md
new file mode 100644
index 000000000..551c82473
--- /dev/null
+++ b/articles/eliminate-maximum-number-of-monsters.md
@@ -0,0 +1,298 @@
+## 1. Sorting
+
+::tabs-start
+
+```python
+class Solution:
+    def eliminateMaximum(self, dist: List[int], speed: List[int]) -> int:
+        minReach = [math.ceil(d / s) for d, s in zip(dist, speed)]
+        minReach.sort()
+
+        res = 0
+        for minute in range(len(minReach)):
+            if minute >= minReach[minute]:
+                return res
+            res += 1
+
+        return res
+```
+
+```java
+public class Solution {
+    public int eliminateMaximum(int[] dist, int[] speed) {
+        int n = dist.length;
+        int[] minReach = new int[n];
+
+        for (int i = 0; i < n; i++) {
+            minReach[i] = (int) Math.ceil((double) dist[i] / speed[i]);
+        }
+
+        Arrays.sort(minReach);
+
+        int res = 0;
+        for (int minute = 0; minute < n; minute++) {
+            if (minute >= minReach[minute]) {
+                return res;
+            }
+            res++;
+        }
+
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int eliminateMaximum(vector<int>& dist, vector<int>& speed) {
+        int n = dist.size();
+        vector<int> minReach(n);
+
+        for (int i = 0; i < n; i++) {
+            minReach[i] = ceil((double)dist[i] / speed[i]);
+        }
+
+        sort(minReach.begin(), minReach.end());
+
+        int res = 0;
+        for (int minute = 0; minute < n; minute++) {
+            if (minute >= minReach[minute]) {
+                return res;
+            }
+            res++;
+        }
+
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} dist
+     * @param {number[]} speed
+     * @return {number}
+     */
+    eliminateMaximum(dist, speed) {
+        let n = dist.length;
+        let minReach = new Array(n);
+
+        for (let i = 0; i < n; i++) {
+            minReach[i] = Math.ceil(dist[i] / speed[i]);
+        }
+
+        minReach.sort((a, b) => a - b);
+
+        let res = 0;
+        for (let minute = 0; minute < n; minute++) {
+            if (minute >= minReach[minute]) {
+                return res;
+            }
+            res++;
+        }
+
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n \log n)$
+* Space complexity: $O(n)$
+
+---
+
+## 2. Sorting (Overwrting Input Array)
+
+::tabs-start
+
+```python
+class Solution:
+    def eliminateMaximum(self, dist: List[int], speed: List[int]) -> int:
+        for i in range(len(dist)):
+            dist[i] = math.ceil(dist[i] / speed[i])
+
+        dist.sort()
+        for minute in range(len(dist)):
+            if minute >= dist[minute]:
+                return minute
+
+        return len(dist)
+```
+
+```java
+public class Solution {
+    public int eliminateMaximum(int[] dist, int[] speed) {
+        int n = dist.length;
+        for (int i = 0; i < n; i++) {
+            dist[i] = (int) Math.ceil((double) dist[i] / speed[i]);
+        }
+
+        Arrays.sort(dist);
+        for (int minute = 0; minute < n; minute++) {
+            if (minute >= dist[minute]) {
+                return minute;
+            }
+        }
+
+        return n;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int eliminateMaximum(vector<int>& dist, vector<int>& speed) {
+        int n = dist.size();
+        for (int i = 0; i < n; i++) {
+            dist[i] = ceil((double)dist[i] / speed[i]);
+        }
+
+        sort(dist.begin(), dist.end());
+        for (int minute = 0; minute < n; minute++) {
+            if (minute >= dist[minute]) {
+                return minute;
+            }
+        }
+
+        return n;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} dist
+     * @param {number[]} speed
+     * @return {number}
+     */
+    eliminateMaximum(dist, speed) {
+        let n = dist.length;
+        for (let i = 0; i < n; i++) {
+            dist[i] = Math.ceil(dist[i] / speed[i]);
+        }
+
+        dist.sort((a, b) => a - b);
+        for (let minute = 0; minute < n; minute++) {
+            if (minute >= dist[minute]) {
+                return minute;
+            }
+        }
+
+        return n;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n \log n)$
+* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm.
+
+---
+
+## 3. Min-Heap
+
+::tabs-start
+
+```python
+class Solution:
+    def eliminateMaximum(self, dist: List[int], speed: List[int]) -> int:
+        minHeap = []
+        for i in range(len(dist)):
+            heapq.heappush(minHeap, dist[i] / speed[i])
+
+        res = 0
+        while minHeap:
+            if res >= heapq.heappop(minHeap):
+                return res
+            res += 1
+
+        return res
+```
+
+```java
+public class Solution {
+    public int eliminateMaximum(int[] dist, int[] speed) {
+        PriorityQueue<Double> minHeap = new PriorityQueue<>();
+        for (int i = 0; i < dist.length; i++) {
+            minHeap.add((double) dist[i] / speed[i]);
+        }
+
+        int res = 0;
+        while (!minHeap.isEmpty()) {
+            if (res >= minHeap.poll()) {
+                return res;
+            }
+            res++;
+        }
+
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int eliminateMaximum(vector<int>& dist, vector<int>& speed) {
+        priority_queue<double, vector<double>, greater<double>> minHeap;
+        for (int i = 0; i < dist.size(); i++) {
+            minHeap.push((double)dist[i] / speed[i]);
+        }
+
+        int res = 0;
+        while (!minHeap.empty()) {
+            if (res >= minHeap.top()) {
+                return res;
+            }
+            minHeap.pop();
+            res++;
+        }
+
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} dist
+     * @param {number[]} speed
+     * @return {number}
+     */
+    eliminateMaximum(dist, speed) {
+        const minHeap = new MinPriorityQueue();
+        for (let i = 0; i < dist.length; i++) {
+            minHeap.enqueue(dist[i] / speed[i]);
+        }
+
+        let res = 0;
+        while (!minHeap.isEmpty()) {
+            if (res >= minHeap.dequeue().element) {
+                return res;
+            }
+            res++;
+        }
+
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n \log n)$
+* Space complexity: $O(n)$
\ No newline at end of file
diff --git a/articles/maximum-nesting-depth-of-the-parentheses.md b/articles/maximum-nesting-depth-of-the-parentheses.md
new file mode 100644
index 000000000..f18d24a7f
--- /dev/null
+++ b/articles/maximum-nesting-depth-of-the-parentheses.md
@@ -0,0 +1,305 @@
+## 1. Recursion
+
+::tabs-start
+
+```python
+class Solution:
+    def maxDepth(self, s: str) -> int:
+        res = 0
+
+        def dfs(i):
+            nonlocal res
+            if i == len(s):
+                return 0
+
+            cur = dfs(i + 1)
+            if s[i] == '(':
+                cur += 1
+            elif s[i] == ')':
+                cur -= 1
+            
+            res = max(res, abs(cur))
+            return cur
+
+        dfs(0)
+        return res
+```
+
+```java
+public class Solution {
+    private int res = 0;
+
+    public int maxDepth(String s) {
+        dfs(s, 0);
+        return res;
+    }
+
+    private int dfs(String s, int i) {
+        if (i == s.length()) {
+            return 0;
+        }
+
+        int cur = dfs(s, i + 1);
+        if (s.charAt(i) == '(') {
+            cur += 1;
+        } else if (s.charAt(i) == ')') {
+            cur -= 1;
+        }
+
+        res = Math.max(res, Math.abs(cur));
+        return cur;
+    }
+}
+```
+
+```cpp
+class Solution {
+private:
+    int res = 0;
+
+    int dfs(const string& s, int i) {
+        if (i == s.length()) {
+            return 0;
+        }
+
+        int cur = dfs(s, i + 1);
+        if (s[i] == '(') {
+            cur += 1;
+        } else if (s[i] == ')') {
+            cur -= 1;
+        }
+
+        res = max(res, abs(cur));
+        return cur;
+    }
+
+public:
+    int maxDepth(string s) {
+        dfs(s, 0);
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {string} s
+     * @return {number}
+     */
+    maxDepth(s) {
+        let res = 0;
+
+        const dfs = (i) => {
+            if (i === s.length) {
+                return 0;
+            }
+
+            let cur = dfs(i + 1);
+            if (s[i] === '(') {
+                cur += 1;
+            } else if (s[i] === ')') {
+                cur -= 1;
+            }
+
+            res = Math.max(res, Math.abs(cur));
+            return cur;
+        };
+
+        dfs(0);
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(n)$ for recursion stack.
+
+---
+
+## 2. Stack
+
+::tabs-start
+
+```python
+class Solution:
+    def maxDepth(self, s: str) -> int:
+        res, stack = 0, []
+
+        for c in s:
+            if c == "(":
+                stack.append(c)
+                res = max(res, len(stack))
+            elif c == ")":
+                stack.pop()
+
+        return res
+```
+
+```java
+public class Solution {
+    public int maxDepth(String s) {
+        int res = 0;
+        Stack<Character> stack = new Stack<>();
+
+        for (char c : s.toCharArray()) {
+            if (c == '(') {
+                stack.push(c);
+                res = Math.max(res, stack.size());
+            } else if (c == ')') {
+                stack.pop();
+            }
+        }
+
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int maxDepth(string s) {
+        int res = 0;
+        stack<char> stack;
+
+        for (char c : s) {
+            if (c == '(') {
+                stack.push(c);
+                res = max(res, (int)stack.size());
+            } else if (c == ')') {
+                stack.pop();
+            }
+        }
+
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {string} s
+     * @return {number}
+     */
+    maxDepth(s) {
+        let res = 0;
+        let stack = [];
+
+        for (let c of s) {
+            if (c === '(') {
+                stack.push(c);
+                res = Math.max(res, stack.length);
+            } else if (c === ')') {
+                stack.pop();
+            }
+        }
+
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(n)$
+
+---
+
+## 3. Iteration
+
+::tabs-start
+
+```python
+class Solution:
+    def maxDepth(self, s: str) -> int:
+        res = 0
+        cur = 0
+
+        for c in s:
+            if c == "(":
+                cur += 1
+            elif c == ")":
+                cur -= 1
+            res = max(res, cur)
+
+        return res
+```
+
+```java
+public class Solution {
+    public int maxDepth(String s) {
+        int res = 0, cur = 0;
+
+        for (int i = 0; i < s.length(); i++) {
+            char c = s.charAt(i);
+            if (c == '(') {
+                cur++;
+            } else if (c == ')') {
+                cur--;
+            }
+            res = Math.max(res, cur);
+        }
+
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int maxDepth(string s) {
+        int res = 0, cur = 0;
+
+        for (char c : s) {
+            if (c == '(') {
+                cur++;
+            } else if (c == ')') {
+                cur--;
+            }
+            res = max(res, cur);
+        }
+
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {string} s
+     * @return {number}
+     */
+    maxDepth(s) {
+        let res = 0, cur = 0;
+
+        for (let c of s) {
+            if (c === '(') {
+                cur++;
+            } else if (c === ')') {
+                cur--;
+            }
+            res = Math.max(res, cur);
+        }
+
+        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/maximum-points-you-can-obtain-from-cards.md b/articles/maximum-points-you-can-obtain-from-cards.md
new file mode 100644
index 000000000..8d1b9294a
--- /dev/null
+++ b/articles/maximum-points-you-can-obtain-from-cards.md
@@ -0,0 +1,462 @@
+## 1. Brute Force
+
+::tabs-start
+
+```python
+class Solution:
+    def maxScore(self, cardPoints: List[int], k: int) -> int:
+        n = len(cardPoints)
+        res = 0
+
+        for left in range(k + 1):
+            leftSum = sum(cardPoints[:left])
+            rightSum = sum(cardPoints[n - (k - left):])
+            res = max(res, leftSum + rightSum)
+
+        return res
+```
+
+```java
+public class Solution {
+    public int maxScore(int[] cardPoints, int k) {
+        int n = cardPoints.length;
+        int res = 0;
+
+        for (int left = 0; left <= k; left++) {
+            int leftSum = 0;
+            for (int i = 0; i < left; i++) {
+                leftSum += cardPoints[i];
+            }
+
+            int rightSum = 0;
+            for (int i = n - (k - left); i < n; i++) {
+                rightSum += cardPoints[i];
+            }
+
+            res = Math.max(res, leftSum + rightSum);
+        }
+
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int maxScore(vector<int>& cardPoints, int k) {
+        int n = cardPoints.size();
+        int res = 0;
+
+        for (int left = 0; left <= k; left++) {
+            int leftSum = 0;
+            for (int i = 0; i < left; i++) {
+                leftSum += cardPoints[i];
+            }
+
+            int rightSum = 0;
+            for (int i = n - (k - left); i < n; i++) {
+                rightSum += cardPoints[i];
+            }
+
+            res = max(res, leftSum + rightSum);
+        }
+
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} cardPoints
+     * @param {number} k
+     * @return {number}
+     */
+    maxScore(cardPoints, k) {
+        let n = cardPoints.length;
+        let res = 0;
+
+        for (let left = 0; left <= k; left++) {
+            let leftSum = 0;
+            for (let i = 0; i < left; i++) {
+                leftSum += cardPoints[i];
+            }
+
+            let rightSum = 0;
+            for (let i = n - (k - left); i < n; i++) {
+                rightSum += cardPoints[i];
+            }
+
+            res = Math.max(res, leftSum + rightSum);
+        }
+
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(k ^ 2)$
+* Space complexity: $O(1)$ extra space.
+
+> Where $k$ is the number of cards to pick.
+
+---
+
+## 2. Prefix & Suffix Sums
+
+::tabs-start
+
+```python
+class Solution:
+    def maxScore(self, cardPoints: List[int], k: int) -> int:
+        n = len(cardPoints)
+
+        prefix = [0] * (n + 1)
+        for i in range(n):
+            prefix[i + 1] = prefix[i] + cardPoints[i]
+
+        suffix = [0] * (n + 1)
+        for i in range(n - 1, -1, -1):
+            suffix[i] = suffix[i + 1] + cardPoints[i]
+
+        res = 0
+        for left in range(k + 1):
+            right = k - left
+            res = max(res, prefix[left] + suffix[n - right])
+
+        return res
+```
+
+```java
+public class Solution {
+    public int maxScore(int[] cardPoints, int k) {
+        int n = cardPoints.length;
+
+        int[] prefix = new int[n + 1];
+        for (int i = 0; i < n; i++) {
+            prefix[i + 1] = prefix[i] + cardPoints[i];
+        }
+
+        int[] suffix = new int[n + 1];
+        for (int i = n - 1; i >= 0; i--) {
+            suffix[i] = suffix[i + 1] + cardPoints[i];
+        }
+
+        int res = 0;
+        for (int left = 0; left <= k; left++) {
+            int right = k - left;
+            res = Math.max(res, prefix[left] + suffix[n - right]);
+        }
+
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int maxScore(vector<int>& cardPoints, int k) {
+        int n = cardPoints.size();
+
+        vector<int> prefix(n + 1, 0);
+        for (int i = 0; i < n; i++) {
+            prefix[i + 1] = prefix[i] + cardPoints[i];
+        }
+
+        vector<int> suffix(n + 1, 0);
+        for (int i = n - 1; i >= 0; i--) {
+            suffix[i] = suffix[i + 1] + cardPoints[i];
+        }
+
+        int res = 0;
+        for (int left = 0; left <= k; left++) {
+            int right = k - left;
+            res = max(res, prefix[left] + suffix[n - right]);
+        }
+
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} cardPoints
+     * @param {number} k
+     * @return {number}
+     */
+    maxScore(cardPoints, k) {
+        let n = cardPoints.length;
+
+        let prefix = new Array(n + 1).fill(0);
+        for (let i = 0; i < n; i++) {
+            prefix[i + 1] = prefix[i] + cardPoints[i];
+        }
+
+        let suffix = new Array(n + 1).fill(0);
+        for (let i = n - 1; i >= 0; i--) {
+            suffix[i] = suffix[i + 1] + cardPoints[i];
+        }
+
+        let res = 0;
+        for (let left = 0; left <= k; left++) {
+            let right = k - left;
+            res = Math.max(res, prefix[left] + suffix[n - right]);
+        }
+
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(n)$
+
+---
+
+## 3. Sliding Window (Minimum Sum Window)
+
+::tabs-start
+
+```python
+class Solution:
+    def maxScore(self, cardPoints: List[int], k: int) -> int:
+        n = len(cardPoints)
+        windowSize = n - k
+
+        if windowSize == 0:
+            return sum(cardPoints)
+
+        total = 0
+        minWindowSum = float("inf")
+        curSum = 0
+
+        for i in range(n):
+            total += cardPoints[i]
+            curSum += cardPoints[i]
+            if i >= windowSize - 1:
+                minWindowSum = min(minWindowSum, curSum)
+                curSum -= cardPoints[i - windowSize + 1]
+
+        return total - minWindowSum
+```
+
+```java
+public class Solution {
+    public int maxScore(int[] cardPoints, int k) {
+        int n = cardPoints.length;
+        int windowSize = n - k;
+
+        if (windowSize == 0) {
+            int sum = 0;
+            for (int num : cardPoints) sum += num;
+            return sum;
+        }
+
+        int total = 0;
+        int minWindowSum = Integer.MAX_VALUE;
+        int curSum = 0;
+
+        for (int i = 0; i < n; i++) {
+            total += cardPoints[i];
+            curSum += cardPoints[i];
+            if (i >= windowSize - 1) {
+                minWindowSum = Math.min(minWindowSum, curSum);
+                curSum -= cardPoints[i - windowSize + 1];
+            }
+        }
+
+        return total - minWindowSum;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int maxScore(vector<int>& cardPoints, int k) {
+        int n = cardPoints.size();
+        int windowSize = n - k;
+
+        if (windowSize == 0) {
+            return accumulate(cardPoints.begin(), cardPoints.end(), 0);
+        }
+
+        int total = 0;
+        int minWindowSum = INT_MAX;
+        int curSum = 0;
+
+        for (int i = 0; i < n; i++) {
+            total += cardPoints[i];
+            curSum += cardPoints[i];
+            if (i >= windowSize - 1) {
+                minWindowSum = min(minWindowSum, curSum);
+                curSum -= cardPoints[i - windowSize + 1];
+            }
+        }
+
+        return total - minWindowSum;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} cardPoints
+     * @param {number} k
+     * @return {number}
+     */
+    maxScore(cardPoints, k) {
+        let n = cardPoints.length;
+        let windowSize = n - k;
+
+        if (windowSize === 0) {
+            return cardPoints.reduce((sum, num) => sum + num, 0);
+        }
+
+        let total = 0;
+        let minWindowSum = Infinity;
+        let curSum = 0;
+
+        for (let i = 0; i < n; i++) {
+            total += cardPoints[i];
+            curSum += cardPoints[i];
+            if (i >= windowSize - 1) {
+                minWindowSum = Math.min(minWindowSum, curSum);
+                curSum -= cardPoints[i - windowSize + 1];
+            }
+        }
+
+        return total - minWindowSum;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(1)$ extra space.
+
+---
+
+## 4. Sliding Window
+
+::tabs-start
+
+```python
+class Solution:
+    def maxScore(self, cardPoints: List[int], k: int) -> int:
+        l, r = 0, len(cardPoints) - k
+        total = sum(cardPoints[r:])
+        res = total
+
+        while r < len(cardPoints):
+            total += cardPoints[l] - cardPoints[r]
+            res = max(res, total)
+            l += 1
+            r += 1
+
+        return res
+```
+
+```java
+public class Solution {
+    public int maxScore(int[] cardPoints, int k) {
+        int l = 0, r = cardPoints.length - k;
+        int total = 0;
+
+        for (int i = r; i < cardPoints.length; i++) {
+            total += cardPoints[i];
+        }
+
+        int res = total;
+
+        while (r < cardPoints.length) {
+            total += cardPoints[l] - cardPoints[r];
+            res = Math.max(res, total);
+            l++;
+            r++;
+        }
+
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int maxScore(vector<int>& cardPoints, int k) {
+        int l = 0, r = cardPoints.size() - k;
+        int total = 0;
+
+        for (int i = r; i < cardPoints.size(); i++) {
+            total += cardPoints[i];
+        }
+
+        int res = total;
+
+        while (r < cardPoints.size()) {
+            total += cardPoints[l] - cardPoints[r];
+            res = max(res, total);
+            l++;
+            r++;
+        }
+
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} cardPoints
+     * @param {number} k
+     * @return {number}
+     */
+    maxScore(cardPoints, k) {
+        let l = 0, r = cardPoints.length - k;
+        let total = 0;
+
+        for (let i = r; i < cardPoints.length; i++) {
+            total += cardPoints[i];
+        }
+
+        let res = total;
+
+        while (r < cardPoints.length) {
+            total += cardPoints[l] - cardPoints[r];
+            res = Math.max(res, total);
+            l++;
+            r++;
+        }
+
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(k)$
+* Space complexity: $O(1)$ extra space.
+
+> Where $k$ is the number of cards to pick.
\ No newline at end of file
diff --git a/articles/minimize-maximum-of-array.md b/articles/minimize-maximum-of-array.md
new file mode 100644
index 000000000..b851e40b5
--- /dev/null
+++ b/articles/minimize-maximum-of-array.md
@@ -0,0 +1,210 @@
+## 1. Binary Search
+
+::tabs-start
+
+```python
+class Solution:
+    def minimizeArrayValue(self, nums: List[int]) -> int:
+        def isValid(maxVal):
+            prefix_sum = 0
+            for i in range(len(nums)):
+                prefix_sum += nums[i]
+                if prefix_sum > maxVal * (i + 1):
+                    return False
+            return True
+
+        left, right = 0, max(nums)
+        while left < right:
+            mid = left + (right - left) // 2
+            if isValid(mid):
+                right = mid
+            else:
+                left = mid + 1
+
+        return left
+```
+
+```java
+public class Solution {
+    public int minimizeArrayValue(int[] nums) {
+        int left = 0, right = 0;
+        for (int num : nums) {
+            right = Math.max(right, num);
+        }
+
+        while (left < right) {
+            int mid = left + (right - left) / 2;
+            if (isValid(nums, mid)) {
+                right = mid;
+            } else {
+                left = mid + 1;
+            }
+        }
+
+        return left;
+    }
+
+    private boolean isValid(int[] nums, int maxVal) {
+        long prefixSum = 0;
+        for (int i = 0; i < nums.length; i++) {
+            prefixSum += nums[i];
+            if (prefixSum > (long) maxVal * (i + 1)) {
+                return false;
+            }
+        }
+        return true;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int minimizeArrayValue(vector<int>& nums) {
+        int left = 0, right = *max_element(nums.begin(), nums.end());
+
+        while (left < right) {
+            int mid = left + (right - left) / 2;
+            if (isValid(nums, mid)) {
+                right = mid;
+            } else {
+                left = mid + 1;
+            }
+        }
+
+        return left;
+    }
+
+private:
+    bool isValid(vector<int>& nums, int maxVal) {
+        long long prefixSum = 0;
+        for (int i = 0; i < nums.size(); i++) {
+            prefixSum += nums[i];
+            if (prefixSum > (long long)maxVal * (i + 1)) {
+                return false;
+            }
+        }
+        return true;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} nums
+     * @return {number}
+     */
+    minimizeArrayValue(nums) {
+        const isValid = (maxVal) => {
+            let prefixSum = 0;
+            for (let i = 0; i < nums.length; i++) {
+                prefixSum += nums[i];
+                if (prefixSum > maxVal * (i + 1)) {
+                    return false;
+                }
+            }
+            return true;
+        };
+
+        let left = 0, right = Math.max(...nums);
+        while (left < right) {
+            let mid = left + Math.floor((right - left) / 2);
+            if (isValid(mid)) {
+                right = mid;
+            } else {
+                left = mid + 1;
+            }
+        }
+
+        return left;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n \log m)$
+* Space complexity: $O(1)$ extra space.
+
+> Where $n$ is the size of the array $nums$ and $m$ is the maximum value in the array.
+
+---
+
+## 2. Prefix Sum + Greedy
+
+::tabs-start
+
+```python
+class Solution:
+    def minimizeArrayValue(self, nums: List[int]) -> int:
+        res = total = nums[0]
+
+        for i in range(1, len(nums)):
+            total += nums[i]
+            res = max(res, math.ceil(total / (i + 1)))
+
+        return res
+```
+
+```java
+public class Solution {
+    public int minimizeArrayValue(int[] nums) {
+        int res = nums[0];
+        long total = nums[0];
+
+        for (int i = 1; i < nums.length; i++) {
+            total += nums[i];
+            res = Math.max(res, (int) Math.ceil((double) total / (i + 1)));
+        }
+
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int minimizeArrayValue(vector<int>& nums) {
+        int res = nums[0];
+        long long total = nums[0];
+
+        for (int i = 1; i < nums.size(); i++) {
+            total += nums[i];
+            res = max(res, (int)ceil((double)total / (i + 1)));
+        }
+
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} nums
+     * @return {number}
+     */
+    minimizeArrayValue(nums) {
+        let res = nums[0];
+        let total = nums[0];
+
+        for (let i = 1; i < nums.length; i++) {
+            total += nums[i];
+            res = Math.max(res, Math.ceil(total / (i + 1)));
+        }
+
+        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/two-city-scheduling.md b/articles/two-city-scheduling.md
new file mode 100644
index 000000000..61f80767c
--- /dev/null
+++ b/articles/two-city-scheduling.md
@@ -0,0 +1,683 @@
+## 1. Recursion
+
+::tabs-start
+
+```python
+class Solution:
+    def twoCitySchedCost(self, costs: List[List[int]]) -> int:
+        n = len(costs) // 2
+
+        def dfs(i, aCount, bCount):
+            if i == len(costs):
+                return 0
+
+            res = float("inf")
+            if aCount > 0:
+                res = costs[i][0] + dfs(i + 1, aCount - 1, bCount)
+
+            if bCount > 0:
+                res = min(res, costs[i][1] + dfs(i + 1, aCount, bCount - 1))
+            return res
+
+        return dfs(0, n, n)
+```
+
+```java
+public class Solution {
+    public int twoCitySchedCost(int[][] costs) {
+        int n = costs.length / 2;
+        return dfs(costs, 0, n, n);
+    }
+
+    private int dfs(int[][] costs, int i, int aCount, int bCount) {
+        if (i == costs.length) {
+            return 0;
+        }
+
+        int res = Integer.MAX_VALUE;
+        if (aCount > 0) {
+            res = costs[i][0] + dfs(costs, i + 1, aCount - 1, bCount);
+        }
+
+        if (bCount > 0) {
+            res = Math.min(res, costs[i][1] + dfs(costs, i + 1, aCount, bCount - 1));
+        }
+
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int twoCitySchedCost(vector<vector<int>>& costs) {
+        int n = costs.size() / 2;
+        return dfs(costs, 0, n, n);
+    }
+
+private:
+    int dfs(vector<vector<int>>& costs, int i, int aCount, int bCount) {
+        if (i == costs.size()) {
+            return 0;
+        }
+
+        int res = INT_MAX;
+        if (aCount > 0) {
+            res = costs[i][0] + dfs(costs, i + 1, aCount - 1, bCount);
+        }
+
+        if (bCount > 0) {
+            res = min(res, costs[i][1] + dfs(costs, i + 1, aCount, bCount - 1));
+        }
+
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} costs
+     * @return {number}
+     */
+    twoCitySchedCost(costs) {
+        let n = costs.length / 2;
+
+        const dfs = (i, aCount, bCount) => {
+            if (i === costs.length) {
+                return 0;
+            }
+
+            let res = Infinity;
+            if (aCount > 0) {
+                res = costs[i][0] + dfs(i + 1, aCount - 1, bCount);
+            }
+
+            if (bCount > 0) {
+                res = Math.min(res, costs[i][1] + dfs(i + 1, aCount, bCount - 1));
+            }
+
+            return res;
+        };
+
+        return dfs(0, n, n);
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(2 ^ N)$
+* Space complexity: $O(N)$ for recursion stack.
+
+> Where $N$ is the size of the array $costs$.
+
+---
+
+## 2. Dynamic Programming (Top-Down)
+
+::tabs-start
+
+```python
+class Solution:
+    def twoCitySchedCost(self, costs: List[List[int]]) -> int:
+        n = len(costs) // 2
+        dp = [[-1] * (n + 1) for _ in range(n + 1)]
+
+        def dfs(i, aCount, bCount):
+            if i == len(costs):
+                return 0
+            if dp[aCount][bCount] != -1:
+                return dp[aCount][bCount]
+
+            res = float("inf")
+            if aCount > 0:
+                res = costs[i][0] + dfs(i + 1, aCount - 1, bCount)
+            if bCount > 0:
+                res = min(res, costs[i][1] + dfs(i + 1, aCount, bCount - 1))
+
+            dp[aCount][bCount] = res
+            return res
+
+        return dfs(0, n, n)
+```
+
+```java
+public class Solution {
+    private int[][] dp;
+
+    public int twoCitySchedCost(int[][] costs) {
+        int n = costs.length / 2;
+        dp = new int[n + 1][n + 1];
+        for (int[] row : dp) {
+            Arrays.fill(row, -1);
+        }
+        return dfs(costs, 0, n, n);
+    }
+
+    private int dfs(int[][] costs, int i, int aCount, int bCount) {
+        if (i == costs.length) {
+            return 0;
+        }
+        if (dp[aCount][bCount] != -1) {
+            return dp[aCount][bCount];
+        }
+
+        int res = Integer.MAX_VALUE;
+        if (aCount > 0) {
+            res = costs[i][0] + dfs(costs, i + 1, aCount - 1, bCount);
+        }
+        if (bCount > 0) {
+            res = Math.min(res, costs[i][1] + dfs(costs, i + 1, aCount, bCount - 1));
+        }
+
+        dp[aCount][bCount] = res;
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    vector<vector<int>> dp;
+
+    int twoCitySchedCost(vector<vector<int>>& costs) {
+        int n = costs.size() / 2;
+        dp = vector<vector<int>>(n + 1, vector<int>(n + 1, -1));
+        return dfs(costs, 0, n, n);
+    }
+
+private:
+    int dfs(vector<vector<int>>& costs, int i, int aCount, int bCount) {
+        if (i == costs.size()) {
+            return 0;
+        }
+        if (dp[aCount][bCount] != -1) {
+            return dp[aCount][bCount];
+        }
+
+        int res = INT_MAX;
+        if (aCount > 0) {
+            res = costs[i][0] + dfs(costs, i + 1, aCount - 1, bCount);
+        }
+        if (bCount > 0) {
+            res = min(res, costs[i][1] + dfs(costs, i + 1, aCount, bCount - 1));
+        }
+
+        dp[aCount][bCount] = res;
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} costs
+     * @return {number}
+     */
+    twoCitySchedCost(costs) {
+        let n = costs.length / 2;
+        let dp = Array.from({ length: n + 1 }, () => new Array(n + 1).fill(-1));
+
+        const dfs = (i, aCount, bCount) => {
+            if (i === costs.length) {
+                return 0;
+            }
+            if (dp[aCount][bCount] !== -1) {
+                return dp[aCount][bCount];
+            }
+
+            let res = Infinity;
+            if (aCount > 0) {
+                res = costs[i][0] + dfs(i + 1, aCount - 1, bCount);
+            }
+            if (bCount > 0) {
+                res = Math.min(res, costs[i][1] + dfs(i + 1, aCount, bCount - 1));
+            }
+
+            dp[aCount][bCount] = res;
+            return res;
+        };
+
+        return dfs(0, n, n);
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n ^ 2)$
+* Space complexity: $O(n ^ 2)$
+
+> Where $n$ is the half of the size of the array $costs$.
+
+---
+
+## 3. Dynamic Programming (Bottom-Up)
+
+::tabs-start
+
+```python
+class Solution:
+    def twoCitySchedCost(self, costs: List[List[int]]) -> int:
+        n = len(costs) // 2
+        dp = [[0] * (n + 1) for _ in range(n + 1)]
+
+        for aCount in range(n + 1):
+            for bCount in range(n + 1):
+                i = aCount + bCount
+                if i == 0:
+                    continue
+
+                dp[aCount][bCount] = float("inf")
+                if aCount > 0:
+                    dp[aCount][bCount] = min(dp[aCount][bCount], dp[aCount - 1][bCount] + costs[i - 1][0])
+                if bCount > 0:
+                    dp[aCount][bCount] = min(dp[aCount][bCount], dp[aCount][bCount - 1] + costs[i - 1][1])
+
+        return dp[n][n]
+```
+
+```java
+public class Solution {
+    public int twoCitySchedCost(int[][] costs) {
+        int n = costs.length / 2;
+        int[][] dp = new int[n + 1][n + 1];
+
+        for (int aCount = 0; aCount <= n; aCount++) {
+            for (int bCount = 0; bCount <= n; bCount++) {
+                int i = aCount + bCount;
+                if (i == 0) continue;
+
+                dp[aCount][bCount] = Integer.MAX_VALUE;
+                if (aCount > 0) {
+                    dp[aCount][bCount] = Math.min(dp[aCount][bCount], dp[aCount - 1][bCount] + costs[i - 1][0]);
+                }
+                if (bCount > 0) {
+                    dp[aCount][bCount] = Math.min(dp[aCount][bCount], dp[aCount][bCount - 1] + costs[i - 1][1]);
+                }
+            }
+        }
+
+        return dp[n][n];
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int twoCitySchedCost(vector<vector<int>>& costs) {
+        int n = costs.size() / 2;
+        vector<vector<int>> dp(n + 1, vector<int>(n + 1));
+
+        for (int aCount = 0; aCount <= n; aCount++) {
+            for (int bCount = 0; bCount <= n; bCount++) {
+                int i = aCount + bCount;
+                if (i == 0) continue;
+
+                dp[aCount][bCount] = INT_MAX;
+                if (aCount > 0) {
+                    dp[aCount][bCount] = min(dp[aCount][bCount], dp[aCount - 1][bCount] + costs[i - 1][0]);
+                }
+                if (bCount > 0) {
+                    dp[aCount][bCount] = min(dp[aCount][bCount], dp[aCount][bCount - 1] + costs[i - 1][1]);
+                }
+            }
+        }
+
+        return dp[n][n];
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} costs
+     * @return {number}
+     */
+    twoCitySchedCost(costs) {
+        let n = costs.length / 2;
+        let dp = Array.from({ length: n + 1 }, () => new Array(n + 1).fill(0));
+
+        for (let aCount = 0; aCount <= n; aCount++) {
+            for (let bCount = 0; bCount <= n; bCount++) {
+                let i = aCount + bCount;
+                if (i === 0) continue;
+
+                dp[aCount][bCount] = Infinity;
+                if (aCount > 0) {
+                    dp[aCount][bCount] = Math.min(dp[aCount][bCount], dp[aCount - 1][bCount] + costs[i - 1][0]);
+                }
+                if (bCount > 0) {
+                    dp[aCount][bCount] = Math.min(dp[aCount][bCount], dp[aCount][bCount - 1] + costs[i - 1][1]);
+                }
+            }
+        }
+
+        return dp[n][n];
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n ^ 2)$
+* Space complexity: $O(n ^ 2)$
+
+> Where $n$ is the half of the size of the array $costs$.
+
+---
+
+## 4. Dynamic Programming (Space Optimized)
+
+::tabs-start
+
+```python
+class Solution:
+    def twoCitySchedCost(self, costs: List[List[int]]) -> int:
+        n = len(costs) // 2
+        dp = [0] * (n + 1)
+
+        for aCount in range(n + 1):
+            for bCount in range(n + 1):
+                i = aCount + bCount
+                if i == 0:
+                    continue
+
+                tmp = dp[bCount]
+                dp[bCount] = float("inf")
+                if aCount > 0:
+                    dp[bCount] = min(dp[bCount], tmp + costs[i - 1][0])
+                if bCount > 0:
+                    dp[bCount] = min(dp[bCount], dp[bCount - 1] + costs[i - 1][1])
+
+        return dp[n]
+```
+
+```java
+public class Solution {
+    public int twoCitySchedCost(int[][] costs) {
+        int n = costs.length / 2;
+        int[] dp = new int[n + 1];
+
+        for (int aCount = 0; aCount <= n; aCount++) {
+            for (int bCount = 0; bCount <= n; bCount++) {
+                int i = aCount + bCount;
+                if (i == 0) continue;
+
+                int tmp = dp[bCount];
+                dp[bCount] = Integer.MAX_VALUE;
+                if (aCount > 0) {
+                    dp[bCount] = Math.min(dp[bCount], tmp + costs[i - 1][0]);
+                }
+                if (bCount > 0) {
+                    dp[bCount] = Math.min(dp[bCount], dp[bCount - 1] + costs[i - 1][1]);
+                }
+            }
+        }
+
+        return dp[n];
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int twoCitySchedCost(vector<vector<int>>& costs) {
+        int n = costs.size() / 2;
+        vector<int> dp(n + 1, 0);
+
+        for (int aCount = 0; aCount <= n; aCount++) {
+            for (int bCount = 0; bCount <= n; bCount++) {
+                int i = aCount + bCount;
+                if (i == 0) continue;
+
+                int tmp = dp[bCount];
+                dp[bCount] = INT_MAX;
+                if (aCount > 0) {
+                    dp[bCount] = min(dp[bCount], tmp + costs[i - 1][0]);
+                }
+                if (bCount > 0) {
+                    dp[bCount] = min(dp[bCount], dp[bCount - 1] + costs[i - 1][1]);
+                }
+            }
+        }
+
+        return dp[n];
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} costs
+     * @return {number}
+     */
+    twoCitySchedCost(costs) {
+        let n = costs.length / 2;
+        let dp = new Array(n + 1).fill(0);
+
+        for (let aCount = 0; aCount <= n; aCount++) {
+            for (let bCount = 0; bCount <= n; bCount++) {
+                let i = aCount + bCount;
+                if (i === 0) continue;
+
+                let tmp = dp[bCount];
+                dp[bCount] = Infinity;
+                if (aCount > 0) {
+                    dp[bCount] = Math.min(dp[bCount], tmp + costs[i - 1][0]);
+                }
+                if (bCount > 0) {
+                    dp[bCount] = Math.min(dp[bCount], dp[bCount - 1] + costs[i - 1][1]);
+                }
+            }
+        }
+
+        return dp[n];
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n ^ 2)$
+* Space complexity: $O(n)$
+
+> Where $n$ is the half of the size of the array $costs$.
+
+---
+
+## 5. Greedy
+
+::tabs-start
+
+```python
+class Solution:
+    def twoCitySchedCost(self, costs: List[List[int]]) -> int:
+        diffs = []
+        for c1, c2 in costs:
+            diffs.append([c2 - c1, c1, c2])
+
+        diffs.sort()
+        res = 0
+        for i in range(len(diffs)):
+            if i < len(diffs) // 2:
+                res += diffs[i][2]
+            else:
+                res += diffs[i][1]
+
+        return res
+```
+
+```java
+public class Solution {
+    public int twoCitySchedCost(int[][] costs) {
+        List<int[]> diffs = new ArrayList<>();
+        for (int[] cost : costs) {
+            diffs.add(new int[]{cost[1] - cost[0], cost[0], cost[1]});
+        }
+
+        diffs.sort(Comparator.comparingInt(a -> a[0]));
+
+        int res = 0;
+        for (int i = 0; i < diffs.size(); i++) {
+            if (i < diffs.size() / 2) {
+                res += diffs.get(i)[2];
+            } else {
+                res += diffs.get(i)[1];
+            }
+        }
+
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int twoCitySchedCost(vector<vector<int>>& costs) {
+        vector<vector<int>> diffs;
+        for (auto& cost : costs) {
+            diffs.push_back({cost[1] - cost[0], cost[0], cost[1]});
+        }
+
+        sort(diffs.begin(), diffs.end());
+
+        int res = 0;
+        for (int i = 0; i < diffs.size(); i++) {
+            if (i < diffs.size() / 2) {
+                res += diffs[i][2];
+            } else {
+                res += diffs[i][1];
+            }
+        }
+
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} costs
+     * @return {number}
+     */
+    twoCitySchedCost(costs) {
+        let diffs = [];
+        for (let cost of costs) {
+            diffs.push([cost[1] - cost[0], cost[0], cost[1]]);
+        }
+
+        diffs.sort((a, b) => a[0] - b[0]);
+
+        let res = 0;
+        for (let i = 0; i < diffs.length; i++) {
+            if (i < diffs.length / 2) {
+                res += diffs[i][2];
+            } else {
+                res += diffs[i][1];
+            }
+        }
+
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n \log n)$
+* Space complexity: $O(n)$
+
+---
+
+## 6. Greedy (Optimal)
+
+::tabs-start
+
+```python
+class Solution:
+    def twoCitySchedCost(self, costs: List[List[int]]) -> int:
+        costs.sort(key=lambda x: x[1] - x[0])
+        n, res = len(costs) // 2, 0
+
+        for i in range(n):
+            res += costs[i][1] + costs[i + n][0]
+        return res
+```
+
+```java
+public class Solution {
+    public int twoCitySchedCost(int[][] costs) {
+        Arrays.sort(costs, (a, b) -> Integer.compare(a[1] - a[0], b[1] - b[0]));
+        int n = costs.length / 2, res = 0;
+
+        for (int i = 0; i < n; i++) {
+            res += costs[i][1] + costs[i + n][0];
+        }
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int twoCitySchedCost(vector<vector<int>>& costs) {
+        sort(costs.begin(), costs.end(), [](const auto& a, const auto& b) {
+            return (a[1] - a[0]) < (b[1] - b[0]);
+        });
+
+        int n = costs.size() / 2, res = 0;
+        for (int i = 0; i < n; i++) {
+            res += costs[i][1] + costs[i + n][0];
+        }
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} costs
+     * @return {number}
+     */
+    twoCitySchedCost(costs) {
+        costs.sort((a, b) => (a[1] - a[0]) - (b[1] - b[0]));
+        let n = costs.length / 2, res = 0;
+
+        for (let i = 0; i < n; i++) {
+            res += costs[i][1] + costs[i + n][0];
+        }
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n \log n)$
+* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm.
\ No newline at end of file

From 53121f6c1b8a11ab874006296c7afe099da3a49e Mon Sep 17 00:00:00 2001
From: Sri Hari <kataresrihari@gmail.com>
Date: Fri, 7 Feb 2025 15:29:08 +0530
Subject: [PATCH 05/13] Batch-5/Neetcode-ALL/Added-articles

---
 articles/furthest-building-you-can-reach.md   | 723 ++++++++++++++++++
 ...lement-after-decreasing-and-rearranging.md | 158 ++++
 articles/maximum-length-of-pair-chain.md      | 556 ++++++++++++++
 ...ns-to-make-character-frequencies-unique.md | 348 +++++++++
 ...es-if-both-neighbors-are-the-same-color.md | 322 ++++++++
 5 files changed, 2107 insertions(+)
 create mode 100644 articles/furthest-building-you-can-reach.md
 create mode 100644 articles/maximum-element-after-decreasing-and-rearranging.md
 create mode 100644 articles/maximum-length-of-pair-chain.md
 create mode 100644 articles/minimum-deletions-to-make-character-frequencies-unique.md
 create mode 100644 articles/remove-colored-pieces-if-both-neighbors-are-the-same-color.md

diff --git a/articles/furthest-building-you-can-reach.md b/articles/furthest-building-you-can-reach.md
new file mode 100644
index 000000000..24ca0ef3b
--- /dev/null
+++ b/articles/furthest-building-you-can-reach.md
@@ -0,0 +1,723 @@
+## 1. Brute Force (Greedy)
+
+::tabs-start
+
+```python
+class Solution:
+    def furthestBuilding(self, heights: List[int], bricks: int, ladders: int) -> int:
+        n = len(heights)
+
+        for i in range(1, n):
+            if ladders >= i:
+                continue
+
+            diffs = []
+            for j in range(i):
+                if heights[j + 1] > heights[j]:
+                    diffs.append(heights[j + 1] - heights[j])
+
+            diffs.sort()
+            brickSum = 0
+            for j in range(len(diffs) - ladders):
+                brickSum += diffs[j]
+
+            if brickSum > bricks:
+                return i - 1
+
+        return n - 1
+```
+
+```java
+public class Solution {
+    public int furthestBuilding(int[] heights, int bricks, int ladders) {
+        int n = heights.length;
+
+        for (int i = 1; i < n; i++) {
+            if (ladders >= i) {
+                continue;
+            }
+
+            List<Integer> diffs = new ArrayList<>();
+            for (int j = 0; j < i; j++) {
+                if (heights[j + 1] > heights[j]) {
+                    diffs.add(heights[j + 1] - heights[j]);
+                }
+            }
+
+            Collections.sort(diffs);
+            long brickSum = 0;
+            for (int j = 0; j < diffs.size() - ladders; j++) {
+                brickSum += diffs.get(j);
+            }
+
+            if (brickSum > bricks) {
+                return i - 1;
+            }
+        }
+
+        return n - 1;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int furthestBuilding(vector<int>& heights, int bricks, int ladders) {
+        int n = heights.size();
+
+        for (int i = 1; i < n; i++) {
+            if (ladders >= i) {
+                continue;
+            }
+
+            vector<int> diffs;
+            for (int j = 0; j < i; j++) {
+                if (heights[j + 1] > heights[j]) {
+                    diffs.push_back(heights[j + 1] - heights[j]);
+                }
+            }
+
+            sort(diffs.begin(), diffs.end());
+            long long brickSum = 0;
+            for (int j = 0; j < int(diffs.size()) - ladders; j++) {
+                brickSum += diffs[j];
+            }
+
+            if (brickSum > bricks) {
+                return i - 1;
+            }
+        }
+
+        return n - 1;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} heights
+     * @param {number} bricks
+     * @param {number} ladders
+     * @return {number}
+     */
+    furthestBuilding(heights, bricks, ladders) {
+        let n = heights.length;
+
+        for (let i = 1; i < n; i++) {
+            if (ladders >= i) {
+                continue;
+            }
+
+            let diffs = [];
+            for (let j = 0; j < i; j++) {
+                if (heights[j + 1] > heights[j]) {
+                    diffs.push(heights[j + 1] - heights[j]);
+                }
+            }
+
+            diffs.sort((a, b) => a - b);
+            let brickSum = 0;
+            for (let j = 0; j < diffs.length - ladders; j++) {
+                brickSum += diffs[j];
+            }
+
+            if (brickSum > bricks) {
+                return i - 1;
+            }
+        }
+
+        return n - 1;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n ^ 2 \log n)$
+* Space complexity: $O(n)$
+
+---
+
+## 2. Binary Search On Buildings
+
+::tabs-start
+
+```python
+class Solution:
+    def furthestBuilding(self, heights: List[int], bricks: int, ladders: int) -> int:
+        def canReach(mid):
+            diffs = []
+            for i in range(mid):
+                if heights[i + 1] > heights[i]:
+                    diffs.append(heights[i + 1] - heights[i])
+
+            diffs.sort()
+            brickSum = 0
+            for j in range(len(diffs) - ladders):
+                brickSum += diffs[j]
+                if brickSum > bricks:
+                    return False
+
+            return True
+
+        l, r = ladders - 1, len(heights) - 1
+        while l <= r:
+            mid = (l + r) // 2
+            if canReach(mid):
+                l = mid + 1
+            else:
+                r = mid - 1
+
+        return l - 1
+```
+
+```java
+public class Solution {
+    public int furthestBuilding(int[] heights, int bricks, int ladders) {
+        int l = ladders - 1, r = heights.length - 1;
+
+        while (l <= r) {
+            int mid = (l + r) / 2;
+            if (canReach(heights, mid, bricks, ladders)) {
+                l = mid + 1;
+            } else {
+                r = mid - 1;
+            }
+        }
+
+        return l - 1;
+    }
+
+    private boolean canReach(int[] heights, int mid, int bricks, int ladders) {
+        List<Integer> diffs = new ArrayList<>();
+
+        for (int i = 0; i < mid; i++) {
+            if (heights[i + 1] > heights[i]) {
+                diffs.add(heights[i + 1] - heights[i]);
+            }
+        }
+
+        Collections.sort(diffs);
+        int brickSum = 0;
+
+        for (int j = 0; j < diffs.size() - ladders; j++) {
+            brickSum += diffs.get(j);
+            if (brickSum > bricks) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int furthestBuilding(vector<int>& heights, int bricks, int ladders) {
+        int l = ladders - 1, r = heights.size() - 1;
+
+        while (l <= r) {
+            int mid = (l + r) / 2;
+            if (canReach(heights, mid, bricks, ladders)) {
+                l = mid + 1;
+            } else {
+                r = mid - 1;
+            }
+        }
+
+        return l - 1;
+    }
+
+private:
+    bool canReach(vector<int>& heights, int mid, int bricks, int ladders) {
+        vector<int> diffs;
+
+        for (int i = 0; i < mid; i++) {
+            if (heights[i + 1] > heights[i]) {
+                diffs.push_back(heights[i + 1] - heights[i]);
+            }
+        }
+
+        sort(diffs.begin(), diffs.end());
+        long long brickSum = 0;
+
+        for (int j = 0; j < int(diffs.size()) - ladders; j++) {
+            brickSum += diffs[j];
+            if (brickSum > bricks) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} heights
+     * @param {number} bricks
+     * @param {number} ladders
+     * @return {number}
+     */
+    furthestBuilding(heights, bricks, ladders) {
+        let l = ladders - 1, r = heights.length - 1;
+
+        const canReach = (mid) => {
+            let diffs = [];
+            for (let i = 0; i < mid; i++) {
+                if (heights[i + 1] > heights[i]) {
+                    diffs.push(heights[i + 1] - heights[i]);
+                }
+            }
+
+            diffs.sort((a, b) => a - b);
+            let brickSum = 0;
+
+            for (let j = 0; j < diffs.length - ladders; j++) {
+                brickSum += diffs[j];
+                if (brickSum > bricks) {
+                    return false;
+                }
+            }
+
+            return true;
+        };
+
+        while (l <= r) {
+            let mid = Math.floor((l + r) / 2);
+            if (canReach(mid)) {
+                l = mid + 1;
+            } else {
+                r = mid - 1;
+            }
+        }
+
+        return l - 1;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n \log ^ 2 n)$
+* Space complexity: $O(n)$
+
+---
+
+## 3. Binary Search On Buildings (Optimal)
+
+::tabs-start
+
+```python
+class Solution:
+    def furthestBuilding(self, heights: List[int], bricks: int, ladders: int) -> int:
+        diffs = []
+        for i in range(1, len(heights)):
+            if heights[i] > heights[i - 1]:
+                diffs.append((heights[i] - heights[i - 1], i))
+
+        diffs.sort(reverse=True)
+
+        def canReach(index):
+            useLadders = useBricks = 0
+            for diff, i in diffs:
+                if i > index:
+                    continue
+
+                if useLadders < ladders:
+                    useLadders += 1
+                else:
+                    useBricks += diff
+                    if useBricks > bricks:
+                        return False
+            return True
+
+        l, r = 1, len(heights) - 1
+        while l <= r:
+            mid = (l + r) >> 1
+            if canReach(mid):
+                l = mid + 1
+            else:
+                r = mid - 1
+        return l - 1
+```
+
+```java
+public class Solution {
+    public int furthestBuilding(int[] heights, int bricks, int ladders) {
+        List<int[]> diffs = new ArrayList<>();
+        for (int i = 1; i < heights.length; i++) {
+            if (heights[i] > heights[i - 1]) {
+                diffs.add(new int[]{heights[i] - heights[i - 1], i});
+            }
+        }
+
+        diffs.sort((a, b) -> Integer.compare(b[0], a[0]));
+
+        int l = 1, r = heights.length - 1;
+        while (l <= r) {
+            int mid = (l + r) >> 1;
+            if (canReach(diffs, mid, bricks, ladders)) {
+                l = mid + 1;
+            } else {
+                r = mid - 1;
+            }
+        }
+
+        return l - 1;
+    }
+
+    private boolean canReach(List<int[]> diffs, int index, int bricks, int ladders) {
+        int useLadders = 0;
+        long useBricks = 0;
+        for (int[] diff : diffs) {
+            int jump = diff[0], i = diff[1];
+
+            if (i > index) continue;
+
+            if (useLadders < ladders) {
+                useLadders++;
+            } else {
+                useBricks += jump;
+                if (useBricks > bricks) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int furthestBuilding(vector<int>& heights, int bricks, int ladders) {
+        vector<pair<int, int>> diffs;
+        for (int i = 1; i < heights.size(); i++) {
+            if (heights[i] > heights[i - 1]) {
+                diffs.emplace_back(heights[i] - heights[i - 1], i);
+            }
+        }
+
+        sort(diffs.rbegin(), diffs.rend()); // Sort in descending order
+
+        int l = 1, r = heights.size() - 1;
+        while (l <= r) {
+            int mid = (l + r) >> 1;
+            if (canReach(diffs, mid, bricks, ladders)) {
+                l = mid + 1;
+            } else {
+                r = mid - 1;
+            }
+        }
+
+        return l - 1;
+    }
+
+private:
+    bool canReach(vector<pair<int, int>>& diffs, int index, int bricks, int ladders) {
+        int useLadders = 0;
+        long long useBricks = 0;
+        for (auto& diff : diffs) {
+            int jump = diff.first, i = diff.second;
+
+            if (i > index) continue;
+
+            if (useLadders < ladders) {
+                useLadders++;
+            } else {
+                useBricks += jump;
+                if (useBricks > bricks) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} heights
+     * @param {number} bricks
+     * @param {number} ladders
+     * @return {number}
+     */
+    furthestBuilding(heights, bricks, ladders) {
+        let diffs = [];
+        for (let i = 1; i < heights.length; i++) {
+            if (heights[i] > heights[i - 1]) {
+                diffs.push([heights[i] - heights[i - 1], i]);
+            }
+        }
+
+        diffs.sort((a, b) => b[0] - a[0]);
+
+        const canReach = (index) => {
+            let useLadders = 0, useBricks = 0;
+            for (let [diff, i] of diffs) {
+                if (i > index) continue;
+
+                if (useLadders < ladders) {
+                    useLadders++;
+                } else {
+                    useBricks += diff;
+                    if (useBricks > bricks) {
+                        return false;
+                    }
+                }
+            }
+            return true;
+        };
+
+        let l = 1, r = heights.length - 1;
+        while (l <= r) {
+            let mid = (l + r) >> 1;
+            if (canReach(mid)) {
+                l = mid + 1;
+            } else {
+                r = mid - 1;
+            }
+        }
+
+        return l - 1;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n \log n)$
+* Space complexity: $O(n)$
+
+---
+
+## 4. Max-Heap
+
+::tabs-start
+
+```python
+class Solution:
+    def furthestBuilding(self, heights: List[int], bricks: int, ladders: int) -> int:
+        heap = []  # Max heap of bricks used
+
+        for i in range(len(heights) - 1):
+            diff = heights[i + 1] - heights[i]
+            if diff <= 0:
+                continue
+
+            bricks -= diff
+            heapq.heappush(heap, -diff)
+
+            if bricks < 0:
+                if ladders == 0:
+                    return i
+                ladders -= 1
+                bricks += -heapq.heappop(heap)
+
+        return len(heights) - 1
+```
+
+```java
+public class Solution {
+    public int furthestBuilding(int[] heights, int bricks, int ladders) {
+        PriorityQueue<Integer> maxHeap = new PriorityQueue<>((a, b) -> b - a);
+
+        for (int i = 0; i < heights.length - 1; i++) {
+            int diff = heights[i + 1] - heights[i];
+            if (diff <= 0) continue;
+
+            bricks -= diff;
+            maxHeap.offer(diff);
+
+            if (bricks < 0) {
+                if (ladders == 0) return i;
+                ladders--;
+                bricks += maxHeap.poll();
+            }
+        }
+
+        return heights.length - 1;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int furthestBuilding(vector<int>& heights, int bricks, int ladders) {
+        priority_queue<int> maxHeap;
+
+        for (int i = 0; i < heights.size() - 1; i++) {
+            int diff = heights[i + 1] - heights[i];
+            if (diff <= 0) continue;
+
+            bricks -= diff;
+            maxHeap.push(diff);
+
+            if (bricks < 0) {
+                if (ladders == 0) return i;
+                ladders--;
+                bricks += maxHeap.top();
+                maxHeap.pop();
+            }
+        }
+
+        return heights.size() - 1;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} heights
+     * @param {number} bricks
+     * @param {number} ladders
+     * @return {number}
+     */
+    furthestBuilding(heights, bricks, ladders) {
+        const maxHeap = new MaxPriorityQueue();
+
+        for (let i = 0; i < heights.length - 1; i++) {
+            let diff = heights[i + 1] - heights[i];
+            if (diff <= 0) continue;
+
+            bricks -= diff;
+            maxHeap.enqueue(diff);
+
+            if (bricks < 0) {
+                if (ladders === 0) return i;
+                ladders--;
+                bricks += maxHeap.dequeue().element;
+            }
+        }
+
+        return heights.length - 1;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n \log n)$
+* Space complexity: $O(n)$
+
+---
+
+## 5. Min-Heap
+
+::tabs-start
+
+```python
+class Solution:
+    def furthestBuilding(self, heights: List[int], bricks: int, ladders: int) -> int:
+        minHeap = []
+
+        for i in range(len(heights) - 1):
+            diff = heights[i + 1] - heights[i]
+            if diff <= 0:
+                continue
+
+            heapq.heappush(minHeap, diff)
+            if len(minHeap) > ladders:
+                bricks -= heapq.heappop(minHeap)
+                if bricks < 0:
+                    return i
+
+        return len(heights) - 1
+```
+
+```java
+public class Solution {
+    public int furthestBuilding(int[] heights, int bricks, int ladders) {
+        PriorityQueue<Integer> minHeap = new PriorityQueue<>();
+
+        for (int i = 0; i < heights.length - 1; i++) {
+            int diff = heights[i + 1] - heights[i];
+            if (diff <= 0) continue;
+
+            minHeap.offer(diff);
+            if (minHeap.size() > ladders) {
+                bricks -= minHeap.poll();
+                if (bricks < 0) return i;
+            }
+        }
+
+        return heights.length - 1;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int furthestBuilding(vector<int>& heights, int bricks, int ladders) {
+        priority_queue<int, vector<int>, greater<int>> minHeap;
+
+        for (int i = 0; i < int(heights.size()) - 1; i++) {
+            int diff = heights[i + 1] - heights[i];
+            if (diff <= 0) continue;
+
+            minHeap.push(diff);
+            if (minHeap.size() > ladders) {
+                bricks -= minHeap.top(); minHeap.pop();
+                if (bricks < 0) return i;
+            }
+        }
+
+        return int(heights.size()) - 1;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} heights
+     * @param {number} bricks
+     * @param {number} ladders
+     * @return {number}
+     */
+    furthestBuilding(heights, bricks, ladders) {
+        const minHeap = new MinPriorityQueue();
+
+        for (let i = 0; i < heights.length - 1; i++) {
+            let diff = heights[i + 1] - heights[i];
+            if (diff <= 0) continue;
+
+            minHeap.enqueue(diff);
+            if (minHeap.size() > ladders) {
+                bricks -= minHeap.dequeue().element;
+                if (bricks < 0) return i;
+            }
+        }
+
+        return heights.length - 1;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n \log n)$
+* Space complexity: $O(n)$
\ No newline at end of file
diff --git a/articles/maximum-element-after-decreasing-and-rearranging.md b/articles/maximum-element-after-decreasing-and-rearranging.md
new file mode 100644
index 000000000..b7c01b0db
--- /dev/null
+++ b/articles/maximum-element-after-decreasing-and-rearranging.md
@@ -0,0 +1,158 @@
+## 1. Greedy + Sorting
+
+::tabs-start
+
+```python
+class Solution:
+    def maximumElementAfterDecrementingAndRearranging(self, arr: List[int]) -> int:
+        arr.sort()
+        prev = 0
+        for num in arr:
+            prev = min(prev + 1, num)
+        return prev
+```
+
+```java
+public class Solution {
+    public int maximumElementAfterDecrementingAndRearranging(int[] arr) {
+        Arrays.sort(arr);
+        int prev = 0;
+        for (int num : arr) {
+            prev = Math.min(prev + 1, num);
+        }
+        return prev;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int maximumElementAfterDecrementingAndRearranging(vector<int>& arr) {
+        sort(arr.begin(), arr.end());
+        int prev = 0;
+        for (int num : arr) {
+            prev = min(prev + 1, num);
+        }
+        return prev;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} arr
+     * @return {number}
+     */
+    maximumElementAfterDecrementingAndRearranging(arr) {
+        arr.sort((a, b) => a - b);
+        let prev = 0;
+        for (let num of arr) {
+            prev = Math.min(prev + 1, num);
+        }
+        return prev;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n \log n)$
+* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm.
+
+---
+
+## 2. Greedy
+
+::tabs-start
+
+```python
+class Solution:
+    def maximumElementAfterDecrementingAndRearranging(self, arr: List[int]) -> int:
+        n = len(arr)
+        count = [0] * (n + 1)
+
+        for num in arr:
+            count[min(num, n)] += 1
+
+        prev = 1
+        for num in range(2, n + 1):
+            prev = min(prev + count[num], num)
+
+        return prev
+```
+
+```java
+public class Solution {
+    public int maximumElementAfterDecrementingAndRearranging(int[] arr) {
+        int n = arr.length;
+        int[] count = new int[n + 1];
+
+        for (int num : arr) {
+            count[Math.min(num, n)]++;
+        }
+
+        int prev = 1;
+        for (int num = 2; num <= n; num++) {
+            prev = Math.min(prev + count[num], num);
+        }
+
+        return prev;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int maximumElementAfterDecrementingAndRearranging(vector<int>& arr) {
+        int n = arr.size();
+        vector<int> count(n + 1, 0);
+
+        for (int num : arr) {
+            count[min(num, n)]++;
+        }
+
+        int prev = 1;
+        for (int num = 2; num <= n; num++) {
+            prev = min(prev + count[num], num);
+        }
+
+        return prev;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} arr
+     * @return {number}
+     */
+    maximumElementAfterDecrementingAndRearranging(arr) {
+        let n = arr.length;
+        let count = new Array(n + 1).fill(0);
+
+        for (let num of arr) {
+            count[Math.min(num, n)]++;
+        }
+
+        let prev = 1;
+        for (let num = 2; num <= n; num++) {
+            prev = Math.min(prev + count[num], num);
+        }
+
+        return prev;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(n)$
\ No newline at end of file
diff --git a/articles/maximum-length-of-pair-chain.md b/articles/maximum-length-of-pair-chain.md
new file mode 100644
index 000000000..2855ede51
--- /dev/null
+++ b/articles/maximum-length-of-pair-chain.md
@@ -0,0 +1,556 @@
+## 1. Recursion
+
+::tabs-start
+
+```python
+class Solution:
+    def findLongestChain(self, pairs: List[List[int]]) -> int:
+        n = len(pairs)
+        pairs.sort(key=lambda x: x[1])
+
+        def dfs(i, j):
+            if i == n:
+                return 0
+
+            res = dfs(i + 1, j)
+            if j == -1 or pairs[j][1] < pairs[i][0]:
+                res = max(res, 1 + dfs(i + 1, i))
+
+            return res
+
+        return dfs(0, -1)
+```
+
+```java
+public class Solution {
+    public int findLongestChain(int[][] pairs) {
+        int n = pairs.length;
+        Arrays.sort(pairs, (a, b) -> Integer.compare(a[1], b[1]));
+        return dfs(pairs, 0, -1, n);
+    }
+
+    private int dfs(int[][] pairs, int i, int j, int n) {
+        if (i == n) {
+            return 0;
+        }
+
+        int res = dfs(pairs, i + 1, j, n);
+        if (j == -1 || pairs[j][1] < pairs[i][0]) {
+            res = Math.max(res, 1 + dfs(pairs, i + 1, i, n));
+        }
+
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int findLongestChain(vector<vector<int>>& pairs) {
+        int n = pairs.size();
+        sort(pairs.begin(), pairs.end(), [](const auto& a, const auto& b) {
+            return a[1] < b[1];
+        });
+
+        return dfs(pairs, 0, -1, n);
+    }
+
+private:
+    int dfs(vector<vector<int>>& pairs, int i, int j, int n) {
+        if (i == n) {
+            return 0;
+        }
+
+        int res = dfs(pairs, i + 1, j, n);
+        if (j == -1 || pairs[j][1] < pairs[i][0]) {
+            res = max(res, 1 + dfs(pairs, i + 1, i, n));
+        }
+
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} pairs
+     * @return {number}
+     */
+    findLongestChain(pairs) {
+        pairs.sort((a, b) => a[1] - b[1]);
+        let n = pairs.length;
+
+        const dfs = (i, j) => {
+            if (i === n) {
+                return 0;
+            }
+
+            let res = dfs(i + 1, j);
+            if (j === -1 || pairs[j][1] < pairs[i][0]) {
+                res = Math.max(res, 1 + dfs(i + 1, i));
+            }
+
+            return res;
+        };
+
+        return dfs(0, -1);
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(2 ^ n)$
+* Space complexity: $O(n)$ for recursion stack.
+
+---
+
+## 2. Dynamic Programming (Top-Down)
+
+::tabs-start
+
+```python
+class Solution:
+    def findLongestChain(self, pairs: List[List[int]]) -> int:
+        n = len(pairs)
+        pairs.sort(key=lambda x: x[1])
+        dp = [[-1] * (n + 1) for _ in range(n)]
+
+        def dfs(i, j):
+            if i == n:
+                return 0
+            if dp[i][j + 1] != -1:
+                return dp[i][j + 1]
+
+            res = dfs(i + 1, j)
+            if j == -1 or pairs[j][1] < pairs[i][0]:
+                res = max(res, 1 + dfs(i + 1, i))
+            
+            dp[i][j + 1] = res
+            return res
+
+        return dfs(0, -1)
+```
+
+```java
+public class Solution {
+    private int[][] dp;
+
+    public int findLongestChain(int[][] pairs) {
+        int n = pairs.length;
+        Arrays.sort(pairs, (a, b) -> Integer.compare(a[1], b[1]));
+        dp = new int[n][n + 1];
+
+        for (int[] row : dp) {
+            Arrays.fill(row, -1);
+        }
+
+        return dfs(pairs, 0, -1, n);
+    }
+
+    private int dfs(int[][] pairs, int i, int j, int n) {
+        if (i == n) {
+            return 0;
+        }
+        if (dp[i][j + 1] != -1) {
+            return dp[i][j + 1];
+        }
+
+        int res = dfs(pairs, i + 1, j, n);
+        if (j == -1 || pairs[j][1] < pairs[i][0]) {
+            res = Math.max(res, 1 + dfs(pairs, i + 1, i, n));
+        }
+
+        dp[i][j + 1] = res;
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    vector<vector<int>> dp;
+
+    int findLongestChain(vector<vector<int>>& pairs) {
+        int n = pairs.size();
+        sort(pairs.begin(), pairs.end(), [](const auto& a, const auto& b) {
+            return a[1] < b[1];
+        });
+
+        dp = vector<vector<int>>(n, vector<int>(n + 1, -1));
+        return dfs(pairs, 0, -1, n);
+    }
+
+private:
+    int dfs(vector<vector<int>>& pairs, int i, int j, int n) {
+        if (i == n) {
+            return 0;
+        }
+        if (dp[i][j + 1] != -1) {
+            return dp[i][j + 1];
+        }
+
+        int res = dfs(pairs, i + 1, j, n);
+        if (j == -1 || pairs[j][1] < pairs[i][0]) {
+            res = max(res, 1 + dfs(pairs, i + 1, i, n));
+        }
+
+        dp[i][j + 1] = res;
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} pairs
+     * @return {number}
+     */
+    findLongestChain(pairs) {
+        pairs.sort((a, b) => a[1] - b[1]);
+        let n = pairs.length;
+        let dp = Array.from({ length: n }, () => new Array(n + 1).fill(-1));
+
+        const dfs = (i, j) => {
+            if (i === n) {
+                return 0;
+            }
+            if (dp[i][j + 1] !== -1) {
+                return dp[i][j + 1];
+            }
+
+            let res = dfs(i + 1, j);
+            if (j === -1 || pairs[j][1] < pairs[i][0]) {
+                res = Math.max(res, 1 + dfs(i + 1, i));
+            }
+
+            dp[i][j + 1] = res;
+            return res;
+        };
+
+        return dfs(0, -1);
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n ^ 2)$
+* Space complexity: $O(n ^ 2)$
+
+---
+
+## 3. Dynamic Programming (Bottom-Up)
+
+::tabs-start
+
+```python
+class Solution:
+    def findLongestChain(self, pairs: List[List[int]]) -> int:
+        n = len(pairs)
+        pairs.sort(key=lambda x: x[1])
+        dp = [1] * n  
+
+        for i in range(n):
+            for j in range(i):
+                if pairs[j][1] < pairs[i][0]:
+                    dp[i] = max(dp[i], dp[j] + 1)
+
+        return max(dp)
+```
+
+```java
+public class Solution {
+    public int findLongestChain(int[][] pairs) {
+        int n = pairs.length;
+        Arrays.sort(pairs, (a, b) -> Integer.compare(a[1], b[1]));
+        int[] dp = new int[n];
+        Arrays.fill(dp, 1);
+
+        for (int i = 0; i < n; i++) {
+            for (int j = 0; j < i; j++) {
+                if (pairs[j][1] < pairs[i][0]) {
+                    dp[i] = Math.max(dp[i], dp[j] + 1);
+                }
+            }
+        }
+
+        return Arrays.stream(dp).max().getAsInt();
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int findLongestChain(vector<vector<int>>& pairs) {
+        int n = pairs.size();
+        sort(pairs.begin(), pairs.end(), [](const auto& a, const auto& b) {
+            return a[1] < b[1];
+        });
+
+        vector<int> dp(n, 1);
+
+        for (int i = 0; i < n; i++) {
+            for (int j = 0; j < i; j++) {
+                if (pairs[j][1] < pairs[i][0]) {
+                    dp[i] = max(dp[i], dp[j] + 1);
+                }
+            }
+        }
+
+        return *max_element(dp.begin(), dp.end());
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} pairs
+     * @return {number}
+     */
+    findLongestChain(pairs) {
+        let n = pairs.length;
+        pairs.sort((a, b) => a[1] - b[1]);
+        let dp = new Array(n).fill(1);
+
+        for (let i = 0; i < n; i++) {
+            for (let j = 0; j < i; j++) {
+                if (pairs[j][1] < pairs[i][0]) {
+                    dp[i] = Math.max(dp[i], dp[j] + 1);
+                }
+            }
+        }
+
+        return Math.max(...dp);
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n ^ 2)$
+* Space complexity: $O(n)$
+
+---
+
+## 4. Dynamic Programming (Bianry Search)
+
+::tabs-start
+
+```python
+class Solution:
+    def findLongestChain(self, pairs: List[List[int]]) -> int:
+        pairs.sort(key=lambda x: x[0])
+        dp = []
+
+        for a, b in pairs:
+            pos = bisect_left(dp, a)
+            if pos == len(dp):
+                dp.append(b)
+            else:
+                dp[pos] = min(dp[pos], b)
+
+        return len(dp)
+```
+
+```java
+public class Solution {
+    public int findLongestChain(int[][] pairs) {
+        Arrays.sort(pairs, Comparator.comparingInt(a -> a[0]));
+        List<Integer> dp = new ArrayList<>();
+
+        for (int[] pair : pairs) {
+            int pos = binarySearch(dp, pair[0]);
+            if (pos == dp.size()) {
+                dp.add(pair[1]);
+            } else {
+                dp.set(pos, Math.min(dp.get(pos), pair[1]));
+            }
+        }
+
+        return dp.size();
+    }
+
+    private int binarySearch(List<Integer> dp, int target) {
+        int left = 0, right = dp.size() - 1;
+        while (left <= right) {
+            int mid = left + (right - left) / 2;
+            if (dp.get(mid) < target) {
+                left = mid + 1;
+            } else {
+                right = mid - 1;
+            }
+        }
+        return left;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int findLongestChain(vector<vector<int>>& pairs) {
+        sort(pairs.begin(), pairs.end());
+        vector<int> dp;
+
+        for (auto& pair : pairs) {
+            auto it = lower_bound(dp.begin(), dp.end(), pair[0]);
+            if (it == dp.end()) {
+                dp.push_back(pair[1]);
+            } else {
+                *it = min(*it, pair[1]);
+            }
+        }
+
+        return dp.size();
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} pairs
+     * @return {number}
+     */
+    findLongestChain(pairs) {
+        pairs.sort((a, b) => a[0] - b[0]);
+        let dp = [];
+
+        const binarySearch = (target) => {
+            let left = 0, right = dp.length - 1;
+            while (left <= right) {
+                let mid = Math.floor((left + right) / 2);
+                if (dp[mid] < target) {
+                    left = mid + 1;
+                } else {
+                    right = mid - 1;
+                }
+            }
+            return left;
+        };
+
+        for (let i = 0; i < pairs.length; i++) {
+            let pos = binarySearch(pairs[i][0]);
+            if (pos === dp.length) {
+                dp.push(pairs[i][1]);
+            } else {
+                dp[pos] = Math.min(dp[pos], pairs[i][1]);
+            }
+        }
+
+        return dp.length;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n \log n)$
+* Space complexity: $O(n)$
+
+---
+
+## 5. Greedy
+
+::tabs-start
+
+```python
+class Solution:
+    def findLongestChain(self, pairs: List[List[int]]) -> int:
+        pairs.sort(key=lambda p: p[1])
+        length = 1
+        end = pairs[0][1]
+
+        for i in range(1, len(pairs)):
+            if end < pairs[i][0]:
+                length += 1
+                end = pairs[i][1]
+
+        return length
+```
+
+```java
+public class Solution {
+    public int findLongestChain(int[][] pairs) {
+        Arrays.sort(pairs, (a, b) -> Integer.compare(a[1], b[1]));
+        int length = 1;
+        int end = pairs[0][1];
+
+        for (int i = 1; i < pairs.length; i++) {
+            if (end < pairs[i][0]) {
+                length++;
+                end = pairs[i][1];
+            }
+        }
+
+        return length;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int findLongestChain(vector<vector<int>>& pairs) {
+        sort(pairs.begin(), pairs.end(), [](const auto& a, const auto& b) {
+            return a[1] < b[1];
+        });
+
+        int length = 1, end = pairs[0][1];
+
+        for (int i = 1; i < pairs.size(); i++) {
+            if (end < pairs[i][0]) {
+                length++;
+                end = pairs[i][1];
+            }
+        }
+
+        return length;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} pairs
+     * @return {number}
+     */
+    findLongestChain(pairs) {
+        pairs.sort((a, b) => a[1] - b[1]);
+        let length = 1;
+        let end = pairs[0][1];
+
+        for (let i = 1; i < pairs.length; i++) {
+            if (end < pairs[i][0]) {
+                length++;
+                end = pairs[i][1];
+            }
+        }
+
+        return length;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n\log n)$
+* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm.
\ No newline at end of file
diff --git a/articles/minimum-deletions-to-make-character-frequencies-unique.md b/articles/minimum-deletions-to-make-character-frequencies-unique.md
new file mode 100644
index 000000000..60c9564fa
--- /dev/null
+++ b/articles/minimum-deletions-to-make-character-frequencies-unique.md
@@ -0,0 +1,348 @@
+## 1. Hash Set
+
+::tabs-start
+
+```python
+class Solution:
+    def minDeletions(self, s: str) -> int:
+        count = [0] * 26
+        for c in s:
+            count[ord(c) - ord('a')] += 1
+
+        used_freq = set()
+        res = 0
+        for freq in count:
+            while freq > 0 and freq in used_freq:
+                freq -= 1
+                res += 1
+            used_freq.add(freq)
+
+        return res
+```
+
+```java
+class Solution {
+    public int minDeletions(String s) {
+        int[] count = new int[26];
+        for (int i = 0; i < s.length(); i++) {
+            count[s.charAt(i) - 'a']++;
+        }
+
+        Set<Integer> usedFreq = new HashSet<>();
+        int res = 0;
+
+        for (int freq : count) {
+            while (freq > 0 && usedFreq.contains(freq)) {
+                freq--;
+                res++;
+            }
+            usedFreq.add(freq);
+        }
+
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int minDeletions(string s) {
+        vector<int> count(26, 0);
+        for (char& c : s) {
+            count[c - 'a']++;
+        }
+
+        unordered_set<int> usedFreq;
+        int res = 0;
+
+        for (int& freq : count) {
+            while (freq > 0 && usedFreq.count(freq)) {
+                freq--;
+                res++;
+            }
+            usedFreq.insert(freq);
+        }
+
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {string} s
+     * @return {number}
+     */
+    minDeletions(s) {
+        let count = new Array(26).fill(0);
+        for (let c of s) {
+            count[c.charCodeAt(0) - 'a'.charCodeAt(0)]++;
+        }
+
+        let usedFreq = new Set();
+        let res = 0;
+
+        for (let freq of count) {
+            while (freq > 0 && usedFreq.has(freq)) {
+                freq--;
+                res++;
+            }
+            usedFreq.add(freq);
+        }
+
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n + m ^ 2)$
+* Space complexity: $O(m)$
+
+> Where $n$ is the length of the string $s$ and $m$ is the total number of unique frequncies possible.
+
+---
+
+## 2. Max-Heap
+
+::tabs-start
+
+```python
+class Solution:
+    def minDeletions(self, s: str) -> int:
+        freq = Counter(s)
+        maxHeap = [-f for f in freq.values()]
+        heapq.heapify(maxHeap)
+
+        res = 0
+        while len(maxHeap) > 1:
+            top = -heapq.heappop(maxHeap)
+            if top == -maxHeap[0]:
+                if top - 1 > 0:
+                    heapq.heappush(maxHeap, -(top - 1))
+                res += 1
+
+        return res
+```
+
+```java
+public class Solution {
+    public int minDeletions(String s) {
+        Map<Character, Integer> freq = new HashMap<>();
+        for (int i = 0; i < s.length(); i++) {
+            char c = s.charAt(i);
+            freq.put(c, freq.getOrDefault(c, 0) + 1);
+        }
+
+        PriorityQueue<Integer> maxHeap = new PriorityQueue<>((a, b) -> b - a);
+        maxHeap.addAll(freq.values());
+
+        int res = 0;
+        while (maxHeap.size() > 1) {
+            int top = maxHeap.poll();
+            if (top == maxHeap.peek()) {
+                if (top - 1 > 0) {
+                    maxHeap.add(top - 1);
+                }
+                res++;
+            }
+        }
+
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int minDeletions(string s) {
+        unordered_map<char, int> freq;
+        for (char& c : s) {
+            freq[c]++;
+        }
+
+        priority_queue<int> maxHeap;
+        for (auto& f : freq) {
+            maxHeap.push(f.second);
+        }
+
+        int res = 0;
+        while (maxHeap.size() > 1) {
+            int top = maxHeap.top();
+            maxHeap.pop();
+            if (top == maxHeap.top()) {
+                if (top - 1 > 0) {
+                    maxHeap.push(top - 1);
+                }
+                res++;
+            }
+        }
+
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {string} s
+     * @return {number}
+     */
+    minDeletions(s) {
+        let freq = new Map();
+        for (let c of s) {
+            freq.set(c, (freq.get(c) || 0) + 1);
+        }
+
+        const maxHeap = new MaxPriorityQueue();
+        for (let value of freq.values()) {
+            maxHeap.enqueue(value);
+        }
+
+        let res = 0;
+        while (maxHeap.size() > 1) {
+            let top = maxHeap.dequeue().element;
+            if (maxHeap.front().element === top) {
+                if (top - 1 > 0) {
+                    maxHeap.enqueue(top - 1);
+                }
+                res++;
+            }
+        }
+
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n + m ^ 2 \log m)$
+* Space complexity: $O(m)$
+
+> Where $n$ is the length of the string $s$ and $m$ is the total number of unique frequncies possible.
+
+---
+
+## 3. Sorting
+
+::tabs-start
+
+```python
+class Solution:
+    def minDeletions(self, s: str) -> int:
+        count = [0] * 26
+        for c in s:
+            count[ord(c) - ord('a')] += 1
+
+        count.sort(reverse=True)
+        res = 0
+        maxAllowedFreq = count[0]
+
+        for freq in count:
+            if freq > maxAllowedFreq:
+                res += freq - maxAllowedFreq
+                freq = maxAllowedFreq
+            maxAllowedFreq = max(0, freq - 1)
+
+        return res
+```
+
+```java
+public class Solution {
+    public int minDeletions(String s) {
+        int[] count = new int[26];
+        for (int i = 0; i < s.length(); i++) {
+            count[s.charAt(i) - 'a']++;
+        }
+
+        Arrays.sort(count);
+        int res = 0;
+        int maxAllowedFreq = count[25];
+
+        for (int i = 25; i >= 0; i--) {
+            if (count[i] > maxAllowedFreq) {
+                res += count[i] - maxAllowedFreq;
+                count[i] = maxAllowedFreq;
+            }
+            maxAllowedFreq = Math.max(0, count[i] - 1);
+        }
+
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int minDeletions(string s) {
+        vector<int> count(26, 0);
+        for (char& c : s) {
+            count[c - 'a']++;
+        }
+
+        sort(count.begin(), count.end(), greater<int>());
+        int res = 0;
+        int maxAllowedFreq = count[0];
+
+        for (int& freq : count) {
+            if (freq > maxAllowedFreq) {
+                res += freq - maxAllowedFreq;
+                freq = maxAllowedFreq;
+            }
+            maxAllowedFreq = max(0, freq - 1);
+        }
+
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {string} s
+     * @return {number}
+     */
+    minDeletions(s) {
+        let count = new Array(26).fill(0);
+        for (let c of s) {
+            count[c.charCodeAt(0) - 'a'.charCodeAt(0)]++;
+        }
+
+        count.sort((a, b) => b - a);
+
+        let res = 0;
+        let maxAllowedFreq = count[0];
+
+        for (let i = 0; i < 26; i++) {
+            if (count[i] > maxAllowedFreq) {
+                res += count[i] - maxAllowedFreq;
+                count[i] = maxAllowedFreq;
+            }
+            maxAllowedFreq = Math.max(0, count[i] - 1);
+        }
+
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n + m \log m)$
+* Space complexity: $O(m)$
+
+> Where $n$ is the length of the string $s$ and $m$ is the total number of unique frequncies possible.
\ No newline at end of file
diff --git a/articles/remove-colored-pieces-if-both-neighbors-are-the-same-color.md b/articles/remove-colored-pieces-if-both-neighbors-are-the-same-color.md
new file mode 100644
index 000000000..156cbb636
--- /dev/null
+++ b/articles/remove-colored-pieces-if-both-neighbors-are-the-same-color.md
@@ -0,0 +1,322 @@
+## 1. Brute Force
+
+::tabs-start
+
+```python
+class Solution:
+    def winnerOfGame(self, colors: str) -> bool:
+        s = list(colors)
+
+        def removeChar(c):
+            for i in range(1, len(s) - 1):
+                if s[i] != c:
+                    continue
+
+                if s[i] == s[i + 1] == s[i - 1]:
+                    s.pop(i)
+                    return True
+            return False
+
+        while True:
+            if not removeChar('A'):
+                return False
+            if not removeChar('B'):
+                return True
+
+        return False
+```
+
+```java
+public class Solution {
+    public boolean winnerOfGame(String colors) {
+        StringBuilder s = new StringBuilder(colors);
+
+        while (true) {
+            if (!removeChar(s, 'A')) return false;
+            if (!removeChar(s, 'B')) return true;
+        }
+    }
+
+    private boolean removeChar(StringBuilder s, char c) {
+        for (int i = 1; i < s.length() - 1; i++) {
+            if (s.charAt(i) != c) continue;
+
+            if (s.charAt(i - 1) == c && s.charAt(i + 1) == c) {
+                s.deleteCharAt(i);
+                return true;
+            }
+        }
+        return false;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    bool winnerOfGame(string colors) {
+        while (true) {
+            if (!removeChar(colors, 'A')) return false;
+            if (!removeChar(colors, 'B')) return true;
+        }
+    }
+
+private:
+    bool removeChar(string& s, char c) {
+        for (int i = 1; i < s.size() - 1; i++) {
+            if (s[i] != c) continue;
+
+            if (s[i - 1] == c && s[i + 1] == c) {
+                s.erase(i, 1);
+                return true;
+            }
+        }
+        return false;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {string} colors
+     * @return {boolean}
+     */
+    winnerOfGame(colors) {
+        let s = colors.split("");
+
+        const removeChar = (c) => {
+            for (let i = 1; i < s.length - 1; i++) {
+                if (s[i] !== c) continue;
+
+                if (s[i - 1] === c && s[i + 1] === c) {
+                    s.splice(i, 1);
+                    return true;
+                }
+            }
+            return false;
+        };
+
+        while (true) {
+            if (!removeChar('A')) return false;
+            if (!removeChar('B')) return true;
+        }
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n ^ 2)$
+* Space complexity: $O(n)$
+
+---
+
+## 2. Greedy + Two Pointers
+
+::tabs-start
+
+```python
+class Solution:
+    def winnerOfGame(self, colors: str) -> bool:
+        alice = bob = l = 0
+
+        for r in range(len(colors)):
+            if colors[l] != colors[r]:
+                l = r
+
+            extra = r - l - 1
+            if extra > 0:
+                if colors[l] == 'A':
+                    alice += 1
+                else:
+                    bob += 1
+
+        return alice > bob
+```
+
+```java
+public class Solution {
+    public boolean winnerOfGame(String colors) {
+        int alice = 0, bob = 0, l = 0;
+
+        for (int r = 0; r < colors.length(); r++) {
+            if (colors.charAt(l) != colors.charAt(r)) {
+                l = r;
+            }
+
+            int extra = r - l - 1;
+            if (extra > 0) {
+                if (colors.charAt(l) == 'A') {
+                    alice++;
+                } else {
+                    bob++;
+                }
+            }
+        }
+
+        return alice > bob;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    bool winnerOfGame(string colors) {
+        int alice = 0, bob = 0, l = 0;
+
+        for (int r = 0; r < colors.size(); r++) {
+            if (colors[l] != colors[r]) {
+                l = r;
+            }
+
+            int extra = r - l - 1;
+            if (extra > 0) {
+                if (colors[l] == 'A') {
+                    alice++;
+                } else {
+                    bob++;
+                }
+            }
+        }
+
+        return alice > bob;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {string} colors
+     * @return {boolean}
+     */
+    winnerOfGame(colors) {
+        let alice = 0, bob = 0, l = 0;
+
+        for (let r = 0; r < colors.length; r++) {
+            if (colors[l] !== colors[r]) {
+                l = r;
+            }
+
+            let extra = r - l - 1;
+            if (extra > 0) {
+                if (colors[l] === 'A') {
+                    alice++;
+                } else {
+                    bob++;
+                }
+            }
+        }
+
+        return alice > bob;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(1)$ extra space.
+
+---
+
+## 3. Greedy
+
+::tabs-start
+
+```python
+class Solution:
+    def winnerOfGame(self, colors: str) -> bool:
+        alice, bob = 0, 0
+
+        for i in range(1, len(colors) - 1):
+            if colors[i - 1] == colors[i] == colors[i + 1]:
+                if colors[i] == 'A':
+                    alice += 1
+                if colors[i] == 'B':
+                    bob += 1
+
+        return alice > bob
+```
+
+```java
+public class Solution {
+    public boolean winnerOfGame(String colors) {
+        int alice = 0, bob = 0;
+
+        for (int i = 1; i < colors.length() - 1; i++) {
+            if (colors.charAt(i - 1) == colors.charAt(i) && 
+                colors.charAt(i) == colors.charAt(i + 1)) {
+                if (colors.charAt(i) == 'A') {
+                    alice++;
+                }
+                if (colors.charAt(i) == 'B') {
+                    bob++;
+                }
+            }
+        }
+
+        return alice > bob;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    bool winnerOfGame(string colors) {
+        int alice = 0, bob = 0;
+
+        for (int i = 1; i < colors.size() - 1; i++) {
+            if (colors[i - 1] == colors[i] && colors[i] == colors[i + 1]) {
+                if (colors[i] == 'A') {
+                    alice++;
+                }
+                if (colors[i] == 'B') {
+                    bob++;
+                }
+            }
+        }
+
+        return alice > bob;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {string} colors
+     * @return {boolean}
+     */
+    winnerOfGame(colors) {
+        let alice = 0, bob = 0;
+
+        for (let i = 1; i < colors.length - 1; i++) {
+            if (colors[i - 1] === colors[i] && colors[i] === colors[i + 1]) {
+                if (colors[i] === 'A') {
+                    alice++;
+                }
+                if (colors[i] === 'B') {
+                    bob++;
+                }
+            }
+        }
+
+        return alice > bob;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(1)$ extra space.
\ No newline at end of file

From c043cbfa63363dabb5bd8bdfc332c020302449d6 Mon Sep 17 00:00:00 2001
From: Sri Hari <kataresrihari@gmail.com>
Date: Fri, 7 Feb 2025 22:00:32 +0530
Subject: [PATCH 06/13] Batch-5/Neetcode-ALL/Added-articles

---
 articles/number-of-laser-beams-in-a-bank.md | 110 ++++++++++++++++++++
 1 file changed, 110 insertions(+)
 create mode 100644 articles/number-of-laser-beams-in-a-bank.md

diff --git a/articles/number-of-laser-beams-in-a-bank.md b/articles/number-of-laser-beams-in-a-bank.md
new file mode 100644
index 000000000..598d7fbb2
--- /dev/null
+++ b/articles/number-of-laser-beams-in-a-bank.md
@@ -0,0 +1,110 @@
+## 1. Counting
+
+::tabs-start
+
+```python
+class Solution:
+    def numberOfBeams(self, bank: List[str]) -> int:
+        prev = bank[0].count("1")
+        res = 0
+
+        for i in range(1, len(bank)):
+            curr = bank[i].count("1")
+            if curr:
+                res += prev * curr
+                prev = curr
+
+        return res
+```
+
+```java
+public class Solution {
+    public int numberOfBeams(String[] bank) {
+        int prev = countOnes(bank[0]);
+        int res = 0;
+
+        for (int i = 1; i < bank.length; i++) {
+            int curr = countOnes(bank[i]);
+            if (curr > 0) {
+                res += prev * curr;
+                prev = curr;
+            }
+        }
+
+        return res;
+    }
+
+    private int countOnes(String s) {
+        int count = 0;
+        for (int i = 0; i < s.length(); i++) {
+            if (s.charAt(i) == '1') count++;
+        }
+        return count;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int numberOfBeams(vector<string>& bank) {
+        int prev = countOnes(bank[0]);
+        int res = 0;
+
+        for (int i = 1; i < bank.size(); i++) {
+            int curr = countOnes(bank[i]);
+            if (curr > 0) {
+                res += prev * curr;
+                prev = curr;
+            }
+        }
+
+        return res;
+    }
+
+private:
+    int countOnes(const string& s) {
+        return count(s.begin(), s.end(), '1');
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {string[]} bank
+     * @return {number}
+     */
+    numberOfBeams(bank) {
+        const countOnes = (s) => {
+            let cnt = 0;
+            for (let c of s) {
+                if (c === '1') cnt += 1;
+            }
+            return cnt;
+        };
+
+        let prev = countOnes(bank[0]);
+        let res = 0;
+
+        for (let i = 1; i < bank.length; i++) {
+            let curr = countOnes(bank[i]);
+            if (curr > 0) {
+                res += prev * curr;
+                prev = curr;
+            }
+        }
+
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(m * n)$
+* Space complexity: $O(1)$ extra space.
+
+> Where $m$ is the number of rows and $n$ is the number of columns.
\ No newline at end of file

From bb20d062cc5944676baa1ac998bce09c1c10eccf Mon Sep 17 00:00:00 2001
From: Sri Hari <kataresrihari@gmail.com>
Date: Sat, 8 Feb 2025 13:04:48 +0530
Subject: [PATCH 07/13] Batch-5/Neetcode-ALL/Added-articles

---
 articles/find-the-safest-path-in-a-grid.md   | 1054 ++++++++++++++++++
 articles/number-of-good-paths.md             |  861 ++++++++++++++
 articles/path-with-maximum-probability.md    |  632 +++++++++++
 articles/reveal-cards-in-increasing-order.md |  406 +++++++
 4 files changed, 2953 insertions(+)
 create mode 100644 articles/find-the-safest-path-in-a-grid.md
 create mode 100644 articles/number-of-good-paths.md
 create mode 100644 articles/path-with-maximum-probability.md
 create mode 100644 articles/reveal-cards-in-increasing-order.md

diff --git a/articles/find-the-safest-path-in-a-grid.md b/articles/find-the-safest-path-in-a-grid.md
new file mode 100644
index 000000000..f547fa423
--- /dev/null
+++ b/articles/find-the-safest-path-in-a-grid.md
@@ -0,0 +1,1054 @@
+## 1. Multi Source BFS + Dijkstra's Algorithm
+
+::tabs-start
+
+```python
+class Solution:
+    def maximumSafenessFactor(self, grid: List[List[int]]) -> int:
+        N = len(grid)
+
+        def in_bounds(r, c):
+            return min(r, c) >= 0 and max(r, c) < N
+
+        def precompute():
+            q = deque()
+            min_dist = {}
+            for r in range(N):
+                for c in range(N):
+                    if grid[r][c]:
+                        q.append([r, c, 0])
+                        min_dist[(r, c)] = 0
+            while q:
+                r, c, dist = q.popleft()
+                nei = [[r+1, c], [r-1, c], [r, c+1], [r, c-1]]
+                for r2, c2 in nei:
+                    if in_bounds(r2, c2) and (r2, c2) not in min_dist:
+                        min_dist[(r2, c2)] = dist + 1
+                        q.append([r2, c2, dist + 1])
+            return min_dist
+
+        min_dist = precompute()
+        maxHeap = [(-min_dist[(0, 0)], 0, 0)]  # (dist, r, c)
+        visit = set()
+        visit.add((0, 0))
+
+        while maxHeap:
+            dist, r, c = heapq.heappop(maxHeap)
+            dist = -dist
+            if (r, c) == (N-1, N-1):
+                return dist
+            nei = [[r+1, c], [r-1, c], [r, c+1], [r, c-1]]
+            for r2, c2 in nei:
+                if in_bounds(r2, c2) and (r2, c2) not in visit:
+                    visit.add((r2, c2))
+                    dist2 = min(dist, min_dist[(r2, c2)])
+                    heapq.heappush(maxHeap, (-dist2, r2, c2))
+```
+
+```java
+public class Solution {
+    public int maximumSafenessFactor(List<List<Integer>> grid) {
+        int N = grid.size();
+        int[][] minDist = precompute(grid, N);
+        PriorityQueue<int[]> maxHeap = new PriorityQueue<>((a, b) -> b[0] - a[0]);
+        boolean[][] visit = new boolean[N][N];
+
+        maxHeap.offer(new int[]{minDist[0][0], 0, 0});
+        visit[0][0] = true;
+
+        while (!maxHeap.isEmpty()) {
+            int[] curr = maxHeap.poll();
+            int dist = curr[0], r = curr[1], c = curr[2];
+
+            if (r == N - 1 && c == N - 1) {
+                return dist;
+            }
+
+            for (int[] dir : new int[][]{{1, 0}, {-1, 0}, {0, 1}, {0, -1}}) {
+                int r2 = r + dir[0], c2 = c + dir[1];
+                if (inBounds(r2, c2, N) && !visit[r2][c2]) {
+                    visit[r2][c2] = true;
+                    int dist2 = Math.min(dist, minDist[r2][c2]);
+                    maxHeap.offer(new int[]{dist2, r2, c2});
+                }
+            }
+        }
+        return 0;
+    }
+
+    private int[][] precompute(List<List<Integer>> grid, int N) {
+        int[][] minDist = new int[N][N];
+        for (int[] row : minDist) Arrays.fill(row, -1);
+        Queue<int[]> q = new LinkedList<>();
+
+        for (int r = 0; r < N; r++) {
+            for (int c = 0; c < N; c++) {
+                if (grid.get(r).get(c) == 1) {
+                    q.offer(new int[]{r, c, 0});
+                    minDist[r][c] = 0;
+                }
+            }
+        }
+
+        while (!q.isEmpty()) {
+            int[] curr = q.poll();
+            int r = curr[0], c = curr[1], dist = curr[2];
+
+            for (int[] dir : new int[][]{{1, 0}, {-1, 0}, {0, 1}, {0, -1}}) {
+                int r2 = r + dir[0], c2 = c + dir[1];
+                if (inBounds(r2, c2, N) && minDist[r2][c2] == -1) {
+                    minDist[r2][c2] = dist + 1;
+                    q.offer(new int[]{r2, c2, dist + 1});
+                }
+            }
+        }
+        return minDist;
+    }
+
+    private boolean inBounds(int r, int c, int N) {
+        return r >= 0 && c >= 0 && r < N && c < N;
+    }
+}
+```
+
+```cpp
+class Solution {
+    static constexpr int directions[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
+
+public:
+    int maximumSafenessFactor(vector<vector<int>>& grid) {
+        int N = grid.size();
+        vector<vector<int>> minDist = precompute(grid, N);
+        priority_queue<vector<int>> maxHeap;
+        vector<vector<bool>> visit(N, vector<bool>(N, false));
+
+        maxHeap.push({minDist[0][0], 0, 0});
+        visit[0][0] = true;
+
+        while (!maxHeap.empty()) {
+            vector<int> cur = maxHeap.top(); maxHeap.pop();
+            int dist = cur[0], r = cur[1], c = cur[2];
+
+            if (r == N - 1 && c == N - 1) {
+                return dist;
+            }
+
+            for (const auto& dir : directions) {
+                int r2 = r + dir[0], c2 = c + dir[1];
+                if (inBounds(r2, c2, N) && !visit[r2][c2]) {
+                    visit[r2][c2] = true;
+                    int dist2 = min(dist, minDist[r2][c2]);
+                    maxHeap.push({dist2, r2, c2});
+                }
+            }
+        }
+        return 0;
+    }
+
+private:
+    vector<vector<int>> precompute(vector<vector<int>>& grid, int N) {
+        vector<vector<int>> minDist(N, vector<int>(N, -1));
+        queue<vector<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, 0});
+                    minDist[r][c] = 0;
+                }
+            }
+        }
+
+        while (!q.empty()) {
+            vector<int> cur = q.front();
+            q.pop();
+            int r = cur[0], c = cur[1], dist = cur[2];
+
+            for (const auto& dir : directions) {
+                int r2 = r + dir[0], c2 = c + dir[1];
+                if (inBounds(r2, c2, N) && minDist[r2][c2] == -1) {
+                    minDist[r2][c2] = dist + 1;
+                    q.push({r2, c2, dist + 1});
+                }
+            }
+        }
+        return minDist;
+    }
+
+    bool inBounds(int r, int c, int N) {
+        return r >= 0 && c >= 0 && r < N && c < N;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} grid
+     * @return {number}
+     */
+    maximumSafenessFactor(grid) {
+        const N = grid.length;
+        const directions = [[1, 0], [-1, 0], [0, 1], [0, -1]];
+
+        const inBounds = (r, c) => {
+            return r >= 0 && c >= 0 && r < N && c < N;
+        };
+
+        const precompute = () => {
+            const q = new Queue();
+            const minDist = Array.from({ length: N }, () => Array(N).fill(-1));
+
+            for (let r = 0; r < N; r++) {
+                for (let c = 0; c < N; c++) {
+                    if (grid[r][c] === 1) {
+                        q.push([r, c, 0]);
+                        minDist[r][c] = 0;
+                    }
+                }
+            }
+
+            while (!q.isEmpty()) {
+                let [r, c, dist] = q.pop();
+
+                for (let [dr, dc] of directions) {
+                    let r2 = r + dr, c2 = c + dc;
+                    if (inBounds(r2, c2) && minDist[r2][c2] === -1) {
+                        minDist[r2][c2] = dist + 1;
+                        q.push([r2, c2, dist + 1]);
+                    }
+                }
+            }
+            return minDist;
+        };
+
+        const minDist = precompute();
+        const maxHeap = new MaxPriorityQueue({ priority: x => x[0] });
+        const visit = Array.from({ length: N }, () => Array(N).fill(false));
+
+        maxHeap.enqueue([minDist[0][0], 0, 0]);
+        visit[0][0] = true;
+
+        while (!maxHeap.isEmpty()) {
+            let [dist, r, c] = maxHeap.dequeue().element;
+
+            if (r === N - 1 && c === N - 1) {
+                return dist;
+            }
+
+            for (let [dr, dc] of directions) {
+                let r2 = r + dr, c2 = c + dc;
+                if (inBounds(r2, c2) && !visit[r2][c2]) {
+                    visit[r2][c2] = true;
+                    let dist2 = Math.min(dist, minDist[r2][c2]);
+                    maxHeap.enqueue([dist2, r2, c2]);
+                }
+            }
+        }
+        return 0;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n ^ 2 \log n)$
+* Space complexity: $O(n ^ 2)$
+
+---
+
+## 2. Multi Source BFS + Dijkstra's Algorithm (Overwriting the Input)
+
+::tabs-start
+
+```python
+class Solution:
+    def maximumSafenessFactor(self, grid):
+        N = len(grid)
+        minDist = grid
+        directions = [0, 1, 0, -1, 0]
+
+        q = deque()
+        for r in range(N):
+            for c in range(N):
+                if grid[r][c] == 1:
+                    q.append(r * N + c)
+                    minDist[r][c] = 0
+                else:
+                    minDist[r][c] = -1
+
+        while q:
+            node = q.popleft()
+            r, c = divmod(node, N)
+            for i in range(4):
+                r2, c2 = r + directions[i], c + directions[i + 1]
+                if 0 <= r2 < N and 0 <= c2 < N and minDist[r2][c2] == -1:
+                    minDist[r2][c2] = minDist[r][c] + 1
+                    q.append(r2 * N + c2)
+
+        maxHeap = [(-minDist[0][0], 0)]
+        safeFactor = [0] * (N * N)
+        safeFactor[0] = minDist[0][0]
+
+        while maxHeap:
+            dist, node = heapq.heappop(maxHeap)
+            dist = -dist
+            r, c = divmod(node, N)
+            if r == N - 1 and c == N - 1:
+                return dist
+            if safeFactor[node] > dist:
+                continue
+
+            for i in range(4):
+                r2, c2 = r + directions[i], c + directions[i + 1]
+                node2 = r2 * N + c2
+                if 0 <= r2 < N and 0 <= c2 < N:
+                    dist2 = min(dist, minDist[r2][c2])
+                    if dist2 > safeFactor[node2]:
+                        safeFactor[node2] = dist2
+                        heapq.heappush(maxHeap, (-dist2, node2))
+
+        return 0
+```
+
+```java
+public class Solution {
+    public int maximumSafenessFactor(List<List<Integer>> grid) {
+        int N = grid.size();
+        int[][] minDist = new int[N][N];
+        int[] directions = {0, 1, 0, -1, 0};
+
+        Queue<Integer> q = new LinkedList<>();
+        for (int r = 0; r < N; r++) {
+            for (int c = 0; c < N; c++) {
+                if (grid.get(r).get(c) == 1) {
+                    q.offer(r * N + c);
+                    minDist[r][c] = 0;
+                } else {
+                    minDist[r][c] = -1;
+                }
+            }
+        }
+
+        while (!q.isEmpty()) {
+            int node = q.poll();
+            int r = node / N, c = node % N;
+            for (int i = 0; i < 4; i++) {
+                int r2 = r + directions[i], c2 = c + directions[i + 1];
+                if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N && minDist[r2][c2] == -1) {
+                    minDist[r2][c2] = minDist[r][c] + 1;
+                    q.offer(r2 * N + c2);
+                }
+            }
+        }
+
+        PriorityQueue<int[]> maxHeap = new PriorityQueue<>((a, b) -> Integer.compare(b[0], a[0]));
+        int[] safeFactor = new int[N * N];
+        Arrays.fill(safeFactor, -1);
+        safeFactor[0] = minDist[0][0];
+        maxHeap.offer(new int[]{safeFactor[0], 0});
+
+        while (!maxHeap.isEmpty()) {
+            int[] top = maxHeap.poll();
+            int dist = top[0], node = top[1];
+            int r = node / N, c = node % N;
+            if (r == N - 1 && c == N - 1) {
+                return dist;
+            }
+            if (safeFactor[node] > dist) {
+                continue;
+            }
+
+            for (int i = 0; i < 4; i++) {
+                int r2 = r + directions[i], c2 = c + directions[i + 1];
+                int node2 = r2 * N + c2;
+                if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N) {
+                    int dist2 = Math.min(dist, minDist[r2][c2]);
+                    if (dist2 > safeFactor[node2]) {
+                        safeFactor[node2] = dist2;
+                        maxHeap.offer(new int[]{dist2, node2});
+                    }
+                }
+            }
+        }
+        return 0;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int maximumSafenessFactor(vector<vector<int>>& grid) {
+        int N = grid.size();
+        vector<int> directions = {0, 1, 0, -1, 0};
+        vector<vector<int>>& minDist = grid;
+
+        queue<int> q;
+        for (int r = 0; r < N; r++) {
+            for (int c = 0; c < N; c++) {
+                if (grid[r][c] == 1) {
+                    q.push(r * N + c);
+                    minDist[r][c] = 0;
+                } else {
+                    minDist[r][c] = -1;
+                }
+            }
+        }
+
+        while (!q.empty()) {
+            int node = q.front(); q.pop();
+            int r = node / N, c = node % N;
+            for (int i = 0; i < 4; i++) {
+                int r2 = r + directions[i], c2 = c + directions[i + 1];
+                if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N && minDist[r2][c2] == -1) {
+                    minDist[r2][c2] = minDist[r][c] + 1;
+                    q.push(r2 * N + c2);
+                }
+            }
+        }
+
+        priority_queue<pair<int, int>> maxHeap;
+        vector<int> safeFactor(N * N, 0);
+        safeFactor[0] = minDist[0][0];
+        maxHeap.push({safeFactor[0], 0});
+
+        while (!maxHeap.empty()) {
+            auto [dist, node] = maxHeap.top(); maxHeap.pop();
+            int r = node / N, c = node % N;
+            if (r == N - 1 && c == N - 1) {
+                return dist;
+            }
+            if (safeFactor[node] > dist) {
+                continue;
+            }
+
+            for (int i = 0; i < 4; i++) {
+                int r2 = r + directions[i], c2 = c + directions[i + 1], node2 = r2 * N + c2;
+                if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N) {
+                    int dist2 = min(dist, minDist[r2][c2]);
+                    if (dist2 > safeFactor[node2]) {
+                        safeFactor[node2] = dist2;
+                        maxHeap.push({dist2, node2});
+                    }
+                }
+            }
+        }
+        return 0;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} grid
+     * @return {number}
+     */
+    maximumSafenessFactor(grid) {
+        const N = grid.length;
+        const directions = [0, 1, 0, -1, 0];
+        const minDist = grid;
+
+        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 * N + c);
+                    minDist[r][c] = 0;
+                } else {
+                    minDist[r][c] = -1;
+                }
+            }
+        }
+
+        while (!q.isEmpty()) {
+            let node = q.pop();
+            let r = Math.floor(node / N), c = node % N;
+            for (let i = 0; i < 4; i++) {
+                let r2 = r + directions[i], c2 = c + directions[i + 1];
+                if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N && minDist[r2][c2] === -1) {
+                    minDist[r2][c2] = minDist[r][c] + 1;
+                    q.push(r2 * N + c2);
+                }
+            }
+        }
+
+        let maxHeap = new MaxPriorityQueue({ priority: x => x[0] });
+        let safeFactor = new Array(N * N).fill(0);
+        safeFactor[0] = minDist[0][0];
+        maxHeap.enqueue([safeFactor[0], 0]);
+
+        while (!maxHeap.isEmpty()) {
+            let [dist, node] = maxHeap.dequeue().element;
+            let r = Math.floor(node / N), c = node % N;
+            if (r === N - 1 && c === N - 1) {
+                return dist;
+            }
+            if (safeFactor[node] > dist) {
+                continue;
+            }
+
+            for (let i = 0; i < 4; i++) {
+                let r2 = r + directions[i], c2 = c + directions[i + 1], node2 = r2 * N + c2;
+                if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N) {
+                    let dist2 = Math.min(dist, minDist[r2][c2]);
+                    if (dist2 > safeFactor[node2]) {
+                        safeFactor[node2] = dist2;
+                        maxHeap.enqueue([dist2, node2]);
+                    }
+                }
+            }
+        }
+        return 0;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n ^ 2 \log n)$
+* Space complexity: $O(n ^ 2)$
+
+---
+
+## 3. Multi Source BFS + Binary Search
+
+::tabs-start
+
+```python
+class Solution:
+    def maximumSafenessFactor(self, grid):
+        N = len(grid)
+        minDist = grid
+        directions = [0, 1, 0, -1, 0]
+
+        q = deque()
+        for r in range(N):
+            for c in range(N):
+                if grid[r][c] == 1:
+                    q.append(r * N + c)
+                    minDist[r][c] = 0
+                else:
+                    minDist[r][c] = -1
+
+        while q:
+            node = q.popleft()
+            r, c = divmod(node, N)
+            for i in range(4):
+                r2, c2 = r + directions[i], c + directions[i + 1]
+                if 0 <= r2 < N and 0 <= c2 < N and minDist[r2][c2] == -1:
+                    minDist[r2][c2] = minDist[r][c] + 1
+                    q.append(r2 * N + c2)
+
+        def canReach(threshold):
+            q = deque([0])
+            visited = [False] * (N * N)
+            visited[0] = True
+
+            while q:
+                node = q.popleft()
+                r, c = divmod(node, N)
+                if r == N - 1 and c == N - 1:
+                    return True
+
+                for i in range(4):
+                    r2, c2 = r + directions[i], c + directions[i + 1]
+                    node2 = r2 * N + c2
+                    if (0 <= r2 < N and 0 <= c2 < N and not visited[node2] and 
+                        minDist[r2][c2] >= threshold
+                    ):
+                        visited[node2] = True
+                        q.append(node2)
+
+            return False
+
+        l, r = 0, min(minDist[0][0], minDist[N - 1][N - 1])
+        while l <= r:
+            mid = (l + r) // 2
+            if canReach(mid):
+                l = mid + 1
+            else:
+                r = mid - 1
+
+        return l - 1
+```
+
+```java
+public class Solution {
+    private static int[] directions = {0, 1, 0, -1, 0};
+
+    public int maximumSafenessFactor(List<List<Integer>> grid) {
+        int N = grid.size();
+        int[][] minDist = new int[N][N];
+
+        Queue<Integer> q = new LinkedList<>();
+        for (int r = 0; r < N; r++) {
+            for (int c = 0; c < N; c++) {
+                if (grid.get(r).get(c) == 1) {
+                    q.offer(r * N + c);
+                    minDist[r][c] = 0;
+                } else {
+                    minDist[r][c] = -1;
+                }
+            }
+        }
+
+        while (!q.isEmpty()) {
+            int node = q.poll();
+            int r = node / N, c = node % N;
+            for (int i = 0; i < 4; i++) {
+                int r2 = r + directions[i], c2 = c + directions[i + 1];
+                if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N && minDist[r2][c2] == -1) {
+                    minDist[r2][c2] = minDist[r][c] + 1;
+                    q.offer(r2 * N + c2);
+                }
+            }
+        }
+
+        int l = 0, r = Math.min(minDist[0][0], minDist[N - 1][N - 1]);
+        while (l <= r) {
+            int mid = (l + r) / 2;
+            if (canReach(minDist, N, mid)) {
+                l = mid + 1;
+            } else {
+                r = mid - 1;
+            }
+        }
+        return l - 1;
+    }
+
+    private boolean canReach(int[][] minDist, int N, int threshold) {
+        Queue<Integer> q = new LinkedList<>();
+        boolean[] visited = new boolean[N * N];
+        q.offer(0);
+        visited[0] = true;
+
+        while (!q.isEmpty()) {
+            int node = q.poll();
+            int r = node / N, c = node % N;
+            if (r == N - 1 && c == N - 1) {
+                return true;
+            }
+
+            for (int i = 0; i < 4; i++) {
+                int r2 = r + directions[i], c2 = c + directions[i + 1];
+                int node2 = r2 * N + c2;
+                if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N && !visited[node2] && 
+                    minDist[r2][c2] >= threshold) {
+                    visited[node2] = true;
+                    q.offer(node2);
+                }
+            }
+        }
+        return false;
+    }
+}
+```
+
+```cpp
+class Solution {
+    static constexpr int directions[5] = {0, 1, 0, -1, 0};
+
+public:
+    int maximumSafenessFactor(vector<vector<int>>& grid) {
+        int N = grid.size();
+        vector<vector<int>>& minDist = grid;
+
+        queue<int> q;
+        for (int r = 0; r < N; r++) {
+            for (int c = 0; c < N; c++) {
+                if (grid[r][c] == 1) {
+                    q.push(r * N + c);
+                    minDist[r][c] = 0;
+                } else {
+                    minDist[r][c] = -1;
+                }
+            }
+        }
+
+        while (!q.empty()) {
+            int node = q.front(); q.pop();
+            int r = node / N, c = node % N;
+            for (int i = 0; i < 4; i++) {
+                int r2 = r + directions[i], c2 = c + directions[i + 1];
+                if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N && minDist[r2][c2] == -1) {
+                    minDist[r2][c2] = minDist[r][c] + 1;
+                    q.push(r2 * N + c2);
+                }
+            }
+        }
+
+        int l = 0, r = min(minDist[0][0], minDist[N - 1][N - 1]);
+        while (l <= r) {
+            int mid = (l + r) / 2;
+            if (canReach(minDist, N, mid)) {
+                l = mid + 1;
+            } else {
+                r = mid - 1;
+            }
+        }
+        return l - 1;
+    }
+
+private:
+    bool canReach(vector<vector<int>>& minDist, int N, int threshold) {
+        queue<int> q;
+        vector<bool> visited(N * N, false);
+        q.push(0);
+        visited[0] = true;
+
+        while (!q.empty()) {
+            int node = q.front(); q.pop();
+            int r = node / N, c = node % N;
+            if (r == N - 1 && c == N - 1) {
+                return true;
+            }
+
+            for (int i = 0; i < 4; i++) {
+                int r2 = r + directions[i], c2 = c + directions[i + 1], node2 = r2 * N + c2;
+                if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N && !visited[node2] && 
+                    minDist[r2][c2] >= threshold) {
+                    visited[node2] = true;
+                    q.push(node2);
+                }
+            }
+        }
+        return false;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} grid
+     * @return {number}
+     */
+    maximumSafenessFactor(grid) {
+        const N = grid.length;
+        const minDist = grid;
+        const directions = [0, 1, 0, -1, 0];
+
+        let 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 * N + c);
+                    minDist[r][c] = 0;
+                } else {
+                    minDist[r][c] = -1;
+                }
+            }
+        }
+
+        while (!q.isEmpty()) {
+            let node = q.pop();
+            let r = Math.floor(node / N), c = node % N;
+            for (let i = 0; i < 4; i++) {
+                let r2 = r + directions[i], c2 = c + directions[i + 1];
+                if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N && minDist[r2][c2] === -1) {
+                    minDist[r2][c2] = minDist[r][c] + 1;
+                    q.push(r2 * N + c2);
+                }
+            }
+        }
+
+        const canReach = (threshold) => {
+            q = new Queue([0]);
+            let visited = new Array(N * N).fill(false);
+            visited[0] = true;
+
+            while (!q.isEmpty()) {
+                let node = q.pop();
+                let r = Math.floor(node / N), c = node % N;
+                if (r === N - 1 && c === N - 1) return true;
+
+                for (let i = 0; i < 4; i++) {
+                    let r2 = r + directions[i], c2 = c + directions[i + 1], node2 = r2 * N + c2;
+                    if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N && !visited[node2] && 
+                        minDist[r2][c2] >= threshold) {
+                        visited[node2] = true;
+                        q.push(node2);
+                    }
+                }
+            }
+            return false;
+        };
+
+        let l = 0, r = Math.min(minDist[0][0], minDist[N - 1][N - 1]);
+        while (l <= r) {
+            let mid = Math.floor((l + r) / 2);
+            if (canReach(mid)) {
+                l = mid + 1;
+            } else {
+                r = mid - 1;
+            }
+        }
+        return l - 1;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n ^ 2 \log n)$
+* Space complexity: $O(n ^ 2)$
+
+---
+
+## 4. Breadth First Search (0-1 BFS)
+
+::tabs-start
+
+```python
+class Solution:
+    def maximumSafenessFactor(self, grid):
+        N = len(grid)
+        minDist = grid
+        directions = [0, 1, 0, -1, 0]
+
+        q = deque()
+        for r in range(N):
+            for c in range(N):
+                if grid[r][c] == 1:
+                    q.append(r * N + c)
+                    minDist[r][c] = 0
+                else:
+                    minDist[r][c] = -1
+
+        while q:
+            node = q.popleft()
+            r, c = divmod(node, N)
+            for i in range(4):
+                r2, c2 = r + directions[i], c + directions[i + 1]
+                if 0 <= r2 < N and 0 <= c2 < N and minDist[r2][c2] == -1:
+                    minDist[r2][c2] = minDist[r][c] + 1
+                    q.append(r2 * N + c2)
+
+        safeFactor = [-1] * (N * N)
+        res = safeFactor[0] = min(minDist[N - 1][N - 1], minDist[0][0])
+        q.append(0)
+
+        while q:
+            node = q.popleft()
+            r, c = divmod(node, N)
+            res = min(res, safeFactor[node])
+            if r == N - 1 and c == N - 1:
+                break
+
+            for i in range(4):
+                r2, c2 = r + directions[i], c + directions[i + 1]
+                node2 = r2 * N + c2
+                if 0 <= r2 < N and 0 <= c2 < N and safeFactor[node2] == -1:
+                    safeFactor[node2] = min(safeFactor[node], minDist[r2][c2])
+                    if safeFactor[node2] < res:
+                        q.append(node2)
+                    else:
+                        q.appendleft(node2)
+
+        return res
+```
+
+```java
+public class Solution {
+    private static final int[] directions = {0, 1, 0, -1, 0};
+
+    public int maximumSafenessFactor(List<List<Integer>> grid) {
+        int N = grid.size();
+        int[][] minDist = new int[N][N];
+
+        Deque<Integer> q = new ArrayDeque<>();
+        for (int r = 0; r < N; r++) {
+            for (int c = 0; c < N; c++) {
+                if (grid.get(r).get(c) == 1) {
+                    q.offerLast(r * N + c);
+                    minDist[r][c] = 0;
+                } else {
+                    minDist[r][c] = -1;
+                }
+            }
+        }
+
+        while (!q.isEmpty()) {
+            int node = q.pollFirst();
+            int r = node / N, c = node % N;
+            for (int i = 0; i < 4; i++) {
+                int r2 = r + directions[i], c2 = c + directions[i + 1];
+                if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N && minDist[r2][c2] == -1) {
+                    minDist[r2][c2] = minDist[r][c] + 1;
+                    q.offerLast(r2 * N + c2);
+                }
+            }
+        }
+
+        int[] safeFactor = new int[N * N];
+        Arrays.fill(safeFactor, -1);
+        int res = safeFactor[0] = Math.min(minDist[N - 1][N - 1], minDist[0][0]);
+        q.offerLast(0);
+
+        while (!q.isEmpty()) {
+            int node = q.pollFirst();
+            int r = node / N, c = node % N;
+            res = Math.min(res, safeFactor[node]);
+            if (r == N - 1 && c == N - 1) {
+                break;
+            }
+
+            for (int i = 0; i < 4; i++) {
+                int r2 = r + directions[i], c2 = c + directions[i + 1], node2 = r2 * N + c2;
+                if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N && safeFactor[node2] == -1) {
+                    safeFactor[node2] = Math.min(safeFactor[node], minDist[r2][c2]);
+                    if (safeFactor[node2] < res) {
+                        q.offerLast(node2);
+                    } else {
+                        q.offerFirst(node2);
+                    }
+                }
+            }
+        }
+
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int maximumSafenessFactor(vector<vector<int>>& grid) {
+        int N = grid.size();
+        vector<vector<int>>& minDist = grid;
+        constexpr int directions[5] = {0, 1, 0, -1, 0};
+
+        deque<int> q;
+        for (int r = 0; r < N; r++) {
+            for (int c = 0; c < N; c++) {
+                if (grid[r][c] == 1) {
+                    q.push_back(r * N + c);
+                    minDist[r][c] = 0;
+                } else {
+                    minDist[r][c] = -1;
+                }
+            }
+        }
+
+        while (!q.empty()) {
+            int node = q.front(); q.pop_front();
+            int r = node / N, c = node % N;
+            for (int i = 0; i < 4; i++) {
+                int r2 = r + directions[i], c2 = c + directions[i + 1];
+                if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N && minDist[r2][c2] == -1) {
+                    minDist[r2][c2] = minDist[r][c] + 1;
+                    q.push_back(r2 * N + c2);
+                }
+            }
+        }
+
+        vector<int> safeFactor(N * N, -1);
+        int res = safeFactor[0] = min(minDist[N - 1][N - 1], minDist[0][0]);
+        q.push_back(0);
+
+        while (!q.empty()) {
+            int node = q.front(); q.pop_front();
+            int r = node / N, c = node % N;
+            res = min(res, safeFactor[node]);
+            if (r == N - 1 && c == N - 1) {
+                break;
+            }
+
+            for (int i = 0; i < 4; i++) {
+                int r2 = r + directions[i], c2 = c + directions[i + 1], node2 = r2 * N + c2;
+                if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N && safeFactor[node2] == -1) {
+                    safeFactor[node2] = min(safeFactor[node], minDist[r2][c2]);
+                    if (safeFactor[node2] < res) {
+                        q.push_back(node2);
+                    } else {
+                        q.push_front(node2);
+                    }
+                }
+            }
+        }
+
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} grid
+     * @return {number}
+     */
+    maximumSafenessFactor(grid) {
+        const N = grid.length;
+        const minDist = grid;
+        const directions = [0, 1, 0, -1, 0];
+
+        const q = new Deque();
+        for (let r = 0; r < N; r++) {
+            for (let c = 0; c < N; c++) {
+                if (grid[r][c] === 1) {
+                    q.pushBack(r * N + c);
+                    minDist[r][c] = 0;
+                } else {
+                    minDist[r][c] = -1;
+                }
+            }
+        }
+
+        while (!q.isEmpty()) {
+            let node = q.popFront();
+            let r = Math.floor(node / N), c = node % N;
+            for (let i = 0; i < 4; i++) {
+                let r2 = r + directions[i], c2 = c + directions[i + 1];
+                if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N && minDist[r2][c2] === -1) {
+                    minDist[r2][c2] = minDist[r][c] + 1;
+                    q.pushBack(r2 * N + c2);
+                }
+            }
+        }
+
+        let safeFactor = new Array(N * N).fill(-1);
+        let res = safeFactor[0] = Math.min(minDist[N - 1][N - 1], minDist[0][0]);
+        q.pushBack(0);
+
+        while (!q.isEmpty()) {
+            let node = q.popFront();
+            let r = Math.floor(node / N), c = node % N;
+            res = Math.min(res, safeFactor[node]);
+            if (r === N - 1 && c === N - 1) {
+                break;
+            }
+
+            for (let i = 0; i < 4; i++) {
+                let r2 = r + directions[i], c2 = c + directions[i + 1], node2 = r2 * N + c2;
+                if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N && safeFactor[node2] === -1) {
+                    safeFactor[node2] = Math.min(safeFactor[node], minDist[r2][c2]);
+                    if (safeFactor[node2] < res) {
+                        q.pushBack(node2);
+                    } else {
+                        q.pushFront(node2);
+                    }
+                }
+            }
+        }
+
+        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/number-of-good-paths.md b/articles/number-of-good-paths.md
new file mode 100644
index 000000000..f0e16529f
--- /dev/null
+++ b/articles/number-of-good-paths.md
@@ -0,0 +1,861 @@
+## 1. Brute Force (DFS)
+
+::tabs-start
+
+```python
+class Solution:
+    def numberOfGoodPaths(self, vals: List[int], edges: List[List[int]]) -> int:
+        n = len(vals)
+        adj = [[] for _ in range(n)]
+        for u, v in edges:
+            adj[u].append(v)
+            adj[v].append(u)
+
+        def dfs(node, startNode, parent):
+            if vals[node] > vals[startNode]:
+                return 0
+
+            res = 0
+            if vals[node] == vals[startNode] and node >= startNode:
+                res += 1
+
+            for child in adj[node]:
+                if child == parent:
+                    continue
+                res += dfs(child, startNode, node)
+
+            return res
+
+
+        res = 0
+        for node in range(n):
+            res += dfs(node, node, -1)
+        return res
+```
+
+```java
+public class Solution {
+    public int numberOfGoodPaths(int[] vals, int[][] edges) {
+        int n = vals.length;
+        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]);
+            adj[edge[1]].add(edge[0]);
+        }
+
+        int res = 0;
+        for (int node = 0; node < n; node++) {
+            res += dfs(node, node, -1, vals, adj);
+        }
+        return res;
+    }
+
+    private int dfs(int node, int startNode, int parent, int[] vals, List<Integer>[] adj) {
+        if (vals[node] > vals[startNode]) {
+            return 0;
+        }
+
+        int res = 0;
+        if (vals[node] == vals[startNode] && node >= startNode) {
+            res += 1;
+        }
+
+        for (int child : adj[node]) {
+            if (child == parent) {
+                continue;
+            }
+            res += dfs(child, startNode, node, vals, adj);
+        }
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int numberOfGoodPaths(vector<int>& vals, vector<vector<int>>& edges) {
+        int n = vals.size();
+        vector<vector<int>> adj(n);
+        for (auto& edge : edges) {
+            adj[edge[0]].push_back(edge[1]);
+            adj[edge[1]].push_back(edge[0]);
+        }
+
+        int res = 0;
+        for (int node = 0; node < n; node++) {
+            res += dfs(node, node, -1, vals, adj);
+        }
+        return res;
+    }
+
+private:
+    int dfs(int node, int startNode, int parent, vector<int>& vals, vector<vector<int>>& adj) {
+        if (vals[node] > vals[startNode]) {
+            return 0;
+        }
+
+        int res = 0;
+        if (vals[node] == vals[startNode] && node >= startNode) {
+            res += 1;
+        }
+
+        for (int child : adj[node]) {
+            if (child == parent) {
+                continue;
+            }
+            res += dfs(child, startNode, node, vals, adj);
+        }
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} vals
+     * @param {number[][]} edges
+     * @return {number}
+     */
+    numberOfGoodPaths(vals, edges) {
+        const n = vals.length;
+        const adj = Array.from({ length: n }, () => []);
+
+        for (const [u, v] of edges) {
+            adj[u].push(v);
+            adj[v].push(u);
+        }
+
+        const dfs = (node, startNode, parent) => {
+            if (vals[node] > vals[startNode]) {
+                return 0;
+            }
+
+            let res = 0;
+            if (vals[node] === vals[startNode] && node >= startNode) {
+                res += 1;
+            }
+
+            for (const child of adj[node]) {
+                if (child === parent) continue;
+                res += dfs(child, startNode, node);
+            }
+            return res;
+        };
+
+        let res = 0;
+        for (let node = 0; node < n; node++) {
+            res += dfs(node, node, -1);
+        }
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n ^ 2)$
+* Space complexity: $O(n)$ for recursion stack.
+
+---
+
+## 2. Brute Force (BFS)
+
+::tabs-start
+
+```python
+class Solution:
+    def numberOfGoodPaths(self, vals, edges):
+        n = len(vals)
+        adj = [[] for _ in range(n)]
+        for u, v in edges:
+            adj[u].append(v)
+            adj[v].append(u)
+
+        res = 0
+        for startNode in range(n):
+            q = deque([startNode])
+            visited = set([startNode])
+            count = 0
+
+            while q:
+                node = q.popleft()
+                if vals[node] == vals[startNode] and node >= startNode:
+                    count += 1
+
+                for child in adj[node]:
+                    if child not in visited and vals[child] <= vals[startNode]:
+                        visited.add(child)
+                        q.append(child)
+
+            res += count
+
+        return res
+```
+
+```java
+public class Solution {
+    public int numberOfGoodPaths(int[] vals, int[][] edges) {
+        int n = vals.length;
+        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]);
+            adj[edge[1]].add(edge[0]);
+        }
+
+        int res = 0;
+        for (int startNode = 0; startNode < n; startNode++) {
+            Queue<Integer> q = new LinkedList<>();
+            Set<Integer> visited = new HashSet<>();
+            q.offer(startNode);
+            visited.add(startNode);
+            int count = 0;
+
+            while (!q.isEmpty()) {
+                int node = q.poll();
+                if (vals[node] == vals[startNode] && node >= startNode) {
+                    count++;
+                }
+
+                for (int child : adj[node]) {
+                    if (!visited.contains(child) && vals[child] <= vals[startNode]) {
+                        visited.add(child);
+                        q.offer(child);
+                    }
+                }
+            }
+
+            res += count;
+        }
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int numberOfGoodPaths(vector<int>& vals, vector<vector<int>>& edges) {
+        int n = vals.size();
+        vector<vector<int>> adj(n);
+        for (auto& edge : edges) {
+            adj[edge[0]].push_back(edge[1]);
+            adj[edge[1]].push_back(edge[0]);
+        }
+
+        int res = 0;
+        for (int startNode = 0; startNode < n; startNode++) {
+            queue<int> q;
+            unordered_set<int> visited;
+            q.push(startNode);
+            visited.insert(startNode);
+            int count = 0;
+
+            while (!q.empty()) {
+                int node = q.front();
+                q.pop();
+                if (vals[node] == vals[startNode] && node >= startNode) {
+                    count++;
+                }
+
+                for (int child : adj[node]) {
+                    if (visited.find(child) == visited.end() && vals[child] <= vals[startNode]) {
+                        visited.insert(child);
+                        q.push(child);
+                    }
+                }
+            }
+
+            res += count;
+        }
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} vals
+     * @param {number[][]} edges
+     * @return {number}
+     */
+    numberOfGoodPaths(vals, edges) {
+        const n = vals.length;
+        const adj = Array.from({ length: n }, () => []);
+
+        for (const [u, v] of edges) {
+            adj[u].push(v);
+            adj[v].push(u);
+        }
+
+        let res = 0;
+        for (let startNode = 0; startNode < n; startNode++) {
+            const q = new Queue([startNode]);
+            const visited = new Set([startNode]);
+            let count = 0;
+
+            while (q.length) {
+                let node = q.shift();
+                if (vals[node] === vals[startNode] && node >= startNode) {
+                    count++;
+                }
+
+                for (const child of adj[node]) {
+                    if (!visited.has(child) && vals[child] <= vals[startNode]) {
+                        visited.add(child);
+                        q.push(child);
+                    }
+                }
+            }
+
+            res += count;
+        }
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n ^ 2)$
+* Space complexity: $O(n)$
+
+---
+
+## 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 numberOfGoodPaths(self, vals: List[int], edges: List[List[int]]) -> int:
+        adj = collections.defaultdict(list)
+        for a, b in edges:
+            adj[a].append(b)
+            adj[b].append(a)
+
+        valToIndex = collections.defaultdict(list)
+        for i, val in enumerate(vals):
+            valToIndex[val].append(i)
+
+        res = 0
+        uf = DSU(len(vals))
+
+        for val in sorted(valToIndex.keys()):
+            for i in valToIndex[val]:
+                for nei in adj[i]:
+                    if vals[nei] <= vals[i]:
+                        uf.union(nei, i)
+
+            count = collections.defaultdict(int)
+            for i in valToIndex[val]:
+                count[uf.find(i)] += 1
+                res += count[uf.find(i)]
+
+        return res
+```
+
+```java
+class DSU {
+    private 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 numberOfGoodPaths(int[] vals, int[][] edges) {
+        int n = vals.length;
+        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]);
+            adj[edge[1]].add(edge[0]);
+        }
+
+        TreeMap<Integer, List<Integer>> valToIndex = new TreeMap<>();
+        for (int i = 0; i < n; i++) {
+            valToIndex.putIfAbsent(vals[i], new ArrayList<>());
+            valToIndex.get(vals[i]).add(i);
+        }
+
+        DSU dsu = new DSU(n);
+        int res = 0;
+
+        for (int val : valToIndex.keySet()) {
+            for (int i : valToIndex.get(val)) {
+                for (int nei : adj[i]) {
+                    if (vals[nei] <= vals[i]) dsu.union(nei, i);
+                }
+            }
+
+            Map<Integer, Integer> count = new HashMap<>();
+            for (int i : valToIndex.get(val)) {
+                int root = dsu.find(i);
+                count.put(root, count.getOrDefault(root, 0) + 1);
+                res += count.get(root);
+            }
+        }
+        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 unite(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 numberOfGoodPaths(vector<int>& vals, vector<vector<int>>& edges) {
+        int n = vals.size();
+        vector<vector<int>> adj(n);
+        for (auto& edge : edges) {
+            adj[edge[0]].push_back(edge[1]);
+            adj[edge[1]].push_back(edge[0]);
+        }
+
+        map<int, vector<int>> valToIndex;
+        for (int i = 0; i < n; i++) valToIndex[vals[i]].push_back(i);
+
+        DSU dsu(n);
+        int res = 0;
+
+        for (auto& [val, nodes] : valToIndex) {
+            for (int& i : nodes) {
+                for (int& nei : adj[i]) {
+                    if (vals[nei] <= vals[i]) dsu.unite(nei, i);
+                }
+            }
+
+            unordered_map<int, int> count;
+            for (int& i : nodes) {
+                int root = dsu.find(i);
+                count[root]++;
+                res += count[root];
+            }
+        }
+        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[]} vals
+     * @param {number[][]} edges
+     * @return {number}
+     */
+    numberOfGoodPaths(vals, edges) {
+        const n = vals.length;
+        const adj = Array.from({ length: n }, () => []);
+
+        for (const [u, v] of edges) {
+            adj[u].push(v);
+            adj[v].push(u);
+        }
+
+        const valToIndex = new Map();
+        for (let i = 0; i < n; i++) {
+            if (!valToIndex.has(vals[i])) valToIndex.set(vals[i], []);
+            valToIndex.get(vals[i]).push(i);
+        }
+
+        const dsu = new DSU(n);
+        let res = 0;
+
+        for (const [val, nodes] of [...valToIndex.entries()].sort((a, b) => a[0] - b[0])) {
+            for (const i of nodes) {
+                for (const nei of adj[i]) {
+                    if (vals[nei] <= vals[i]) dsu.union(nei, i);
+                }
+            }
+
+            const count = new Map();
+            for (const i of nodes) {
+                const root = dsu.find(i);
+                count.set(root, (count.get(root) || 0) + 1);
+                res += count.get(root);
+            }
+        }
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n \log n)$
+* Space complexity: $O(n)$
+
+---
+
+## 4. Disjoint Set Union (Union By Value)
+
+::tabs-start
+
+```python
+class DSU:
+    def __init__(self, n, vals):
+        self.parent = list(range(n))
+        self.vals = vals
+        self.count = [1] * n # count of nodes with max value of the component
+
+    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 0
+        if self.vals[pu] < self.vals[pv]:
+            self.parent[pu] = pv
+        elif self.vals[pu] > self.vals[pv]:
+            self.parent[pv] = pu
+        else:
+            self.parent[pv] = pu
+            result = self.count[pu] * self.count[pv]
+            self.count[pu] += self.count[pv]
+            return result
+        
+        return 0
+
+
+class Solution:
+    def numberOfGoodPaths(self, vals: List[int], edges: List[List[int]]) -> int:
+        n = len(vals)
+        dsu = DSU(n, vals)
+
+        # Sort edges based on max value of the two nodes
+        edges.sort(key=lambda edge: max(vals[edge[0]], vals[edge[1]]))
+
+        res = n  # Each node alone is a good path
+        for u, v in edges:
+            res += dsu.union(u, v)
+        return res
+```
+
+```java
+class DSU {
+    private int[] parent, count, vals;
+
+    public DSU(int n, int[] vals) {
+        this.parent = new int[n];
+        this.vals = vals;
+        this.count = new int[n]; // count of nodes with max value of the component
+        Arrays.fill(count, 1);
+
+        for (int i = 0; i < n; i++) {
+            parent[i] = i;
+        }
+    }
+
+    public int find(int node) {
+        if (parent[node] != node) {
+            parent[node] = find(parent[node]);
+        }
+        return parent[node];
+    }
+
+    public int union(int u, int v) {
+        int pu = find(u), pv = find(v);
+        if (pu == pv) {
+            return 0;
+        }
+        if (vals[pu] < vals[pv]) {
+            parent[pu] = pv;
+        } else if (vals[pu] > vals[pv]) {
+            parent[pv] = pu;
+        } else {
+            parent[pv] = pu;
+            int result = count[pu] * count[pv];
+            count[pu] += count[pv];
+            return result;
+        }
+        return 0;
+    }
+}
+
+public class Solution {
+    public int numberOfGoodPaths(int[] vals, int[][] edges) {
+        int n = vals.length;
+        DSU dsu = new DSU(n, vals);
+
+        // Sort edges based on max value of the two nodes
+        Arrays.sort(edges, 
+            Comparator.comparingInt(edge -> Math.max(vals[edge[0]], vals[edge[1]]))
+        );
+
+        int res = n; // Each node alone is a good path
+        for (int[] edge : edges) {
+            res += dsu.union(edge[0], edge[1]);
+        }
+        return res;
+    }
+}
+```
+
+```cpp
+class DSU {
+    vector<int> parent, count, vals;
+
+public:
+    DSU(int n, vector<int>& vals) : vals(vals), parent(n), count(n, 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];
+    }
+
+    int unionNodes(int u, int v) {
+        int pu = find(u), pv = find(v);
+        if (pu == pv) {
+            return 0;
+        }
+        if (vals[pu] < vals[pv]) {
+            parent[pu] = pv;
+        } else if (vals[pu] > vals[pv]) {
+            parent[pv] = pu;
+        } else {
+            parent[pv] = pu;
+            int result = count[pu] * count[pv];
+            count[pu] += count[pv];
+            return result;
+        }
+        return 0;
+    }
+};
+
+class Solution {
+public:
+    int numberOfGoodPaths(vector<int>& vals, vector<vector<int>>& edges) {
+        int n = vals.size();
+        DSU dsu(n, vals);
+
+        // Sort edges based on max value of the two nodes
+        sort(edges.begin(), edges.end(), [&](auto& a, auto& b) {
+            return max(vals[a[0]], vals[a[1]]) < max(vals[b[0]], vals[b[1]]);
+        });
+
+        int res = n; // Each node alone is a good path
+        for (auto& edge : edges) {
+            res += dsu.unionNodes(edge[0], edge[1]);
+        }
+        return res;
+    }
+};
+```
+
+```javascript
+class DSU {
+    /**
+     * @param {number} n
+     * @param {number[]} vals
+     */
+    constructor(n, vals) {
+        this.parent = Array(n).fill(0).map((_, i) => i);
+        this.vals = vals;
+        this.count = Array(n).fill(1); // count of nodes with max value of the component
+    }
+
+    /**
+     * @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} v
+     * @return {number}
+     */
+    union(u, v) {
+        let pu = this.find(u), pv = this.find(v);
+        if (pu === pv) {
+            return 0;
+        }
+        if (this.vals[pu] < this.vals[pv]) {
+            this.parent[pu] = pv;
+        } else if (this.vals[pu] > this.vals[pv]) {
+            this.parent[pv] = pu;
+        } else {
+            this.parent[pv] = pu;
+            let result = this.count[pu] * this.count[pv];
+            this.count[pu] += this.count[pv];
+            return result;
+        }
+        return 0;
+    }
+}
+
+class Solution {
+    /**
+     * @param {number[]} vals
+     * @param {number[][]} edges
+     * @return {number}
+     */
+    numberOfGoodPaths(vals, edges) {
+        let n = vals.length;
+        let dsu = new DSU(n, vals);
+
+        // Sort edges based on max value of the two nodes
+        edges.sort((a, b) => 
+            Math.max(vals[a[0]], vals[a[1]]) - Math.max(vals[b[0]], vals[b[1]])
+        );
+
+        let res = n; // Each node alone is a good path
+        for (let [u, v] of edges) {
+            res += dsu.union(u, v);
+        }
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n\log n)$
+* Space complexity: $O(n)$
\ No newline at end of file
diff --git a/articles/path-with-maximum-probability.md b/articles/path-with-maximum-probability.md
new file mode 100644
index 000000000..b16d1e43b
--- /dev/null
+++ b/articles/path-with-maximum-probability.md
@@ -0,0 +1,632 @@
+## 1. Dijkstra's Algorithm - I
+
+::tabs-start
+
+```python
+class Solution:
+    def maxProbability(self, n: int, edges: List[List[int]], succProb: List[float], start_node: int, end_node: int) -> float:
+        adj = collections.defaultdict(list)
+        for i in range(len(edges)):
+            src, dst = edges[i]
+            adj[src].append((dst, succProb[i]))
+            adj[dst].append((src, succProb[i]))
+
+        pq = [(-1, start_node)]
+        visit = set()
+
+        while pq:
+            prob, cur = heapq.heappop(pq)
+            visit.add(cur)
+
+            if cur == end_node:
+                return -prob
+
+            for nei, edgeProb in adj[cur]:
+                if nei not in visit:
+                    heapq.heappush(pq, (prob * edgeProb, nei))
+
+        return 0.0
+```
+
+```java
+public class Solution {
+    public double maxProbability(int n, int[][] edges, double[] succProb, int start_node, int end_node) {
+        List<Pair>[] adj = new ArrayList[n];
+        for (int i = 0; i < n; i++) adj[i] = new ArrayList<>();
+
+        for (int i = 0; i < edges.length; i++) {
+            int src = edges[i][0], dst = edges[i][1];
+            adj[src].add(new Pair(dst, succProb[i]));
+            adj[dst].add(new Pair(src, succProb[i]));
+        }
+
+        double[] maxProb = new double[n];
+        maxProb[start_node] = 1.0;
+        PriorityQueue<Pair> pq = new PriorityQueue<>((a, b) -> Double.compare(b.prob, a.prob));
+        pq.offer(new Pair(start_node, 1.0));
+
+        while (!pq.isEmpty()) {
+            Pair top = pq.poll();
+            int node = top.node;
+            double curr_prob = top.prob;
+
+            if (node == end_node) return curr_prob;
+            if (curr_prob > maxProb[node]) continue;
+
+            for (Pair nei : adj[node]) {
+                double new_prob = curr_prob * nei.prob;
+                if (new_prob > maxProb[nei.node]) {
+                    maxProb[nei.node] = new_prob;
+                    pq.offer(new Pair(nei.node, new_prob));
+                }
+            }
+        }
+
+        return 0.0;
+    }
+
+    static class Pair {
+        int node;
+        double prob;
+
+        Pair(int node, double prob) {
+            this.node = node;
+            this.prob = prob;
+        }
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    double maxProbability(int n, vector<vector<int>>& edges, vector<double>& succProb, int start_node, int end_node) {
+        vector<vector<pair<int, double>>> adj(n);
+        for (int i = 0; i < edges.size(); i++) {
+            int src = edges[i][0], dst = edges[i][1];
+            adj[src].emplace_back(dst, succProb[i]);
+            adj[dst].emplace_back(src, succProb[i]);
+        }
+
+        vector<double> maxProb(n, 0.0);
+        maxProb[start_node] = 1.0;
+        priority_queue<pair<double, int>> pq;
+        pq.emplace(1.0, start_node);
+
+        while (!pq.empty()) {
+            auto [curr_prob, node] = pq.top(); pq.pop();
+
+            if (node == end_node) return curr_prob;
+            if (curr_prob > maxProb[node]) continue;
+
+            for (auto& [nei, edge_prob] : adj[node]) {
+                double new_prob = curr_prob * edge_prob;
+                if (new_prob > maxProb[nei]) {
+                    maxProb[nei] = new_prob;
+                    pq.emplace(new_prob, nei);
+                }
+            }
+        }
+
+        return 0.0;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number} n
+     * @param {number[][]} edges
+     * @param {number[]} succProb
+     * @param {number} start_node
+     * @param {number} end_node
+     * @return {number}
+     */
+    maxProbability(n, edges, succProb, start_node, end_node) {
+        let adj = new Map();
+        for (let i = 0; i < n; i++) adj.set(i, []);
+
+        for (let i = 0; i < edges.length; i++) {
+            let [src, dst] = edges[i];
+            adj.get(src).push([dst, succProb[i]]);
+            adj.get(dst).push([src, succProb[i]]);
+        }
+
+        let pq = new MaxPriorityQueue({ priority: x => x[0] });
+        pq.enqueue([1.0, start_node]);
+        let visited = new Set();
+
+        while (!pq.isEmpty()) {
+            let [prob, cur] = pq.dequeue().element;
+            visited.add(cur);
+
+            if (cur === end_node) return prob;
+
+            for (let [nei, edgeProb] of adj.get(cur)) {
+                if (!visited.has(nei)) {
+                    pq.enqueue([prob * edgeProb, nei]);
+                }
+            }
+        }
+
+        return 0.0;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O((V + E) \log V)$
+* Space complexity: $O(V + E)$
+
+> Where $V$ is the number nodes and $E$ is the number of edges.
+
+---
+
+## 2. Dijkstra's Algorithm - II
+
+::tabs-start
+
+```python
+class Solution:
+    def maxProbability(self, n: int, edges: List[List[int]], succProb: List[float], start_node: int, end_node: int) -> float:
+        adj = [[] for _ in range(n)]
+        for i in range(len(edges)):
+            src, dst = edges[i]
+            adj[src].append((dst, succProb[i]))
+            adj[dst].append((src, succProb[i]))
+
+        maxProb = [0] * n
+        maxProb[start_node] = 1.0
+        pq = [(-1.0, start_node)]
+
+        while pq:
+            curr_prob, node = heapq.heappop(pq)
+            curr_prob *= -1
+
+            if node == end_node:
+                return curr_prob
+            if curr_prob > maxProb[node]:
+                continue
+
+            for nei, edge_prob in adj[node]:
+                new_prob = curr_prob * edge_prob
+                if new_prob > maxProb[nei]:  
+                    maxProb[nei] = new_prob
+                    heapq.heappush(pq, (-new_prob, nei))
+
+        return 0.0
+```
+
+```java
+public class Solution {
+    public double maxProbability(int n, int[][] edges, double[] succProb, int start_node, int end_node) {
+        List<Pair>[] adj = new ArrayList[n];
+        for (int i = 0; i < n; i++) adj[i] = new ArrayList<>();
+
+        for (int i = 0; i < edges.length; i++) {
+            int src = edges[i][0], dst = edges[i][1];
+            adj[src].add(new Pair(dst, succProb[i]));
+            adj[dst].add(new Pair(src, succProb[i]));
+        }
+
+        double[] maxProb = new double[n];
+        maxProb[start_node] = 1.0;
+        PriorityQueue<Pair> pq = new PriorityQueue<>((a, b) -> Double.compare(b.prob, a.prob));
+        pq.offer(new Pair(start_node, 1.0));
+
+        while (!pq.isEmpty()) {
+            Pair top = pq.poll();
+            int node = top.node;
+            double curr_prob = top.prob;
+
+            if (node == end_node) return curr_prob;
+            if (curr_prob > maxProb[node]) continue;
+
+            for (Pair nei : adj[node]) {
+                double new_prob = curr_prob * nei.prob;
+                if (new_prob > maxProb[nei.node]) {
+                    maxProb[nei.node] = new_prob;
+                    pq.offer(new Pair(nei.node, new_prob));
+                }
+            }
+        }
+
+        return 0.0;
+    }
+
+    static class Pair {
+        int node;
+        double prob;
+
+        Pair(int node, double prob) {
+            this.node = node;
+            this.prob = prob;
+        }
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    double maxProbability(int n, vector<vector<int>>& edges, vector<double>& succProb, int start_node, int end_node) {
+        vector<vector<pair<int, double>>> adj(n);
+        for (int i = 0; i < edges.size(); i++) {
+            int src = edges[i][0], dst = edges[i][1];
+            adj[src].emplace_back(dst, succProb[i]);
+            adj[dst].emplace_back(src, succProb[i]);
+        }
+
+        vector<double> maxProb(n, 0.0);
+        maxProb[start_node] = 1.0;
+        priority_queue<pair<double, int>> pq;
+        pq.emplace(1.0, start_node);
+
+        while (!pq.empty()) {
+            auto [curr_prob, node] = pq.top(); pq.pop();
+
+            if (node == end_node) return curr_prob;
+            if (curr_prob > maxProb[node]) continue;
+
+            for (auto& [nei, edge_prob] : adj[node]) {
+                double new_prob = curr_prob * edge_prob;
+                if (new_prob > maxProb[nei]) {
+                    maxProb[nei] = new_prob;
+                    pq.emplace(new_prob, nei);
+                }
+            }
+        }
+
+        return 0.0;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number} n
+     * @param {number[][]} edges
+     * @param {number[]} succProb
+     * @param {number} start_node
+     * @param {number} end_node
+     * @return {number}
+     */
+    maxProbability(n, edges, succProb, start_node, end_node) {
+        let adj = Array.from({ length: n }, () => []);
+        for (let i = 0; i < edges.length; i++) {
+            let [src, dst] = edges[i];
+            adj[src].push([dst, succProb[i]]);
+            adj[dst].push([src, succProb[i]]);
+        }
+
+        let maxProb = Array(n).fill(0);
+        maxProb[start_node] = 1.0;
+        let pq = new MaxPriorityQueue({ priority: x => x[1] });
+        pq.enqueue([start_node, 1.0]);
+
+        while (!pq.isEmpty()) {
+            let [node, curr_prob] = pq.dequeue().element;
+
+            if (node === end_node) return curr_prob;
+            if (curr_prob > maxProb[node]) continue;
+
+            for (let [nei, edge_prob] of adj[node]) {
+                let new_prob = curr_prob * edge_prob;
+                if (new_prob > maxProb[nei]) {
+                    maxProb[nei] = new_prob;
+                    pq.enqueue([nei, new_prob]);
+                }
+            }
+        }
+
+        return 0.0;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O((V + E) \log V)$
+* Space complexity: $O(V + E)$
+
+> Where $V$ is the number nodes and $E$ is the number of edges.
+
+---
+
+## 3. Bellman Ford Algorithm
+
+::tabs-start
+
+```python
+class Solution:
+    def maxProbability(self, n: int, edges: List[List[int]], succProb: List[float], start_node: int, end_node: int) -> float:
+        maxProb = [0.0] * n
+        maxProb[start_node] = 1.0
+
+        for i in range(n):
+            updated = False
+            for j in range(len(edges)):
+                src, dst = edges[j]
+                if maxProb[src] * succProb[j] > maxProb[dst]:
+                    maxProb[dst] = maxProb[src] * succProb[j]
+                    updated = True
+
+                if maxProb[dst] * succProb[j] > maxProb[src]:
+                    maxProb[src] = maxProb[dst] * succProb[j]
+                    updated = True
+
+            if not updated:
+                break
+
+        return maxProb[end_node]
+```
+
+```java
+public class Solution {
+    public double maxProbability(int n, int[][] edges, double[] succProb, int start_node, int end_node) {
+        double[] maxProb = new double[n];
+        maxProb[start_node] = 1.0;
+
+        for (int i = 0; i < n; i++) {
+            boolean updated = false;
+            for (int j = 0; j < edges.length; j++) {
+                int src = edges[j][0], dst = edges[j][1];
+                
+                if (maxProb[src] * succProb[j] > maxProb[dst]) {
+                    maxProb[dst] = maxProb[src] * succProb[j];
+                    updated = true;
+                }
+                
+                if (maxProb[dst] * succProb[j] > maxProb[src]) {
+                    maxProb[src] = maxProb[dst] * succProb[j];
+                    updated = true;
+                }
+            }
+            if (!updated) break;
+        }
+
+        return maxProb[end_node];
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    double maxProbability(int n, vector<vector<int>>& edges, vector<double>& succProb, int start_node, int end_node) {
+        vector<double> maxProb(n, 0.0);
+        maxProb[start_node] = 1.0;
+
+        for (int i = 0; i < n; i++) {
+            bool updated = false;
+            for (int j = 0; j < edges.size(); j++) {
+                int src = edges[j][0], dst = edges[j][1];
+
+                if (maxProb[src] * succProb[j] > maxProb[dst]) {
+                    maxProb[dst] = maxProb[src] * succProb[j];
+                    updated = true;
+                }
+
+                if (maxProb[dst] * succProb[j] > maxProb[src]) {
+                    maxProb[src] = maxProb[dst] * succProb[j];
+                    updated = true;
+                }
+            }
+            if (!updated) break;
+        }
+
+        return maxProb[end_node];
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number} n
+     * @param {number[][]} edges
+     * @param {number[]} succProb
+     * @param {number} start_node
+     * @param {number} end_node
+     * @return {number}
+     */
+    maxProbability(n, edges, succProb, start_node, end_node) {
+        let maxProb = new Array(n).fill(0.0);
+        maxProb[start_node] = 1.0;
+
+        for (let i = 0; i < n; i++) {
+            let updated = false;
+            for (let j = 0; j < edges.length; j++) {
+                let [src, dst] = edges[j];
+
+                if (maxProb[src] * succProb[j] > maxProb[dst]) {
+                    maxProb[dst] = maxProb[src] * succProb[j];
+                    updated = true;
+                }
+
+                if (maxProb[dst] * succProb[j] > maxProb[src]) {
+                    maxProb[src] = maxProb[dst] * succProb[j];
+                    updated = true;
+                }
+            }
+            if (!updated) break;
+        }
+
+        return maxProb[end_node];
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(V * E)$
+* Space complexity: $O(V)$
+
+> Where $V$ is the number nodes and $E$ is the number of edges.
+
+---
+
+## 4. Shortest Path Faster Algorithm
+
+::tabs-start
+
+```python
+class Solution:
+    def maxProbability(self, n: int, edges: List[List[int]], succProb: List[float], start_node: int, end_node: int) -> float:
+        adj = [[] for _ in range(n)]
+        for i in range(len(edges)):
+            src, dst = edges[i]
+            adj[src].append((dst, succProb[i]))
+            adj[dst].append((src, succProb[i]))
+
+        maxProb = [0.0] * n
+        maxProb[start_node] = 1.0
+        q = deque([start_node])
+
+        while q:
+            node = q.popleft()
+
+            for nei, edge_prob in adj[node]:
+                new_prob = maxProb[node] * edge_prob
+                if new_prob > maxProb[nei]:  
+                    maxProb[nei] = new_prob
+                    q.append(nei)
+
+        return maxProb[end_node]
+```
+
+```java
+public class Solution {
+    public double maxProbability(int n, int[][] edges, double[] succProb, int start_node, int end_node) {
+        List<Pair>[] adj = new ArrayList[n];
+        for (int i = 0; i < n; i++) adj[i] = new ArrayList<>();
+
+        for (int i = 0; i < edges.length; i++) {
+            int src = edges[i][0], dst = edges[i][1];
+            adj[src].add(new Pair(dst, succProb[i]));
+            adj[dst].add(new Pair(src, succProb[i]));
+        }
+
+        double[] maxProb = new double[n];
+        maxProb[start_node] = 1.0;
+        Queue<Integer> q = new LinkedList<>();
+        q.offer(start_node);
+
+        while (!q.isEmpty()) {
+            int node = q.poll();
+
+            for (Pair nei : adj[node]) {
+                double newProb = maxProb[node] * nei.prob;
+                if (newProb > maxProb[nei.node]) {
+                    maxProb[nei.node] = newProb;
+                    q.offer(nei.node);
+                }
+            }
+        }
+
+        return maxProb[end_node];
+    }
+
+    static class Pair {
+        int node;
+        double prob;
+
+        Pair(int node, double prob) {
+            this.node = node;
+            this.prob = prob;
+        }
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    double maxProbability(int n, vector<vector<int>>& edges, vector<double>& succProb, int start_node, int end_node) {
+        vector<vector<pair<int, double>>> adj(n);
+
+        for (int i = 0; i < edges.size(); i++) {
+            int src = edges[i][0], dst = edges[i][1];
+            adj[src].emplace_back(dst, succProb[i]);
+            adj[dst].emplace_back(src, succProb[i]);
+        }
+
+        vector<double> maxProb(n, 0.0);
+        maxProb[start_node] = 1.0;
+        queue<int> q;
+        q.push(start_node);
+
+        while (!q.empty()) {
+            int node = q.front();
+            q.pop();
+
+            for (auto& [nei, edgeProb] : adj[node]) {
+                double newProb = maxProb[node] * edgeProb;
+                if (newProb > maxProb[nei]) {
+                    maxProb[nei] = newProb;
+                    q.push(nei);
+                }
+            }
+        }
+
+        return maxProb[end_node];
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number} n
+     * @param {number[][]} edges
+     * @param {number[]} succProb
+     * @param {number} start_node
+     * @param {number} end_node
+     * @return {number}
+     */
+    maxProbability(n, edges, succProb, start_node, end_node) {
+        let adj = Array.from({ length: n }, () => []);
+        for (let i = 0; i < edges.length; i++) {
+            let [src, dst] = edges[i];
+            adj[src].push([dst, succProb[i]]);
+            adj[dst].push([src, succProb[i]]);
+        }
+
+        let maxProb = new Array(n).fill(0.0);
+        maxProb[start_node] = 1.0;
+        const q = new Queue([start_node]);
+
+        while (!q.isEmpty()) {
+            let node = q.pop();
+
+            for (let [nei, edgeProb] of adj[node]) {
+                let newProb = maxProb[node] * edgeProb;
+                if (newProb > maxProb[nei]) {
+                    maxProb[nei] = newProb;
+                    q.push(nei);
+                }
+            }
+        }
+
+        return maxProb[end_node];
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(V * E)$
+* Space complexity: $O(V + E)$
+
+> Where $V$ is the number nodes and $E$ is the number of edges.
\ No newline at end of file
diff --git a/articles/reveal-cards-in-increasing-order.md b/articles/reveal-cards-in-increasing-order.md
new file mode 100644
index 000000000..4759af658
--- /dev/null
+++ b/articles/reveal-cards-in-increasing-order.md
@@ -0,0 +1,406 @@
+## 1. Simulation Using Queue - I
+
+::tabs-start
+
+```python
+class Solution:
+    def deckRevealedIncreasing(self, deck: List[int]) -> List[int]:
+        deck.sort()
+        res = [0] * len(deck)
+        q = deque(range(len(deck)))
+
+        for num in deck:
+            i = q.popleft()
+            res[i] = num
+            if q:
+                q.append(q.popleft())
+
+        return res
+```
+
+```java
+public class Solution {
+    public int[] deckRevealedIncreasing(int[] deck) {
+        Arrays.sort(deck);
+        int n = deck.length;
+        int[] res = new int[n];
+        Queue<Integer> q = new LinkedList<>();
+
+        for (int i = 0; i < n; i++) {
+            q.offer(i);
+        }
+
+        for (int num : deck) {
+            int i = q.poll();
+            res[i] = num;
+            if (!q.isEmpty()) {
+                q.offer(q.poll());
+            }
+        }
+
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    vector<int> deckRevealedIncreasing(vector<int>& deck) {
+        sort(deck.begin(), deck.end());
+        int n = deck.size();
+        vector<int> res(n);
+        queue<int> q;
+
+        for (int i = 0; i < n; i++) {
+            q.push(i);
+        }
+
+        for (int num : deck) {
+            int i = q.front();
+            q.pop();
+            res[i] = num;
+            if (!q.empty()) {
+                q.push(q.front());
+                q.pop();
+            }
+        }
+
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} deck
+     * @return {number[]}
+     */
+    deckRevealedIncreasing(deck) {
+        deck.sort((a, b) => a - b);
+        let n = deck.length;
+        let res = new Array(n).fill(0);
+        const q = new Queue();
+
+        for (let i = 0; i < n; i++) {
+            q.push(i);
+        }
+
+        for (let num of deck) {
+            let i = q.pop();
+            res[i] = num;
+            if (!q.isEmpty()) {
+                q.push(q.pop());
+            }
+        }
+
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n \log n)$
+* Space complexity: $O(n)$
+
+---
+
+## 2. Simuation Using Queue - II
+
+::tabs-start
+
+```python
+class Solution:
+    def deckRevealedIncreasing(self, deck: List[int]) -> List[int]:
+        deck.sort()
+        q = deque()
+        for i in range(len(deck) - 1, -1, -1):
+            if q:
+                q.append(q.popleft())
+            q.append(deck[i])
+        return list(q)[::-1]
+```
+
+```java
+public class Solution {
+    public int[] deckRevealedIncreasing(int[] deck) {
+        Arrays.sort(deck);
+        Queue<Integer> q = new LinkedList<>();
+
+        for (int i = deck.length - 1; i >= 0; i--) {
+            if (!q.isEmpty()) {
+                q.offer(q.poll());
+            }
+            q.offer(deck[i]);
+        }
+
+        int[] res = new int[deck.length];
+        for (int i = deck.length - 1; i >= 0; i--) {
+            res[i] = q.poll();
+        }
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    vector<int> deckRevealedIncreasing(vector<int>& deck) {
+        sort(deck.begin(), deck.end());
+        queue<int> q;
+
+        for (int i = deck.size() - 1; i >= 0; i--) {
+            if (!q.empty()) {
+                q.push(q.front());
+                q.pop();
+            }
+            q.push(deck[i]);
+        }
+
+        vector<int> res(deck.size());
+        for (int i = deck.size() - 1; i >= 0; i--) {
+            res[i] = q.front();
+            q.pop();
+        }
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} deck
+     * @return {number[]}
+     */
+    deckRevealedIncreasing(deck) {
+        deck.sort((a, b) => a - b);
+        const q = new Queue();
+
+        for (let i = deck.length - 1; i >= 0; i--) {
+            if (!q.isEmpty()) {
+                q.push(q.pop());
+            }
+            q.push(deck[i]);
+        }
+
+        return q.toArray().reverse();
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n \log n)$
+* Space complexity: $O(n)$
+
+---
+
+## 3. Simulation Using Deque
+
+::tabs-start
+
+```python
+class Solution:
+    def deckRevealedIncreasing(self, deck: List[int]) -> List[int]:
+        deck.sort()
+        dq = deque()
+        dq.append(deck.pop())
+        for i in range(len(deck) - 1, -1, -1):
+            dq.appendleft(dq.pop())
+            dq.appendleft(deck[i])
+        return list(dq)
+```
+
+```java
+public class Solution {
+    public int[] deckRevealedIncreasing(int[] deck) {
+        int n = deck.length;
+        Arrays.sort(deck);
+        Deque<Integer> dq = new LinkedList<>();
+        dq.addLast(deck[n - 1]);
+
+        for (int i = n - 2; i >= 0; i--) {
+            dq.addFirst(dq.removeLast());
+            dq.addFirst(deck[i]);
+        }
+
+        return dq.stream().mapToInt(Integer::intValue).toArray();
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    vector<int> deckRevealedIncreasing(vector<int>& deck) {
+        sort(deck.begin(), deck.end());
+        deque<int> dq;
+        dq.push_back(deck.back());
+
+        for (int i = deck.size() - 2; i >= 0; i--) {
+            dq.push_front(dq.back());
+            dq.pop_back();
+            dq.push_front(deck[i]);
+        }
+
+        return vector<int>(dq.begin(), dq.end());
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} deck
+     * @return {number[]}
+     */
+    deckRevealedIncreasing(deck) {
+        deck.sort((a, b) => a - b);
+        const dq = new Deque([deck.pop()]);
+
+        for (let i = deck.length - 1; i >= 0; i--) {
+            let val = dq.popBack();
+            dq.pushFront(val);
+            dq.pushFront(deck[i]);
+        }
+
+        let res = [];
+        while (!dq.isEmpty()) {
+            res.push(dq.popFront());
+        }
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n \log n)$
+* Space complexity: $O(n)$
+
+---
+
+## 4. Simulation Using Two Pointers
+
+::tabs-start
+
+```python
+class Solution:
+    def deckRevealedIncreasing(self, deck: List[int]) -> List[int]:
+        n = len(deck)
+        res = [0] * n
+        skip = False
+        deckIndex, i = 0, 0
+
+        deck.sort()
+
+        while deckIndex < n:
+            if res[i] == 0:
+                if not skip:
+                    res[i] = deck[deckIndex]
+                    deckIndex += 1
+                skip = not skip
+            i = (i + 1) % n
+
+        return res
+```
+
+```java
+public class Solution {
+    public int[] deckRevealedIncreasing(int[] deck) {
+        int n = deck.length;
+        int[] res = new int[n];
+        Arrays.fill(res, 0);
+        boolean skip = false;
+        int deckIndex = 0, i = 0;
+
+        Arrays.sort(deck);
+
+        while (deckIndex < n) {
+            if (res[i] == 0) {
+                if (!skip) {
+                    res[i] = deck[deckIndex++];
+                }
+                skip = !skip;
+            }
+            i = (i + 1) % n;
+        }
+
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    vector<int> deckRevealedIncreasing(vector<int>& deck) {
+        int n = deck.size();
+        vector<int> res(n, 0);
+        bool skip = false;
+        int deckIndex = 0, i = 0;
+
+        sort(deck.begin(), deck.end());
+
+        while (deckIndex < n) {
+            if (res[i] == 0) {
+                if (!skip) {
+                    res[i] = deck[deckIndex++];
+                }
+                skip = !skip;
+            }
+            i = (i + 1) % n;
+        }
+
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} deck
+     * @return {number[]}
+     */
+    deckRevealedIncreasing(deck) {
+        let n = deck.length;
+        let res = new Array(n).fill(0);
+        let skip = false;
+        let deckIndex = 0, i = 0;
+
+        deck.sort((a, b) => a - b);
+
+        while (deckIndex < n) {
+            if (res[i] === 0) {
+                if (!skip) {
+                    res[i] = deck[deckIndex++];
+                }
+                skip = !skip;
+            }
+            i = (i + 1) % n;
+        }
+
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n \log n)$
+* Space complexity:
+    * $O(1)$ or $O(n)$ space depending on the sorting algorithm.
+    * $O(n)$ space for the output array.
\ No newline at end of file

From 6b1f6d1c48ab53a173c510a8f55519fffb4d49e6 Mon Sep 17 00:00:00 2001
From: Sri Hari <kataresrihari@gmail.com>
Date: Sun, 9 Feb 2025 23:20:35 +0530
Subject: [PATCH 08/13] Batch-5/Neetcode-ALL/Added-articles

---
 articles/knight-dialer.md                     | 946 ++++++++++++++++++
 articles/largest-divisible-subset.md          | 738 ++++++++++++++
 ...imum-number-of-arrows-to-burst-balloons.md | 183 ++++
 articles/partition-array-for-maximum-sum.md   | 446 +++++++++
 ...f-edges-to-keep-graph-fully-traversable.md | 274 +++++
 5 files changed, 2587 insertions(+)
 create mode 100644 articles/knight-dialer.md
 create mode 100644 articles/largest-divisible-subset.md
 create mode 100644 articles/minimum-number-of-arrows-to-burst-balloons.md
 create mode 100644 articles/partition-array-for-maximum-sum.md
 create mode 100644 articles/remove-max-number-of-edges-to-keep-graph-fully-traversable.md

diff --git a/articles/knight-dialer.md b/articles/knight-dialer.md
new file mode 100644
index 000000000..9c87f4c13
--- /dev/null
+++ b/articles/knight-dialer.md
@@ -0,0 +1,946 @@
+## 1. Recursion
+
+::tabs-start
+
+```python
+class Solution:
+    def knightDialer(self, n: int) -> int:
+        if n == 1:
+            return 10
+
+        mod = 1000000007
+        jumps = [
+            [4, 6], [6, 8], [7, 9], [4, 8], [0, 3, 9],
+            [], [0, 1, 7], [2, 6], [1, 3], [2, 4]
+        ]
+
+        def dfs(n, d):
+            if n == 0:
+                return 1
+
+            res = 0
+            for j in jumps[d]:
+                res = (res + dfs(n - 1, j)) % mod
+            return res
+
+        res = 0
+        for d in range(10):
+            res = (res + dfs(n - 1, d)) % mod
+        return res
+```
+
+```java
+public class Solution {
+    private static final int MOD = 1000000007;
+    private static final int[][] jumps = {
+        {4, 6}, {6, 8}, {7, 9}, {4, 8}, {0, 3, 9},
+        {}, {0, 1, 7}, {2, 6}, {1, 3}, {2, 4}
+    };
+
+    public int knightDialer(int n) {
+        if (n == 1) return 10;
+        int res = 0;
+
+        for (int d = 0; d < 10; d++) {
+            res = (res + dfs(n - 1, d)) % MOD;
+        }
+        return res;
+    }
+
+    private int dfs(int n, int d) {
+        if (n == 0) return 1;
+
+        int res = 0;
+        for (int next : jumps[d]) {
+            res = (res + dfs(n - 1, next)) % MOD;
+        }
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+private:
+    static constexpr int MOD = 1000000007;
+    const vector<vector<int>> jumps = {
+        {4, 6}, {6, 8}, {7, 9}, {4, 8}, {0, 3, 9},
+        {}, {0, 1, 7}, {2, 6}, {1, 3}, {2, 4}
+    };
+
+public:
+    int knightDialer(int n) {
+        if (n == 1) return 10;
+        int res = 0;
+
+        for (int d = 0; d < 10; d++) {
+            res = (res + dfs(n - 1, d)) % MOD;
+        }
+        return res;
+    }
+
+private:
+    int dfs(int n, int d) {
+        if (n == 0) return 1;
+
+        int res = 0;
+        for (int next : jumps[d]) {
+            res = (res + dfs(n - 1, next)) % MOD;
+        }
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number} n
+     * @return {number}
+     */
+    knightDialer(n) {
+        if (n === 1) return 10;
+        const MOD = 1000000007;
+        const jumps = [
+            [4, 6], [6, 8], [7, 9], [4, 8], [0, 3, 9],
+            [], [0, 1, 7], [2, 6], [1, 3], [2, 4]
+        ];
+
+        const dfs = (n, d) => {
+            if (n === 0) return 1;
+
+            let res = 0;
+            for (const next of jumps[d]) {
+                res = (res + dfs(n - 1, next)) % MOD;
+            }
+            return res;
+        };
+
+        let res = 0;
+        for (let d = 0; d < 10; d++) {
+            res = (res + dfs(n - 1, d)) % MOD;
+        }
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(3 ^ n)$
+* Space complexity: $O(n)$ for recursion stack.
+
+---
+
+## 2. Dynamic Programming (Top-Down)
+
+::tabs-start
+
+```python
+class Solution:
+    def knightDialer(self, n: int) -> int:
+        if n == 1:
+            return 10
+
+        mod = 1000000007
+        jumps = [
+            [4, 6], [6, 8], [7, 9], [4, 8], [0, 3, 9],
+            [], [0, 1, 7], [2, 6], [1, 3], [2, 4]
+        ]
+
+        dp = [[-1] * (n + 1) for _ in range(10)]
+
+        def dfs(n, d):
+            if n == 0:
+                return 1
+            if dp[d][n] != -1:
+                return dp[d][n]
+            
+            dp[d][n] = 0
+            for j in jumps[d]:
+                dp[d][n] = (dp[d][n] + dfs(n - 1, j)) % mod
+            return dp[d][n]
+
+        res = 0
+        for d in range(10):
+            res = (res + dfs(n - 1, d)) % mod
+        return res
+```
+
+```java
+public class Solution {
+    private static final int MOD = 1000000007;
+    private static final int[][] jumps = {
+        {4, 6}, {6, 8}, {7, 9}, {4, 8}, {0, 3, 9},
+        {}, {0, 1, 7}, {2, 6}, {1, 3}, {2, 4}
+    };
+    private int[][] dp;
+
+    public int knightDialer(int n) {
+        if (n == 1) return 10;
+        dp = new int[10][n + 1];
+        for (int[] row : dp) Arrays.fill(row, -1);
+
+        int res = 0;
+        for (int d = 0; d < 10; d++) {
+            res = (res + dfs(n - 1, d)) % MOD;
+        }
+        return res;
+    }
+
+    private int dfs(int n, int d) {
+        if (n == 0) return 1;
+        if (dp[d][n] != -1) return dp[d][n];
+
+        dp[d][n] = 0;
+        for (int next : jumps[d]) {
+            dp[d][n] = (dp[d][n] + dfs(n - 1, next)) % MOD;
+        }
+        return dp[d][n];
+    }
+}
+```
+
+```cpp
+class Solution {
+private:
+    static constexpr int MOD = 1000000007;
+    vector<vector<int>> jumps = {
+        {4, 6}, {6, 8}, {7, 9}, {4, 8}, {0, 3, 9},
+        {}, {0, 1, 7}, {2, 6}, {1, 3}, {2, 4}
+    };
+    vector<vector<int>> dp;
+
+public:
+    int knightDialer(int n) {
+        if (n == 1) return 10;
+        dp.assign(10, vector<int>(n + 1, -1));
+
+        int res = 0;
+        for (int d = 0; d < 10; d++) {
+            res = (res + dfs(n - 1, d)) % MOD;
+        }
+        return res;
+    }
+
+private:
+    int dfs(int n, int d) {
+        if (n == 0) return 1;
+        if (dp[d][n] != -1) return dp[d][n];
+
+        dp[d][n] = 0;
+        for (int next : jumps[d]) {
+            dp[d][n] = (dp[d][n] + dfs(n - 1, next)) % MOD;
+        }
+        return dp[d][n];
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number} n
+     * @return {number}
+     */
+    knightDialer(n) {
+        if (n === 1) return 10;
+        const MOD = 1000000007;
+        const jumps = [
+            [4, 6], [6, 8], [7, 9], [4, 8], [0, 3, 9],
+            [], [0, 1, 7], [2, 6], [1, 3], [2, 4]
+        ];
+
+        const dp = Array.from({ length: 10 }, () => Array(n + 1).fill(-1));
+
+        const dfs = (n, d) => {
+            if (n === 0) return 1;
+            if (dp[d][n] !== -1) return dp[d][n];
+
+            dp[d][n] = 0;
+            for (const next of jumps[d]) {
+                dp[d][n] = (dp[d][n] + dfs(n - 1, next)) % MOD;
+            }
+            return dp[d][n];
+        };
+
+        let res = 0;
+        for (let d = 0; d < 10; d++) {
+            res = (res + dfs(n - 1, d)) % MOD;
+        }
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(n)$
+
+---
+
+## 3. Dynamic Programming (Bottom-Up)
+
+::tabs-start
+
+```python
+class Solution:
+    def knightDialer(self, n: int) -> int:
+        if n == 1:
+            return 10
+
+        mod = 1000000007
+        jumps = [
+            [4, 6], [6, 8], [7, 9], [4, 8], [0, 3, 9],
+            [], [0, 1, 7], [2, 6], [1, 3], [2, 4]
+        ]
+
+        dp = [[0] * (n + 1) for _ in range(10)]
+
+        for d in range(10):
+            dp[d][0] = 1
+
+        for step in range(1, n):
+            for d in range(10):
+                dp[d][step] = sum(dp[j][step - 1] for j in jumps[d]) % mod
+
+        return sum(dp[d][n - 1] for d in range(10)) % mod
+```
+
+```java
+public class Solution {
+    private static final int MOD = 1000000007;
+    private static final int[][] jumps = {
+        {4, 6}, {6, 8}, {7, 9}, {4, 8}, {0, 3, 9},
+        {}, {0, 1, 7}, {2, 6}, {1, 3}, {2, 4}
+    };
+
+    public int knightDialer(int n) {
+        if (n == 1) return 10;
+        
+        int[][] dp = new int[10][n + 1];
+        for (int d = 0; d < 10; d++) {
+            dp[d][0] = 1;
+        }
+
+        for (int step = 1; step < n; step++) {
+            for (int d = 0; d < 10; d++) {
+                for (int j : jumps[d]) {
+                    dp[d][step] = (dp[d][step] + dp[j][step - 1]) % MOD;
+                }
+            }
+        }
+
+        int res = 0;
+        for (int d = 0; d < 10; d++) {
+            res = (res + dp[d][n - 1]) % MOD;
+        }
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+private:
+    static constexpr int MOD = 1000000007;
+    vector<vector<int>> jumps = {
+        {4, 6}, {6, 8}, {7, 9}, {4, 8}, {0, 3, 9},
+        {}, {0, 1, 7}, {2, 6}, {1, 3}, {2, 4}
+    };
+
+public:
+    int knightDialer(int n) {
+        if (n == 1) return 10;
+        
+        vector<vector<int>> dp(10, vector<int>(n + 1, 0));
+        for (int d = 0; d < 10; d++) {
+            dp[d][0] = 1;
+        }
+
+        for (int step = 1; step < n; step++) {
+            for (int d = 0; d < 10; d++) {
+                for (int j : jumps[d]) {
+                    dp[d][step] = (dp[d][step] + dp[j][step - 1]) % MOD;
+                }
+            }
+        }
+
+        int res = 0;
+        for (int d = 0; d < 10; d++) {
+            res = (res + dp[d][n - 1]) % MOD;
+        }
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number} n
+     * @return {number}
+     */
+    knightDialer(n) {
+        if (n === 1) return 10;
+        const MOD = 1000000007;
+        const jumps = [
+            [4, 6], [6, 8], [7, 9], [4, 8], [0, 3, 9],
+            [], [0, 1, 7], [2, 6], [1, 3], [2, 4]
+        ];
+
+        const dp = Array.from({ length: 10 }, () => Array(n + 1).fill(0));
+        for (let d = 0; d < 10; d++) {
+            dp[d][0] = 1;
+        }
+
+        for (let step = 1; step < n; step++) {
+            for (let d = 0; d < 10; d++) {
+                for (const j of jumps[d]) {
+                    dp[d][step] = (dp[d][step] + dp[j][step - 1]) % MOD;
+                }
+            }
+        }
+
+        let res = 0;
+        for (let d = 0; d < 10; d++) {
+            res = (res + dp[d][n - 1]) % MOD;
+        }
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(n)$
+
+---
+
+## 4. Dynamic Programming (Space Optimized)
+
+::tabs-start
+
+```python
+class Solution:
+    def knightDialer(self, n: int) -> int:
+        if n == 1:
+            return 10
+
+        mod = 1000000007
+        jumps = [
+            [4, 6], [6, 8], [7, 9], [4, 8], [0, 3, 9],
+            [], [0, 1, 7], [2, 6], [1, 3], [2, 4]
+        ]
+
+        dp = [1] * 10
+        for step in range(n - 1):
+            next_dp = [0] * 10
+            for d in range(10):
+                for j in jumps[d]:
+                    next_dp[j] = (next_dp[j] + dp[d]) % mod
+            dp = next_dp
+
+        res = 0
+        for d in dp:
+            res = (res + d) % mod
+        return res
+```
+
+```java
+public class Solution {
+    private static final int MOD = 1000000007;
+    private static final int[][] jumps = {
+        {4, 6}, {6, 8}, {7, 9}, {4, 8}, {0, 3, 9},
+        {}, {0, 1, 7}, {2, 6}, {1, 3}, {2, 4}
+    };
+
+    public int knightDialer(int n) {
+        if (n == 1) return 10;
+
+        int[] dp = new int[10];
+        Arrays.fill(dp, 1);
+
+        for (int step = 0; step < n - 1; step++) {
+            int[] nextDp = new int[10];
+            for (int d = 0; d < 10; d++) {
+                for (int j : jumps[d]) {
+                    nextDp[j] = (nextDp[j] + dp[d]) % MOD;
+                }
+            }
+            dp = nextDp;
+        }
+
+        int res = 0;
+        for (int d : dp) {
+            res = (res + d) % MOD;
+        }
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+private:
+    static constexpr int MOD = 1000000007;
+    vector<vector<int>> jumps = {
+        {4, 6}, {6, 8}, {7, 9}, {4, 8}, {0, 3, 9},
+        {}, {0, 1, 7}, {2, 6}, {1, 3}, {2, 4}
+    };
+
+public:
+    int knightDialer(int n) {
+        if (n == 1) return 10;
+        
+        vector<int> dp(10, 1);
+
+        for (int step = 0; step < n - 1; step++) {
+            vector<int> nextDp(10, 0);
+            for (int d = 0; d < 10; d++) {
+                for (int j : jumps[d]) {
+                    nextDp[j] = (nextDp[j] + dp[d]) % MOD;
+                }
+            }
+            dp = nextDp;
+        }
+
+        int res = 0;
+        for (int d : dp) {
+            res = (res + d) % MOD;
+        }
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number} n
+     * @return {number}
+     */
+    knightDialer(n) {
+        if (n === 1) return 10;
+        const MOD = 1000000007;
+        const jumps = [
+            [4, 6], [6, 8], [7, 9], [4, 8], [0, 3, 9],
+            [], [0, 1, 7], [2, 6], [1, 3], [2, 4]
+        ];
+
+        let dp = new Array(10).fill(1);
+
+        for (let step = 0; step < n - 1; step++) {
+            let nextDp = new Array(10).fill(0);
+            for (let d = 0; d < 10; d++) {
+                for (const j of jumps[d]) {
+                    nextDp[j] = (nextDp[j] + dp[d]) % MOD;
+                }
+            }
+            dp = nextDp;
+        }
+
+        return dp.reduce((res, d) => (res + d) % MOD, 0);
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(1)$
+
+---
+
+## 5. Dynamic Programming (Optimal)
+
+::tabs-start
+
+```python
+class Solution:
+    def knightDialer(self, n: int) -> int:
+        if n == 1:
+            return 10
+
+        mod = 10**9 + 7
+        jumps = [1, 4, 2, 2]  # [D, A, B, C]
+
+        for _ in range(n - 1):
+            tmp = [0] * 4
+            tmp[0] = jumps[3]
+            tmp[1] = 2 * jumps[2] + 2 * jumps[3]
+            tmp[2] = jumps[1]
+            tmp[3] = 2 * jumps[0] + jumps[1]
+            jumps = tmp
+
+        return sum(jumps) % mod
+```
+
+```java
+public class Solution {
+    public int knightDialer(int n) {
+        if (n == 1) return 10;
+
+        int MOD = 1000000007;
+        long[] jumps = {1, 4, 2, 2}; // [D, A, B, C]
+
+        for (int i = 0; i < n - 1; i++) {
+            long[] tmp = new long[4];
+            tmp[0] = jumps[3];
+            tmp[1] = (2 * jumps[2] + 2 * jumps[3]) % MOD;
+            tmp[2] = jumps[1];
+            tmp[3] = (2 * jumps[0] + jumps[1]) % MOD;
+            jumps = tmp;
+        }
+
+        long res = 0;
+        for (long num : jumps) {
+            res = (res + num) % MOD;
+        }
+        return (int) res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int knightDialer(int n) {
+        if (n == 1) return 10;
+
+        const int MOD = 1000000007;
+        vector<long long> jumps = {1, 4, 2, 2}; // [D, A, B, C]
+
+        for (int i = 0; i < n - 1; i++) {
+            vector<long long> tmp(4);
+            tmp[0] = jumps[3];
+            tmp[1] = (2 * jumps[2] + 2 * jumps[3]) % MOD;
+            tmp[2] = jumps[1];
+            tmp[3] = (2 * jumps[0] + jumps[1]) % MOD;
+            jumps = tmp;
+        }
+
+        return (jumps[0] + jumps[1] + jumps[2] + jumps[3]) % MOD;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number} n
+     * @return {number}
+     */
+    knightDialer(n) {
+        if (n === 1) return 10;
+
+        const MOD = 1000000007;
+        let jumps = [1, 4, 2, 2]; // [D, A, B, C]
+
+        for (let i = 0; i < n - 1; i++) {
+            let tmp = new Array(4).fill(0);
+            tmp[0] = jumps[3];
+            tmp[1] = (2 * jumps[2] + 2 * jumps[3]) % MOD;
+            tmp[2] = jumps[1];
+            tmp[3] = (2 * jumps[0] + jumps[1]) % MOD;
+            jumps = tmp;
+        }
+
+        return jumps.reduce((sum, num) => (sum + num) % MOD, 0);
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(1)$
+
+---
+
+## 6. Matrix Exponentiation
+
+::tabs-start
+
+```python
+class Matrix:
+    def __init__(self, size):
+        self.n = size
+        self.a = [[0] * size for _ in range(size)]
+
+    def __mul__(self, other):
+        n = self.n
+        MOD = 10**9 + 7
+        product = Matrix(n)
+        for i in range(n):
+            for j in range(n):
+                for k in range(n):
+                    product.a[i][k] = (product.a[i][k] + self.a[i][j] * other.a[j][k]) % MOD
+        return product
+
+
+def matpow(mat, n, size):
+    res = Matrix(size)
+    for i in range(size):
+        res.a[i][i] = 1  # Identity matrix
+
+    while n:
+        if n & 1:
+            res = res * mat
+        mat = mat * mat
+        n >>= 1
+
+    return res
+
+
+class Solution:
+    def knightDialer(self, n: int) -> int:
+        if n == 1:
+            return 10
+
+        MOD = 10**9 + 7
+        jumps = [
+            [4, 6], [6, 8], [7, 9], [4, 8], [0, 3, 9],
+            [], [0, 1, 7], [2, 6], [1, 3], [2, 4]
+        ]
+
+        mat = Matrix(10)
+        for i in range(10):
+            for j in jumps[i]:
+                mat.a[i][j] = 1
+
+        res = matpow(mat, n - 1, 10)
+
+        ans = sum(sum(res.a[i]) for i in range(10)) % MOD
+        return ans
+```
+
+```java
+class Matrix {
+    int[][] a;
+    int size;
+    static final int MOD = 1_000_000_007;
+
+    public Matrix(int size) {
+        this.size = size;
+        a = new int[size][size];
+    }
+
+    public Matrix multiply(Matrix other) {
+        Matrix product = new Matrix(size);
+        for (int i = 0; i < size; i++) {
+            for (int j = 0; j < size; j++) {
+                for (int k = 0; k < size; k++) {
+                    product.a[i][k] = (int)((product.a[i][k] + (long) a[i][j] * other.a[j][k]) % MOD);
+                }
+            }
+        }
+        return product;
+    }
+}
+
+public class Solution {
+    private Matrix matpow(Matrix mat, int n, int size) {
+        Matrix res = new Matrix(size);
+        for (int i = 0; i < size; i++) {
+            res.a[i][i] = 1;  // Identity matrix
+        }
+
+        while (n > 0) {
+            if ((n & 1) == 1) {
+                res = res.multiply(mat);
+            }
+            mat = mat.multiply(mat);
+            n >>= 1;
+        }
+        return res;
+    }
+
+    public int knightDialer(int n) {
+        if (n == 1) return 10;
+
+        int[][] jumps = {
+            {4, 6}, {6, 8}, {7, 9}, {4, 8}, {0, 3, 9},
+            {}, {0, 1, 7}, {2, 6}, {1, 3}, {2, 4}
+        };
+
+        Matrix mat = new Matrix(10);
+        for (int i = 0; i < 10; i++) {
+            for (int j : jumps[i]) {
+                mat.a[i][j] = 1;
+            }
+        }
+
+        Matrix res = matpow(mat, n - 1, 10);
+
+        int ans = 0;
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+                ans = (ans + res.a[i][j]) % Matrix.MOD;
+            }
+        }
+        return ans;
+    }
+}
+```
+
+```cpp
+class Matrix {
+public:
+    vector<vector<int>> a;
+    int size;
+    static const int MOD = 1'000'000'007;
+
+    Matrix(int n) : size(n) {
+        a.assign(n, vector<int>(n, 0));
+    }
+
+    Matrix operator*(const Matrix &other) const {
+        Matrix product(size);
+        for (int i = 0; i < size; i++) {
+            for (int j = 0; j < size; j++) {
+                for (int k = 0; k < size; k++) {
+                    product.a[i][k] = (product.a[i][k] + 1LL * a[i][j] * other.a[j][k]) % MOD;
+                }
+            }
+        }
+        return product;
+    }
+};
+
+Matrix matpow(Matrix mat, int n, int size) {
+    Matrix res(size);
+    for (int i = 0; i < size; i++) {
+        res.a[i][i] = 1; // Identity matrix
+    }
+
+    while (n > 0) {
+        if (n & 1) res = res * mat;
+        mat = mat * mat;
+        n >>= 1;
+    }
+    return res;
+}
+
+class Solution {
+public:
+    int knightDialer(int n) {
+        if (n == 1) return 10;
+
+        vector<vector<int>> jumps = {
+            {4, 6}, {6, 8}, {7, 9}, {4, 8}, {0, 3, 9},
+            {}, {0, 1, 7}, {2, 6}, {1, 3}, {2, 4}
+        };
+
+        Matrix mat(10);
+        for (int i = 0; i < 10; i++) {
+            for (int j : jumps[i]) {
+                mat.a[i][j] = 1;
+            }
+        }
+
+        Matrix res = matpow(mat, n - 1, 10);
+
+        int ans = 0;
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+                ans = (ans + res.a[i][j]) % Matrix::MOD;
+            }
+        }
+        return ans;
+    }
+};
+```
+
+```javascript
+class Matrix {
+    constructor(size) {
+        this.size = size;
+        this.a = Array.from({ length: size }, () => Array(size).fill(0));
+        this.MOD = BigInt(1e9 + 7);
+    }
+
+    multiply(other) {
+        const product = new Matrix(this.size);
+        for (let i = 0; i < this.size; i++) {
+            for (let j = 0; j < this.size; j++) {
+                let sum = BigInt(0);
+                for (let k = 0; k < this.size; k++) {
+                    sum = (sum + BigInt(this.a[i][k]) * BigInt(other.a[k][j])) % this.MOD;
+                }
+                product.a[i][j] = Number(sum);
+            }
+        }
+        return product;
+    }
+}
+
+class Solution {
+    /**
+     * @param {number} n
+     * @return {number}
+     */
+    knightDialer(n) {
+        if (n === 1) return 10;
+
+        const matpow = (mat, exp, size) => {
+            let res = new Matrix(size);
+            for (let i = 0; i < size; i++) {
+                res.a[i][i] = 1; // Identity matrix
+            }
+
+            while (exp > 0) {
+                if (exp & 1) {
+                    res = res.multiply(mat);
+                }
+                mat = mat.multiply(mat);
+                exp >>= 1;
+            }
+            return res;
+        };
+
+        const jumps = [
+            [4, 6], [6, 8], [7, 9], [4, 8], [0, 3, 9],
+            [], [0, 1, 7], [2, 6], [1, 3], [2, 4]
+        ];
+
+        const mat = new Matrix(10);
+        for (let i = 0; i < 10; i++) {
+            for (let j of jumps[i]) {
+                mat.a[i][j] = 1;
+            }
+        }
+
+        const res = matpow(mat, n - 1, 10);
+        const mod = 1e9 + 7
+        let ans = 0;
+        
+        for (let i = 0; i < 10; i++) {
+            for (let j = 0; j < 10; j++) {
+                ans = (ans + res.a[i][j]) % mod;
+            }
+        }
+        
+        return ans;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(\log n)$
+* Space complexity: $O(1)$
\ No newline at end of file
diff --git a/articles/largest-divisible-subset.md b/articles/largest-divisible-subset.md
new file mode 100644
index 000000000..c5d8fa381
--- /dev/null
+++ b/articles/largest-divisible-subset.md
@@ -0,0 +1,738 @@
+## 1. Dynamic Programming (Top-Down)
+
+::tabs-start
+
+```python
+class Solution:
+    def largestDivisibleSubset(self, nums: List[int]) -> List[int]:
+        nums.sort()
+        cache = {}  # (i, prevIndex) -> List
+
+        def dfs(i, prevIndex):
+            if i == len(nums):
+                return []
+            if (i, prevIndex) in cache:
+                return cache[(i, prevIndex)]
+
+            res = dfs(i + 1, prevIndex)  # Skip nums[i]
+            if prevIndex == -1 or nums[i] % nums[prevIndex] == 0:
+                tmp = [nums[i]] + dfs(i + 1, i)  # Include nums[i]
+                res = tmp if len(tmp) > len(res) else res
+
+            cache[(i, prevIndex)] = res
+            return res
+
+        return dfs(0, -1)
+```
+
+```java
+public class Solution {
+    private List<Integer>[][] cache;
+
+    public List<Integer> largestDivisibleSubset(int[] nums) {
+        Arrays.sort(nums);
+        int n = nums.length;
+        cache = new ArrayList[n][n + 1];
+        return dfs(0, -1, nums);
+    }
+
+    private List<Integer> dfs(int i, int prevIndex, int[] nums) {
+        if (i == nums.length) return new ArrayList<>();
+        if (cache[i][prevIndex + 1] != null) return cache[i][prevIndex + 1];
+
+        List<Integer> res = dfs(i + 1, prevIndex, nums);
+
+        if (prevIndex == -1 || nums[i] % nums[prevIndex] == 0) {
+            List<Integer> tmp = new ArrayList<>();
+            tmp.add(nums[i]);
+            tmp.addAll(dfs(i + 1, i, nums));
+            if (tmp.size() > res.size()) res = tmp;
+        }
+
+        cache[i][prevIndex + 1] = res;
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+private:
+    vector<vector<vector<int>>> cache;
+
+public:
+    vector<int> largestDivisibleSubset(vector<int>& nums) {
+        sort(nums.begin(), nums.end());
+        int n = nums.size();
+        cache = vector<vector<vector<int>>>(n, vector<vector<int>>(n + 1));
+        return dfs(0, -1, nums);
+    }
+
+    vector<int> dfs(int i, int prevIndex, vector<int>& nums) {
+        if (i == nums.size()) return {};
+        if (!cache[i][prevIndex + 1].empty()) return cache[i][prevIndex + 1];
+
+        vector<int> res = dfs(i + 1, prevIndex, nums);
+
+        if (prevIndex == -1 || nums[i] % nums[prevIndex] == 0) {
+            vector<int> tmp = {nums[i]};
+            vector<int> next = dfs(i + 1, i, nums);
+            tmp.insert(tmp.end(), next.begin(), next.end());
+            if (tmp.size() > res.size()) res = tmp;
+        }
+
+        return cache[i][prevIndex + 1] = res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} nums
+     * @return {number[]}
+     */
+    largestDivisibleSubset(nums) {
+        nums.sort((a, b) => a - b);
+        const cache = new Map();
+
+        const dfs = (i, prevIndex) => {
+            if (i === nums.length) return [];
+
+            let key = `${i},${prevIndex}`;
+            if (cache.has(key)) return cache.get(key);
+
+            let res = dfs(i + 1, prevIndex);
+            if (prevIndex === -1 || nums[i] % nums[prevIndex] === 0) {
+                let tmp = [nums[i], ...dfs(i + 1, i)];
+                if (tmp.length > res.length) res = tmp;
+            }
+
+            cache.set(key, res);
+            return res;
+        };
+
+        return dfs(0, -1);
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n ^ 2)$
+* Space complexity: $O(n ^ 2)$
+
+---
+
+## 2. Dynamic Programming (Top-Down) Space Optimized
+
+::tabs-start
+
+```python
+class Solution:
+    def largestDivisibleSubset(self, nums: List[int]) -> List[int]:
+        nums.sort()
+        cache = {}
+
+        def dfs(i):
+            if i in cache:
+                return cache[i]
+
+            res = [nums[i]]
+            for j in range(i + 1, len(nums)):
+                if nums[j] % nums[i] == 0:
+                    tmp = [nums[i]] + dfs(j)
+                    if len(tmp) > len(res):
+                        res = tmp
+
+            cache[i] = res
+            return res
+
+        res = []
+        for i in range(len(nums)):
+            tmp = dfs(i)
+            if len(tmp) > len(res):
+                res = tmp
+        return res
+```
+
+```java
+public class Solution {
+    private List<Integer>[] cache;
+
+    public List<Integer> largestDivisibleSubset(int[] nums) {
+        Arrays.sort(nums);
+        int n = nums.length;
+        cache = new ArrayList[n];
+
+        List<Integer> res = new ArrayList<>();
+        for (int i = 0; i < n; i++) {
+            List<Integer> tmp = dfs(i, nums);
+            if (tmp.size() > res.size()) {
+                res = tmp;
+            }
+        }
+        return res;
+    }
+
+    private List<Integer> dfs(int i, int[] nums) {
+        if (cache[i] != null) return cache[i];
+
+        List<Integer> res = new ArrayList<>();
+        res.add(nums[i]);
+        for (int j = i + 1; j < nums.length; j++) {
+            if (nums[j] % nums[i] == 0) {
+                List<Integer> tmp = new ArrayList<>();
+                tmp.add(nums[i]);
+                tmp.addAll(dfs(j, nums));
+
+                if (tmp.size() > res.size()) {
+                    res = tmp;
+                }
+            }
+        }
+        return cache[i] = res;
+    }
+}
+```
+
+```cpp
+class Solution {
+private:
+    vector<vector<int>> cache;
+
+public:
+    vector<int> largestDivisibleSubset(vector<int>& nums) {
+        sort(nums.begin(), nums.end());
+        int n = nums.size();
+        cache.resize(n, vector<int>());
+
+        vector<int> res;
+        for (int i = 0; i < n; i++) {
+            vector<int> tmp = dfs(i, nums);
+            if (tmp.size() > res.size()) {
+                res = tmp;
+            }
+        }
+        return res;
+    }
+
+    vector<int> dfs(int i, vector<int>& nums) {
+        if (!cache[i].empty()) return cache[i];
+
+        vector<int> res = {nums[i]};
+        for (int j = i + 1; j < nums.size(); j++) {
+            if (nums[j] % nums[i] == 0) {
+                vector<int> tmp = {nums[i]};
+                vector<int> next = dfs(j, nums);
+                tmp.insert(tmp.end(), next.begin(), next.end());
+
+                if (tmp.size() > res.size()) {
+                    res = tmp;
+                }
+            }
+        }
+        return cache[i] = res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} nums
+     * @return {number[]}
+     */
+    largestDivisibleSubset(nums) {
+        nums.sort((a, b) => a - b);
+        const n = nums.length;
+        const cache = new Array(n).fill(null);
+
+        const dfs = (i) => {
+            if (cache[i] !== null) return cache[i];
+
+            let res = [nums[i]];
+            for (let j = i + 1; j < n; j++) {
+                if (nums[j] % nums[i] === 0) {
+                    let tmp = [nums[i], ...dfs(j)];
+                    if (tmp.length > res.length) {
+                        res = tmp;
+                    }
+                }
+            }
+            return (cache[i] = res);
+        };
+
+        let res = [];
+        for (let i = 0; i < n; i++) {
+            let tmp = dfs(i);
+            if (tmp.length > res.length) {
+                res = tmp;
+            }
+        }
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n ^ 2)$
+* Space complexity: $O(n)$
+
+---
+
+## 3. Dynamic Programming (Bottom-Up)
+
+::tabs-start
+
+```python
+class Solution:
+    def largestDivisibleSubset(self, nums: List[int]) -> List[int]:
+        nums.sort()
+        dp = [[num] for num in nums]  # dp[i] = longest start at i
+        res = []
+        for i in range(len(nums) - 1, -1, -1):
+            for j in range(i + 1, len(nums)):
+                if nums[j] % nums[i] == 0:
+                    tmp = [nums[i]] + dp[j]
+                    dp[i] = tmp if len(tmp) > len(dp[i]) else dp[i]
+            res = dp[i] if len(dp[i]) > len(res) else res
+        return res
+```
+
+```java
+public class Solution {
+    public List<Integer> largestDivisibleSubset(int[] nums) {
+        Arrays.sort(nums);
+        int n = nums.length;
+        List<Integer>[] dp = new ArrayList[n];
+        List<Integer> res = new ArrayList<>();
+
+        for (int i = n - 1; i >= 0; i--) {
+            dp[i] = new ArrayList<>();
+            dp[i].add(nums[i]);
+
+            for (int j = i + 1; j < n; j++) {
+                if (nums[j] % nums[i] == 0) {
+                    List<Integer> tmp = new ArrayList<>();
+                    tmp.add(nums[i]);
+                    tmp.addAll(dp[j]);
+
+                    if (tmp.size() > dp[i].size()) {
+                        dp[i] = tmp;
+                    }
+                }
+            }
+            if (dp[i].size() > res.size()) {
+                res = dp[i];
+            }
+        }
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    vector<int> largestDivisibleSubset(vector<int>& nums) {
+        sort(nums.begin(), nums.end());
+        int n = nums.size();
+        vector<vector<int>> dp(n);
+        vector<int> res;
+
+        for (int i = n - 1; i >= 0; i--) {
+            dp[i].push_back(nums[i]);
+
+            for (int j = i + 1; j < n; j++) {
+                if (nums[j] % nums[i] == 0) {
+                    vector<int> tmp = dp[j];
+                    tmp.insert(tmp.begin(), nums[i]);
+
+                    if (tmp.size() > dp[i].size()) {
+                        dp[i] = tmp;
+                    }
+                }
+            }
+            if (dp[i].size() > res.size()) {
+                res = dp[i];
+            }
+        }
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} nums
+     * @return {number[]}
+     */
+    largestDivisibleSubset(nums) {
+        nums.sort((a, b) => a - b);
+        const n = nums.length;
+        const dp = new Array(n).fill(0).map(() => []);
+        let res = [];
+
+        for (let i = n - 1; i >= 0; i--) {
+            dp[i] = [nums[i]];
+
+            for (let j = i + 1; j < n; j++) {
+                if (nums[j] % nums[i] === 0) {
+                    let tmp = [nums[i], ...dp[j]];
+
+                    if (tmp.length > dp[i].length) {
+                        dp[i] = tmp;
+                    }
+                }
+            }
+            if (dp[i].length > res.length) {
+                res = dp[i];
+            }
+        }
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n ^ 2)$
+* Space complexity: $O(n)$
+
+---
+
+## 4. Dynamic Programming (Top-Down) + Tracing
+
+::tabs-start
+
+```python
+class Solution:
+    def largestDivisibleSubset(self, nums: List[int]) -> List[int]:
+        nums.sort()
+        n = len(nums)
+        dp = [[-1, -1] for _ in range(n)]  # dp[i] = [maxLen, prevIdx]
+
+        def dfs(i):
+            if dp[i][0] != -1:
+                return dp[i][0]
+
+            dp[i][0] = 1
+            for j in range(i + 1, n):
+                if nums[j] % nums[i] == 0:
+                    length = dfs(j) + 1
+                    if length > dp[i][0]:
+                        dp[i][0] = length
+                        dp[i][1] = j
+
+            return dp[i][0]
+
+        max_len, start_index = 1, 0
+        for i in range(n):
+            if dfs(i) > max_len:
+                max_len = dfs(i)
+                start_index = i
+
+        subset = []
+        while start_index != -1:
+            subset.append(nums[start_index])
+            start_index = dp[start_index][1]
+
+        return subset
+```
+
+```java
+public class Solution {
+    private int[][] dp;
+
+    public List<Integer> largestDivisibleSubset(int[] nums) {
+        Arrays.sort(nums);
+        int n = nums.length;
+        dp = new int[n][2];
+        for (int i = 0; i < n; i++) {
+            dp[i][0] = -1;
+            dp[i][1] = -1;
+        }
+
+        int maxLen = 1, startIndex = 0;
+        for (int i = 0; i < n; i++) {
+            if (dfs(i, nums) > maxLen) {
+                maxLen = dp[i][0];
+                startIndex = i;
+            }
+        }
+
+        List<Integer> subset = new ArrayList<>();
+        while (startIndex != -1) {
+            subset.add(nums[startIndex]);
+            startIndex = dp[startIndex][1];
+        }
+        return subset;
+    }
+
+    private int dfs(int i, int[] nums) {
+        if (dp[i][0] != -1) return dp[i][0];
+
+        dp[i][0] = 1;
+        for (int j = i + 1; j < nums.length; j++) {
+            if (nums[j] % nums[i] == 0) {
+                int length = dfs(j, nums) + 1;
+                if (length > dp[i][0]) {
+                    dp[i][0] = length;
+                    dp[i][1] = j;
+                }
+            }
+        }
+        return dp[i][0];
+    }
+}
+```
+
+```cpp
+class Solution {
+    vector<vector<int>> dp;
+
+public:
+    vector<int> largestDivisibleSubset(vector<int>& nums) {
+        sort(nums.begin(), nums.end());
+        int n = nums.size();
+        dp.assign(n, vector<int>(2, -1));
+
+        int maxLen = 1, startIndex = 0;
+        for (int i = 0; i < n; i++) {
+            if (dfs(i, nums) > maxLen) {
+                maxLen = dp[i][0];
+                startIndex = i;
+            }
+        }
+
+        vector<int> subset;
+        while (startIndex != -1) {
+            subset.push_back(nums[startIndex]);
+            startIndex = dp[startIndex][1];
+        }
+        return subset;
+    }
+
+private:
+    int dfs(int i, vector<int>& nums) {
+        if (dp[i][0] != -1) return dp[i][0];
+
+        dp[i][0] = 1;
+        for (int j = i + 1; j < nums.size(); j++) {
+            if (nums[j] % nums[i] == 0) {
+                int length = dfs(j, nums) + 1;
+                if (length > dp[i][0]) {
+                    dp[i][0] = length;
+                    dp[i][1] = j;
+                }
+            }
+        }
+        return dp[i][0];
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} nums
+     * @return {number[]}
+     */
+    largestDivisibleSubset(nums) {
+        nums.sort((a, b) => a - b);
+        let n = nums.length;
+        let dp = Array.from({ length: n }, () => [-1, -1]); // dp[i] = [maxLen, prevIdx]
+
+        const dfs = (i) => {
+            if (dp[i][0] !== -1) return dp[i][0];
+
+            dp[i][0] = 1;
+            for (let j = i + 1; j < n; j++) {
+                if (nums[j] % nums[i] === 0) {
+                    let length = dfs(j) + 1;
+                    if (length > dp[i][0]) {
+                        dp[i][0] = length;
+                        dp[i][1] = j;
+                    }
+                }
+            }
+            return dp[i][0];
+        };
+
+        let maxLen = 1, startIndex = 0;
+        for (let i = 0; i < n; i++) {
+            if (dfs(i) > maxLen) {
+                maxLen = dfs(i);
+                startIndex = i;
+            }
+        }
+
+        let subset = [];
+        while (startIndex !== -1) {
+            subset.push(nums[startIndex]);
+            startIndex = dp[startIndex][1];
+        }
+        return subset;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n ^ 2)$
+* Space complexity: $O(n)$
+
+---
+
+## 5. Dynamic Programming (Bottom-Up) + Tracing
+
+::tabs-start
+
+```python
+class Solution:
+    def largestDivisibleSubset(self, nums: List[int]) -> List[int]:
+        nums.sort()
+        n = len(nums)
+        dp = [[1, -1] for _ in range(n)]  # dp[i] = [maxLen, prevIdx]
+
+        max_len, start_index = 1, 0
+
+        for i in range(n):
+            for j in range(i):
+                if nums[i] % nums[j] == 0 and dp[j][0] + 1 > dp[i][0]:
+                    dp[i][0] = dp[j][0] + 1
+                    dp[i][1] = j
+
+            if dp[i][0] > max_len:
+                max_len = dp[i][0]
+                start_index = i
+
+        subset = []
+        while start_index != -1:
+            subset.append(nums[start_index])
+            start_index = dp[start_index][1]
+        return subset
+```
+
+```java
+public class Solution {
+    public List<Integer> largestDivisibleSubset(int[] nums) {
+        Arrays.sort(nums);
+        int n = nums.length;
+        int[][] dp = new int[n][2]; // dp[i] = {maxLen, prevIdx}
+
+        int maxLen = 1, startIndex = 0;
+        for (int i = 0; i < n; i++) {
+            dp[i][0] = 1;
+            dp[i][1] = -1;
+            for (int j = 0; j < i; j++) {
+                if (nums[i] % nums[j] == 0 && dp[j][0] + 1 > dp[i][0]) {
+                    dp[i][0] = dp[j][0] + 1;
+                    dp[i][1] = j;
+                }
+            }
+
+            if (dp[i][0] > maxLen) {
+                maxLen = dp[i][0];
+                startIndex = i;
+            }
+        }
+
+        List<Integer> subset = new ArrayList<>();
+        while (startIndex != -1) {
+            subset.add(nums[startIndex]);
+            startIndex = dp[startIndex][1];
+        }
+        return subset;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    vector<int> largestDivisibleSubset(vector<int>& nums) {
+        sort(nums.begin(), nums.end());
+        int n = nums.size();
+        vector<vector<int>> dp(n, vector<int>(2, -1)); // dp[i] = {maxLen, prevIdx}
+
+        int maxLen = 1, startIndex = 0;
+        for (int i = 0; i < n; i++) {
+            dp[i][0] = 1;
+            dp[i][1] = -1;
+            for (int j = 0; j < i; j++) {
+                if (nums[i] % nums[j] == 0 && dp[j][0] + 1 > dp[i][0]) {
+                    dp[i][0] = dp[j][0] + 1;
+                    dp[i][1] = j;
+                }
+            }
+
+            if (dp[i][0] > maxLen) {
+                maxLen = dp[i][0];
+                startIndex = i;
+            }
+        }
+
+        vector<int> subset;
+        while (startIndex != -1) {
+            subset.push_back(nums[startIndex]);
+            startIndex = dp[startIndex][1];
+        }
+        return subset;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} nums
+     * @return {number[]}
+     */
+    largestDivisibleSubset(nums) {
+        nums.sort((a, b) => a - b);
+        let n = nums.length;
+        let dp = Array.from({ length: n }, () => [1, -1]); // dp[i] = [maxLen, prevIdx]
+
+        let maxLen = 1, startIndex = 0;
+        for (let i = 0; i < n; i++) {
+            for (let j = 0; j < i; j++) {
+                if (nums[i] % nums[j] === 0 && dp[j][0] + 1 > dp[i][0]) {
+                    dp[i][0] = dp[j][0] + 1;
+                    dp[i][1] = j;
+                }
+            }
+
+            if (dp[i][0] > maxLen) {
+                maxLen = dp[i][0];
+                startIndex = i;
+            }
+        }
+
+        let subset = [];
+        while (startIndex !== -1) {
+            subset.push(nums[startIndex]);
+            startIndex = dp[startIndex][1];
+        }
+        return subset;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n ^ 2)$
+* Space complexity: $O(n)$
\ No newline at end of file
diff --git a/articles/minimum-number-of-arrows-to-burst-balloons.md b/articles/minimum-number-of-arrows-to-burst-balloons.md
new file mode 100644
index 000000000..195e1e3e0
--- /dev/null
+++ b/articles/minimum-number-of-arrows-to-burst-balloons.md
@@ -0,0 +1,183 @@
+## 1. Greedy (Sort By Start Value)
+
+::tabs-start
+
+```python
+class Solution:
+    def findMinArrowShots(self, points: List[List[int]]) -> int:
+        points.sort()
+        res, prevEnd = len(points), points[0][1]
+
+        for i in range(1, len(points)):
+            curr = points[i]
+            if curr[0] <= prevEnd:
+                res -= 1
+                prevEnd = min(curr[1], prevEnd)
+            else:
+                prevEnd = curr[1]
+
+        return res
+```
+
+```java
+public class Solution {
+    public int findMinArrowShots(int[][] points) {
+        Arrays.sort(points, (a, b) -> Integer.compare(a[0], b[0]));
+        int res = points.length, prevEnd = points[0][1];
+
+        for (int i = 1; i < points.length; i++) {
+            int[] curr = points[i];
+            if (curr[0] <= prevEnd) {
+                res--;
+                prevEnd = Math.min(curr[1], prevEnd);
+            } else {
+                prevEnd = curr[1];
+            }
+        }
+
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int findMinArrowShots(vector<vector<int>>& points) {
+        sort(points.begin(), points.end());
+        int res = points.size(), prevEnd = points[0][1];
+
+        for (int i = 1; i < points.size(); i++) {
+            vector<int>& curr = points[i];
+            if (curr[0] <= prevEnd) {
+                res--;
+                prevEnd = min(curr[1], prevEnd);
+            } else {
+                prevEnd = curr[1];
+            }
+        }
+
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} points
+     * @return {number}
+     */
+    findMinArrowShots(points) {
+        points.sort((a, b) => a[0] - b[0]);
+        let res = points.length, prevEnd = points[0][1];
+
+        for (let i = 1; i < points.length; i++) {
+            let curr = points[i];
+            if (curr[0] <= prevEnd) {
+                res--;
+                prevEnd = Math.min(curr[1], prevEnd);
+            } else {
+                prevEnd = curr[1];
+            }
+        }
+
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n \log n)$
+* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm.
+
+---
+
+## 2. Greedy (Sort By End Value)
+
+::tabs-start
+
+```python
+class Solution:
+    def findMinArrowShots(self, points: List[List[int]]) -> int:
+        points.sort(key=lambda x: x[1])
+        res, prevEnd = 1, points[0][1]
+
+        for i in range(1, len(points)):
+            if points[i][0] > prevEnd:
+                prevEnd = points[i][1]
+                res += 1
+
+        return res
+```
+
+```java
+public class Solution {
+    public int findMinArrowShots(int[][] points) {
+        Arrays.sort(points, (a, b) -> Integer.compare(a[1], b[1]));
+        int res = 1, prevEnd = points[0][1];
+
+        for (int i = 1; i < points.length; i++) {
+            if (points[i][0] > prevEnd) {
+                prevEnd = points[i][1];
+                res++;
+            }
+        }
+
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int findMinArrowShots(vector<vector<int>>& points) {
+        sort(points.begin(), points.end(), [](const auto& a, const auto& b) {
+            return a[1] < b[1];
+        });
+        int res = 1, prevEnd = points[0][1];
+
+        for (int i = 1; i < points.size(); i++) {
+            if (points[i][0] > prevEnd) {
+                prevEnd = points[i][1];
+                res++;
+            }
+        }
+
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} points
+     * @return {number}
+     */
+    findMinArrowShots(points) {
+        points.sort((a, b) => a[1] - b[1]);
+        let res = 1, prevEnd = points[0][1];
+
+        for (let i = 1; i < points.length; i++) {
+            if (points[i][0] > prevEnd) {
+                prevEnd = points[i][1];
+                res++;
+            }
+        }
+
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n \log n)$
+* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm.
\ No newline at end of file
diff --git a/articles/partition-array-for-maximum-sum.md b/articles/partition-array-for-maximum-sum.md
new file mode 100644
index 000000000..a2fb52393
--- /dev/null
+++ b/articles/partition-array-for-maximum-sum.md
@@ -0,0 +1,446 @@
+## 1. Recursion
+
+::tabs-start
+
+```python
+class Solution:
+    def maxSumAfterPartitioning(self, arr: List[int], k: int) -> int:
+        def dfs(i):
+            if i >= len(arr):
+                return 0
+
+            cur_max = 0
+            res = 0
+            for j in range(i, min(len(arr), i + k)):
+                cur_max = max(cur_max, arr[j])
+                window_size = j - i + 1
+                res = max(res, dfs(j + 1) + cur_max * window_size)
+
+            return res
+
+        return dfs(0)
+```
+
+```java
+public class Solution {
+    public int maxSumAfterPartitioning(int[] arr, int k) {
+        return dfs(0, arr, k);
+    }
+
+    private int dfs(int i, int[] arr, int k) {
+        if (i >= arr.length) {
+            return 0;
+        }
+
+        int cur_max = 0;
+        int res = 0;
+        for (int j = i; j < Math.min(arr.length, i + k); j++) {
+            cur_max = Math.max(cur_max, arr[j]);
+            int window_size = j - i + 1;
+            res = Math.max(res, dfs(j + 1, arr, k) + cur_max * window_size);
+        }
+
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int maxSumAfterPartitioning(vector<int>& arr, int k) {
+        return dfs(0, arr, k);
+    }
+
+private:
+    int dfs(int i, vector<int>& arr, int k) {
+        if (i >= arr.size()) {
+            return 0;
+        }
+
+        int cur_max = 0, res = 0;
+        for (int j = i; j < min((int)arr.size(), i + k); j++) {
+            cur_max = max(cur_max, arr[j]);
+            int window_size = j - i + 1;
+            res = max(res, dfs(j + 1, arr, k) + cur_max * window_size);
+        }
+
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} arr
+     * @param {number} k
+     * @return {number}
+     */
+    maxSumAfterPartitioning(arr, k) {
+        const dfs = (i) => {
+            if (i >= arr.length) {
+                return 0;
+            }
+
+            let cur_max = 0, res = 0;
+            for (let j = i; j < Math.min(arr.length, i + k); j++) {
+                cur_max = Math.max(cur_max, arr[j]);
+                let window_size = j - i + 1;
+                res = Math.max(res, dfs(j + 1) + cur_max * window_size);
+            }
+
+            return res;
+        };
+
+        return dfs(0);
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(k ^ n)$
+* Space complexity: $O(n)$ for recursion stack.
+
+> Where $k$ is the maximum length of the subarray and $n$ is the size of the array $arr$.
+
+---
+
+## 2. Dynamic Programming (Top-Down)
+
+::tabs-start
+
+```python
+class Solution:
+    def maxSumAfterPartitioning(self, arr: List[int], k: int) -> int:
+        cache = { len(arr) : 0 }
+
+        def dfs(i):
+            if i in cache:
+                return cache[i]
+
+            cur_max = 0
+            res = 0
+            for j in range(i, min(len(arr), i + k)):
+                cur_max = max(cur_max, arr[j])
+                window_size = j - i + 1
+                res = max(res, dfs(j + 1) + cur_max * window_size)
+
+            cache[i] = res
+            return res
+
+        return dfs(0)
+```
+
+```java
+public class Solution {
+    public int maxSumAfterPartitioning(int[] arr, int k) {
+        int[] cache = new int[arr.length + 1];
+        Arrays.fill(cache, -1);
+        cache[arr.length] = 0;
+        return dfs(0, arr, k, cache);
+    }
+
+    private int dfs(int i, int[] arr, int k, int[] cache) {
+        if (cache[i] != -1) {
+            return cache[i];
+        }
+
+        int cur_max = 0, res = 0;
+        for (int j = i; j < Math.min(arr.length, i + k); j++) {
+            cur_max = Math.max(cur_max, arr[j]);
+            int window_size = j - i + 1;
+            res = Math.max(res, dfs(j + 1, arr, k, cache) + cur_max * window_size);
+        }
+
+        cache[i] = res;
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int maxSumAfterPartitioning(vector<int>& arr, int k) {
+        vector<int> cache(arr.size() + 1, -1);
+        cache[arr.size()] = 0;
+        return dfs(0, arr, k, cache);
+    }
+
+private:
+    int dfs(int i, vector<int>& arr, int k, vector<int>& cache) {
+        if (cache[i] != -1) {
+            return cache[i];
+        }
+
+        int cur_max = 0, res = 0;
+        for (int j = i; j < min((int)arr.size(), i + k); j++) {
+            cur_max = max(cur_max, arr[j]);
+            int window_size = j - i + 1;
+            res = max(res, dfs(j + 1, arr, k, cache) + cur_max * window_size);
+        }
+
+        return cache[i] = res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} arr
+     * @param {number} k
+     * @return {number}
+     */
+    maxSumAfterPartitioning(arr, k) {
+        const cache = new Array(arr.length + 1).fill(-1);
+        cache[arr.length] = 0;
+
+        const dfs = (i) => {
+            if (cache[i] !== -1) {
+                return cache[i];
+            }
+
+            let cur_max = 0, res = 0;
+            for (let j = i; j < Math.min(arr.length, i + k); j++) {
+                cur_max = Math.max(cur_max, arr[j]);
+                let window_size = j - i + 1;
+                res = Math.max(res, dfs(j + 1) + cur_max * window_size);
+            }
+
+            return (cache[i] = res);
+        };
+
+        return dfs(0);
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n * k)$
+* Space complexity: $O(n)$
+
+> Where $k$ is the maximum length of the subarray and $n$ is the size of the array $arr$.
+
+---
+
+## 3. Dynamic Programming (Bottom-Up)
+
+::tabs-start
+
+```python
+class Solution:
+    def maxSumAfterPartitioning(self, arr: List[int], k: int) -> int:
+        n = len(arr)
+        dp = [0] * (n + 1)
+
+        for i in range(n - 1, -1, -1):
+            cur_max = 0
+            for j in range(i, min(n, i + k)):
+                cur_max = max(cur_max, arr[j])
+                window_size = j - i + 1
+                dp[i] = max(dp[i], dp[j + 1] + cur_max * window_size)
+
+        return dp[0]
+```
+
+```java
+public class Solution {
+    public int maxSumAfterPartitioning(int[] arr, int k) {
+        int n = arr.length;
+        int[] dp = new int[n + 1];
+
+        for (int i = n - 1; i >= 0; i--) {
+            int cur_max = 0;
+            for (int j = i; j < Math.min(n, i + k); j++) {
+                cur_max = Math.max(cur_max, arr[j]);
+                int window_size = j - i + 1;
+                dp[i] = Math.max(dp[i], dp[j + 1] + cur_max * window_size);
+            }
+        }
+
+        return dp[0];
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int maxSumAfterPartitioning(vector<int>& arr, int k) {
+        int n = arr.size();
+        vector<int> dp(n + 1, 0);
+
+        for (int i = n - 1; i >= 0; i--) {
+            int cur_max = 0;
+            for (int j = i; j < min(n, i + k); j++) {
+                cur_max = max(cur_max, arr[j]);
+                int window_size = j - i + 1;
+                dp[i] = max(dp[i], dp[j + 1] + cur_max * window_size);
+            }
+        }
+
+        return dp[0];
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} arr
+     * @param {number} k
+     * @return {number}
+     */
+    maxSumAfterPartitioning(arr, k) {
+        let n = arr.length;
+        let dp = new Array(n + 1).fill(0);
+
+        for (let i = n - 1; i >= 0; i--) {
+            let cur_max = 0;
+            for (let j = i; j < Math.min(n, i + k); j++) {
+                cur_max = Math.max(cur_max, arr[j]);
+                let window_size = j - i + 1;
+                dp[i] = Math.max(dp[i], dp[j + 1] + cur_max * window_size);
+            }
+        }
+
+        return dp[0];
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n * k)$
+* Space complexity: $O(n)$
+
+> Where $k$ is the maximum length of the subarray and $n$ is the size of the array $arr$.
+
+---
+
+## 4. Dynamic Programming (Space Optimized)
+
+::tabs-start
+
+```python
+class Solution:
+    def maxSumAfterPartitioning(self, arr: List[int], k: int) -> int:
+        dp = [0] * k
+        dp[0] = arr[0]
+
+        for i in range(1, len(arr)):
+            cur_max = 0
+            max_at_i = 0
+            for j in range(i, i - k, -1):
+                if j < 0:
+                    break
+                cur_max = max(cur_max, arr[j])
+                window_size = i - j + 1
+                cur_sum = cur_max * window_size
+                sub_sum = dp[(j - 1) % k] if j > 0 else 0
+                max_at_i = max(max_at_i, cur_sum + sub_sum)
+
+            dp[i % k] = max_at_i
+
+        return dp[(len(arr) - 1) % k]
+```
+
+```java
+public class Solution {
+    public int maxSumAfterPartitioning(int[] arr, int k) {
+        int n = arr.length;
+        int[] dp = new int[k];
+        dp[0] = arr[0];
+
+        for (int i = 1; i < n; i++) {
+            int cur_max = 0, max_at_i = 0;
+            for (int j = i; j > i - k; j--) {
+                if (j < 0) break;
+                cur_max = Math.max(cur_max, arr[j]);
+                int window_size = i - j + 1;
+                int cur_sum = cur_max * window_size;
+                int sub_sum = (j > 0) ? dp[(j - 1) % k] : 0;
+                max_at_i = Math.max(max_at_i, cur_sum + sub_sum);
+            }
+            dp[i % k] = max_at_i;
+        }
+
+        return dp[(n - 1) % k];
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int maxSumAfterPartitioning(vector<int>& arr, int k) {
+        int n = arr.size();
+        vector<int> dp(k);
+        dp[0] = arr[0];
+
+        for (int i = 1; i < n; i++) {
+            int cur_max = 0, max_at_i = 0;
+            for (int j = i; j > i - k; j--) {
+                if (j < 0) break;
+                cur_max = max(cur_max, arr[j]);
+                int window_size = i - j + 1;
+                int cur_sum = cur_max * window_size;
+                int sub_sum = (j > 0) ? dp[(j - 1) % k] : 0;
+                max_at_i = max(max_at_i, cur_sum + sub_sum);
+            }
+            dp[i % k] = max_at_i;
+        }
+
+        return dp[(n - 1) % k];
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} arr
+     * @param {number} k
+     * @return {number}
+     */
+    maxSumAfterPartitioning(arr, k) {
+        const n = arr.length;
+        const dp = new Array(k).fill(0);
+        dp[0] = arr[0];
+
+        for (let i = 1; i < n; i++) {
+            let cur_max = 0, max_at_i = 0;
+            for (let j = i; j > i - k; j--) {
+                if (j < 0) break;
+                cur_max = Math.max(cur_max, arr[j]);
+                let window_size = i - j + 1;
+                let cur_sum = cur_max * window_size;
+                let sub_sum = (j > 0) ? dp[(j - 1) % k] : 0;
+                max_at_i = Math.max(max_at_i, cur_sum + sub_sum);
+            }
+            dp[i % k] = max_at_i;
+        }
+
+        return dp[(n - 1) % k];
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n * k)$
+* Space complexity: $O(k)$
+
+> Where $k$ is the maximum length of the subarray and $n$ is the size of the array $arr$.
\ No newline at end of file
diff --git a/articles/remove-max-number-of-edges-to-keep-graph-fully-traversable.md b/articles/remove-max-number-of-edges-to-keep-graph-fully-traversable.md
new file mode 100644
index 000000000..04c3da1ac
--- /dev/null
+++ b/articles/remove-max-number-of-edges-to-keep-graph-fully-traversable.md
@@ -0,0 +1,274 @@
+## 1. Disjoint Set Union
+
+::tabs-start
+
+```python
+class DSU:
+    def __init__(self, n):
+        self.n = 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 = self.find(u)
+        pv = self.find(v)
+        if pu == pv:
+            return 0
+        if self.Size[pu] < self.Size[pv]:
+            pu, pv = pv, pu
+        self.Size[pu] += self.Size[pv]
+        self.Parent[pv] = pu
+        self.n -= 1
+        return 1
+
+    def isConnected(self):
+        return self.n == 1
+
+class Solution:
+    def maxNumEdgesToRemove(self, n: int, edges: List[List[int]]) -> int:
+        alice, bob = DSU(n), DSU(n)
+        cnt = 0
+
+        for type, src, dst in edges:
+            if type == 3:
+                cnt += (alice.union(src, dst) | bob.union(src, dst))
+
+        for type, src, dst in edges:
+            if type == 1:
+                cnt += alice.union(src, dst)
+            elif type == 2:
+                cnt += bob.union(src, dst)
+
+        if alice.isConnected() and bob.isConnected():
+            return len(edges) - cnt
+        return -1
+```
+
+```java
+class DSU {
+    private int[] parent, size;
+    private int n;
+
+    public DSU(int n) {
+        this.n = 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 int union(int u, int v) {
+        int pu = find(u), pv = find(v);
+        if (pu == pv) {
+            return 0;
+        }
+        if (size[pu] < size[pv]) {
+            int temp = pu;
+            pu = pv;
+            pv = temp;
+        }
+        size[pu] += size[pv];
+        parent[pv] = pu;
+        n--;
+        return 1;
+    }
+
+    public boolean isConnected() {
+        return n == 1;
+    }
+}
+
+public class Solution {
+    public int maxNumEdgesToRemove(int n, int[][] edges) {
+        DSU alice = new DSU(n), bob = new DSU(n);
+        int cnt = 0;
+
+        for (int[] edge : edges) {
+            if (edge[0] == 3) {
+                cnt += (alice.union(edge[1], edge[2]) | bob.union(edge[1], edge[2]));
+            }
+        }
+
+        for (int[] edge : edges) {
+            if (edge[0] == 1) {
+                cnt += alice.union(edge[1], edge[2]);
+            } else if (edge[0] == 2) {
+                cnt += bob.union(edge[1], edge[2]);
+            }
+        }
+
+        if (alice.isConnected() && bob.isConnected()) {
+            return edges.length - cnt;
+        }
+        return -1;
+    }
+}
+```
+
+```cpp
+class DSU {
+private:
+    vector<int> parent, size;
+    int n;
+
+public:
+    DSU(int n) : n(n), parent(n + 1), size(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];
+    }
+
+    int unionSets(int u, int v) {
+        int pu = find(u), pv = find(v);
+        if (pu == pv) {
+            return 0;
+        }
+        if (size[pu] < size[pv]) {
+            swap(pu, pv);
+        }
+        size[pu] += size[pv];
+        parent[pv] = pu;
+        n--;
+        return 1;
+    }
+
+    bool isConnected() {
+        return n == 1;
+    }
+};
+
+class Solution {
+public:
+    int maxNumEdgesToRemove(int n, vector<vector<int>>& edges) {
+        DSU alice(n), bob(n);
+        int cnt = 0;
+
+        for (auto& edge : edges) {
+            if (edge[0] == 3) {
+                cnt += (alice.unionSets(edge[1], edge[2]) | bob.unionSets(edge[1], edge[2]));
+            }
+        }
+
+        for (auto& edge : edges) {
+            if (edge[0] == 1) {
+                cnt += alice.unionSets(edge[1], edge[2]);
+            } else if (edge[0] == 2) {
+                cnt += bob.unionSets(edge[1], edge[2]);
+            }
+        }
+
+        if (alice.isConnected() && bob.isConnected()) {
+            return edges.size() - cnt;
+        }
+        return -1;
+    }
+};
+```
+
+```javascript
+class DSU {
+    /**
+     * @param {number} n
+     */
+    constructor(n) {
+        this.n = n;
+        this.parent = Array(n + 1).fill(0).map((_, i) => i);
+        this.size = 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} v
+     * @return {number}
+     */
+    union(u, v) {
+        let pu = this.find(u), pv = this.find(v);
+        if (pu === pv) {
+            return 0;
+        }
+        if (this.size[pu] < this.size[pv]) {
+            [pu, pv] = [pv, pu];
+        }
+        this.size[pu] += this.size[pv];
+        this.parent[pv] = pu;
+        this.n--;
+        return 1;
+    }
+
+    /**
+     * @return {boolean}
+     */
+    isConnected() {
+        return this.n === 1;
+    }
+}
+
+class Solution {
+    /**
+     * @param {number} n
+     * @param {number[][]} edges
+     * @return {number}
+     */
+    maxNumEdgesToRemove(n, edges) {
+        let alice = new DSU(n), bob = new DSU(n);
+        let cnt = 0;
+
+        for (let [type, src, dst] of edges) {
+            if (type === 3) {
+                cnt += (alice.union(src, dst) | bob.union(src, dst));
+            }
+        }
+
+        for (let [type, src, dst] of edges) {
+            if (type === 1) {
+                cnt += alice.union(src, dst);
+            } else if (type === 2) {
+                cnt += bob.union(src, dst);
+            }
+        }
+
+        return alice.isConnected() && bob.isConnected() ? edges.length - cnt : -1;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(E * α(V))$
+* Space complexity: $O(V)$
+
+> Where $V$ is the number of verticies and $E$ is the number of edges.
\ No newline at end of file

From 22696a38133c27b119c18779f71d5d82fff3e6ab Mon Sep 17 00:00:00 2001
From: Sri Hari <kataresrihari@gmail.com>
Date: Mon, 10 Feb 2025 18:05:30 +0530
Subject: [PATCH 09/13] Batch-5/Neetcode-ALL/Added-articles

---
 articles/integer-to-roman.md                  | 195 +++++++
 .../largest-submatrix-with-rearrangements.md  | 522 ++++++++++++++++++
 ...ne-bit-operations-to-make-integers-zero.md | 313 +++++++++++
 articles/remove-covered-intervals.md          | 275 +++++++++
 ...between-two-points-containing-no-points.md | 212 +++++++
 5 files changed, 1517 insertions(+)
 create mode 100644 articles/integer-to-roman.md
 create mode 100644 articles/largest-submatrix-with-rearrangements.md
 create mode 100644 articles/minimum-one-bit-operations-to-make-integers-zero.md
 create mode 100644 articles/remove-covered-intervals.md
 create mode 100644 articles/widest-vertical-area-between-two-points-containing-no-points.md

diff --git a/articles/integer-to-roman.md b/articles/integer-to-roman.md
new file mode 100644
index 000000000..6bb15bb30
--- /dev/null
+++ b/articles/integer-to-roman.md
@@ -0,0 +1,195 @@
+## 1. Math - I
+
+::tabs-start
+
+```python
+class Solution:
+    def intToRoman(self, num: int) -> str:
+        symList = [
+            ["I", 1], ["IV", 4], ["V", 5], ["IX", 9],
+            ["X", 10], ["XL", 40], ["L", 50], ["XC", 90],
+            ["C", 100], ["CD", 400], ["D", 500], ["CM", 900],
+            ["M", 1000]
+        ]
+
+        res = ""
+        for sym, val in reversed(symList):
+            count = num // val
+            if count:
+                res += sym * count
+                num %= val
+
+        return res
+```
+
+```java
+public class Solution {
+    public String intToRoman(int num) {
+        String[][] symList = {
+            {"I", "1"}, {"IV", "4"}, {"V", "5"}, {"IX", "9"},
+            {"X", "10"}, {"XL", "40"}, {"L", "50"}, {"XC", "90"},
+            {"C", "100"}, {"CD", "400"}, {"D", "500"}, {"CM", "900"},
+            {"M", "1000"}
+        };
+
+        StringBuilder res = new StringBuilder();
+        for (int i = symList.length - 1; i >= 0; i--) {
+            String sym = symList[i][0];
+            int val = Integer.parseInt(symList[i][1]);
+            int count = num / val;
+            if (count > 0) {
+                res.append(sym.repeat(count));
+                num %= val;
+            }
+        }
+
+        return res.toString();
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    string intToRoman(int num) {
+        vector<pair<string, int>> symList = {
+            {"I", 1}, {"IV", 4}, {"V", 5}, {"IX", 9},
+            {"X", 10}, {"XL", 40}, {"L", 50}, {"XC", 90},
+            {"C", 100}, {"CD", 400}, {"D", 500}, {"CM", 900},
+            {"M", 1000}
+        };
+
+        string res = "";
+        for (int i = symList.size() - 1; i >= 0; i--) {
+            string sym = symList[i].first;
+            int val = symList[i].second;
+            int count = num / val;
+            if (count > 0) {
+                res.append(count, sym[0]);
+                if (sym.size() == 2) res.append(1, sym[1]);
+                num %= val;
+            }
+        }
+
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number} num
+     * @return {string}
+     */
+    intToRoman(num) {
+        const symList = [
+            ["I", 1], ["IV", 4], ["V", 5], ["IX", 9],
+            ["X", 10], ["XL", 40], ["L", 50], ["XC", 90],
+            ["C", 100], ["CD", 400], ["D", 500], ["CM", 900],
+            ["M", 1000]
+        ];
+
+        let res = "";
+        for (let i = symList.length - 1; i >= 0; i--) {
+            const [sym, val] = symList[i];
+            let count = Math.floor(num / val);
+            if (count > 0) {
+                res += sym.repeat(count);
+                num %= val;
+            }
+        }
+
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(1)$
+* Space complexity: $O(1)$
+
+---
+
+## 2. Math - II
+
+::tabs-start
+
+```python
+class Solution:
+    def intToRoman(self, num: int) -> str:
+        thousands = ["", "M", "MM", "MMM"]
+        hundreds = ["", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"]
+        tens = ["", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"]
+        ones = ["", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"]
+
+        return (
+            thousands[num // 1000] +
+            hundreds[(num % 1000) // 100] +
+            tens[(num % 100) // 10] +
+            ones[num % 10]
+        )
+```
+
+```java
+public class Solution {
+    public String intToRoman(int num) {
+        String[] thousands = {"", "M", "MM", "MMM"};
+        String[] hundreds = {"", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"};
+        String[] tens = {"", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"};
+        String[] ones = {"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"};
+
+        return thousands[num / 1000] +
+               hundreds[(num % 1000) / 100] +
+               tens[(num % 100) / 10] +
+               ones[num % 10];
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    string intToRoman(int num) {
+        string thousands[] = {"", "M", "MM", "MMM"};
+        string hundreds[] = {"", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"};
+        string tens[] = {"", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"};
+        string ones[] = {"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"};
+
+        return thousands[num / 1000] + 
+               hundreds[(num % 1000) / 100] + 
+               tens[(num % 100) / 10] + 
+               ones[num % 10];
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number} num
+     * @return {string}
+     */
+    intToRoman(num) {
+        const thousands = ["", "M", "MM", "MMM"];
+        const hundreds = ["", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"];
+        const tens = ["", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"];
+        const ones = ["", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"];
+
+        return thousands[Math.floor(num / 1000)] +
+               hundreds[Math.floor((num % 1000) / 100)] +
+               tens[Math.floor((num % 100) / 10)] +
+               ones[num % 10];
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(1)$
+* Space complexity: $O(1)$
\ No newline at end of file
diff --git a/articles/largest-submatrix-with-rearrangements.md b/articles/largest-submatrix-with-rearrangements.md
new file mode 100644
index 000000000..bebc4c94e
--- /dev/null
+++ b/articles/largest-submatrix-with-rearrangements.md
@@ -0,0 +1,522 @@
+## 1. Brute Force
+
+::tabs-start
+
+```python
+class Solution:
+    def largestSubmatrix(self, matrix: List[List[int]]) -> int:
+        ROWS, COLS = len(matrix), len(matrix[0])
+        res = 0
+
+        for start_row in range(ROWS):
+            ones = deque(list(range(COLS)))
+
+            for r in range(start_row, ROWS):
+                if not ones:
+                    break
+                for _ in range(len(ones)):
+                    c = ones.popleft()
+                    if matrix[r][c] == 1:
+                        ones.append(c)
+
+                res = max(res, len(ones) * (r - start_row + 1))
+
+        return res
+```
+
+```java
+public class Solution {
+    public int largestSubmatrix(int[][] matrix) {
+        int ROWS = matrix.length, COLS = matrix[0].length;
+        int res = 0;
+
+        for (int startRow = 0; startRow < ROWS; startRow++) {
+            Queue<Integer> ones = new LinkedList<>();
+            for (int c = 0; c < COLS; c++) {
+                ones.add(c);
+            }
+
+            for (int r = startRow; r < ROWS; r++) {
+                if (ones.isEmpty()) break;
+
+                for (int i = ones.size(); i > 0; i--) {
+                    int c = ones.poll();
+                    if (matrix[r][c] == 1) {
+                        ones.add(c);
+                    }
+                }
+
+                res = Math.max(res, ones.size() * (r - startRow + 1));
+            }
+        }
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int largestSubmatrix(vector<vector<int>>& matrix) {
+        int ROWS = matrix.size(), COLS = matrix[0].size();
+        int res = 0;
+
+        for (int startRow = 0; startRow < ROWS; startRow++) {
+            queue<int> ones;
+            for (int c = 0; c < COLS; c++) {
+                ones.push(c);
+            }
+
+            for (int r = startRow; r < ROWS; r++) {
+                if (ones.empty()) break;
+
+                for (int i = ones.size(); i > 0; i--) {
+                    int c = ones.front(); ones.pop();
+                    if (matrix[r][c] == 1) {
+                        ones.push(c);
+                    }
+                }
+
+                res = max(res, (int)ones.size() * (r - startRow + 1));
+            }
+        }
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} matrix
+     * @return {number}
+     */
+    largestSubmatrix(matrix) {
+        const ROWS = matrix.length, COLS = matrix[0].length;
+        let res = 0;
+
+        for (let startRow = 0; startRow < ROWS; startRow++) {
+            const ones = new Queue();
+            for (let c = 0; c < COLS; c++) {
+                ones.push(c);
+            }
+
+            for (let r = startRow; r < ROWS; r++) {
+                if (ones.isEmpty()) break;
+
+                for (let i = ones.size(); i > 0; i--) {
+                    let c = ones.pop();
+                    if (matrix[r][c] === 1) {
+                        ones.push(c);
+                    }
+                }
+
+                res = Math.max(res, ones.size() * (r - startRow + 1));
+            }
+        }
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(m * n ^ 2)$
+* Space complexity: $O(n)$
+
+> Where $m$ is the number of rows and $n$ is the number of columns.
+
+---
+
+## 2. Greedy + Sorting
+
+::tabs-start
+
+```python
+class Solution:
+    def largestSubmatrix(self, matrix: List[List[int]]) -> int:
+        ROWS, COLS = len(matrix), len(matrix[0])
+        res = 0
+        prev_heights = [0] * COLS
+
+        for r in range(ROWS):
+            heights = matrix[r][:]
+            for c in range(COLS):
+                if heights[c] > 0:
+                    heights[c] += prev_heights[c]
+
+            sorted_heights = sorted(heights, reverse=True)
+            for i in range(COLS):
+                res = max(res, (i + 1) * sorted_heights[i])
+
+            prev_heights = heights
+
+        return res
+```
+
+```java
+public class Solution {
+    public int largestSubmatrix(int[][] matrix) {
+        int ROWS = matrix.length, COLS = matrix[0].length;
+        int res = 0;
+        int[] prevHeights = new int[COLS];
+
+        for (int r = 0; r < ROWS; r++) {
+            int[] heights = Arrays.copyOf(matrix[r], COLS);
+            int[] sortedHgts = Arrays.copyOf(matrix[r], COLS);
+
+            for (int c = 0; c < COLS; c++) {
+                if (heights[c] > 0) {
+                    heights[c] += prevHeights[c];
+                    sortedHgts[c] = heights[c];
+                }
+            }
+
+            Arrays.sort(sortedHgts);
+            for (int i = COLS - 1; i >= 0; i--) {
+                res = Math.max(res, (COLS - i) * sortedHgts[i]);
+            }
+
+            prevHeights = heights;
+        }
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int largestSubmatrix(vector<vector<int>>& matrix) {
+        int ROWS = matrix.size(), COLS = matrix[0].size();
+        int res = 0;
+        vector<int> prevHeights(COLS);
+
+        for (int r = 0; r < ROWS; r++) {
+            vector<int> heights = matrix[r];
+            vector<int> sortedHgts = matrix[r];
+
+            for (int c = 0; c < COLS; c++) {
+                if (heights[c] > 0) {
+                    heights[c] += prevHeights[c];
+                    sortedHgts[c] = heights[c];
+                }
+            }
+
+            sort(sortedHgts.begin(), sortedHgts.end(), greater<int>());
+            for (int i = 0; i < COLS; i++) {
+                res = max(res, (i + 1) * sortedHgts[i]);
+            }
+
+            prevHeights = heights;
+        }
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} matrix
+     * @return {number}
+     */
+    largestSubmatrix(matrix) {
+        const ROWS = matrix.length, COLS = matrix[0].length;
+        let res = 0;
+        let prevHeights = new Array(COLS).fill(0);
+
+        for (let r = 0; r < ROWS; r++) {
+            let heights = [...matrix[r]];
+            let sortedHgts = [...matrix[r]];
+
+            for (let c = 0; c < COLS; c++) {
+                if (heights[c] > 0) {
+                    heights[c] += prevHeights[c];
+                    sortedHgts[c] = heights[c];
+                }
+            }
+
+            sortedHgts.sort((a, b) => b - a);
+            for (let i = 0; i < COLS; i++) {
+                res = Math.max(res, (i + 1) * sortedHgts[i]);
+            }
+
+            prevHeights = heights;
+        }
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(m * n \log n)$
+* Space complexity: $O(n)$
+
+> Where $m$ is the number of rows and $n$ is the number of columns.
+
+---
+
+## 3. Greedy + Sorting (Overwriting the Input)
+
+::tabs-start
+
+```python
+class Solution:
+    def largestSubmatrix(self, matrix: List[List[int]]) -> int:
+        ROWS, COLS = len(matrix), len(matrix[0])
+        res = 0
+
+        for r in range(1, ROWS):
+            for c in range(COLS):
+                if matrix[r][c]:
+                    matrix[r][c] += matrix[r - 1][c]
+
+        for r in range(ROWS):
+            matrix[r].sort(reverse=True)
+            for i in range(COLS):
+                res = max(res, (i + 1) * matrix[r][i])
+
+        return res
+```
+
+```java
+public class Solution {
+    public int largestSubmatrix(int[][] matrix) {
+        int ROWS = matrix.length, COLS = matrix[0].length;
+        int res = 0;
+
+        for (int r = 1; r < ROWS; r++) {
+            for (int c = 0; c < COLS; c++) {
+                if (matrix[r][c] > 0) {
+                    matrix[r][c] += matrix[r - 1][c];
+                }
+            }
+        }
+
+        for (int r = 0; r < ROWS; r++) {
+            Arrays.sort(matrix[r]);
+            for (int i = 0; i < COLS; i++) {
+                res = Math.max(res, (COLS - i) * matrix[r][i]);
+            }
+        }
+
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int largestSubmatrix(vector<vector<int>>& matrix) {
+        int ROWS = matrix.size(), COLS = matrix[0].size();
+        int res = 0;
+
+        for (int r = 1; r < ROWS; r++) {
+            for (int c = 0; c < COLS; c++) {
+                if (matrix[r][c] > 0) {
+                    matrix[r][c] += matrix[r - 1][c];
+                }
+            }
+        }
+
+        for (int r = 0; r < ROWS; r++) {
+            sort(matrix[r].begin(), matrix[r].end(), greater<int>());
+            for (int i = 0; i < COLS; i++) {
+                res = max(res, (i + 1) * matrix[r][i]);
+            }
+        }
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} matrix
+     * @return {number}
+     */
+    largestSubmatrix(matrix) {
+        const ROWS = matrix.length, COLS = matrix[0].length;
+        let res = 0;
+
+        for (let r = 1; r < ROWS; r++) {
+            for (let c = 0; c < COLS; c++) {
+                if (matrix[r][c] > 0) {
+                    matrix[r][c] += matrix[r - 1][c];
+                }
+            }
+        }
+
+        for (let r = 0; r < ROWS; r++) {
+            matrix[r].sort((a, b) => b - a);
+            for (let i = 0; i < COLS; i++) {
+                res = Math.max(res, (i + 1) * matrix[r][i]);
+            }
+        }
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(m * n \log n)$
+* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algoirhtm.
+
+> Where $m$ is the number of rows and $n$ is the number of columns.
+
+---
+
+## 4. Greedy
+
+::tabs-start
+
+```python
+class Solution:
+    def largestSubmatrix(self, matrix: List[List[int]]) -> int:
+        ROWS, COLS = len(matrix), len(matrix[0])
+        res = 0
+        prevHeights = []
+
+        for r in range(ROWS):
+            heights = []
+            for c in prevHeights:
+                if matrix[r][c]:
+                    matrix[r][c] += matrix[r - 1][c]
+                    heights.append(c)
+
+            for c in range(COLS):
+                if matrix[r][c] == 1:
+                    heights.append(c)
+
+            for i, c in enumerate(heights):
+                res = max(res, (i + 1) * matrix[r][c])
+
+            prevHeights = heights
+
+        return res
+```
+
+```java
+public class Solution {
+    public int largestSubmatrix(int[][] matrix) {
+        int ROWS = matrix.length, COLS = matrix[0].length;
+        int res = 0;
+        List<Integer> prevHeights = new ArrayList<>();
+
+        for (int r = 0; r < ROWS; r++) {
+            List<Integer> heights = new ArrayList<>();
+
+            for (int c : prevHeights) {
+                if (matrix[r][c] == 1) {
+                    matrix[r][c] += matrix[r - 1][c];
+                    heights.add(c);
+                }
+            }
+
+            for (int c = 0; c < COLS; c++) {
+                if (matrix[r][c] == 1) {
+                    heights.add(c);
+                }
+            }
+
+            for (int i = 0; i < heights.size(); i++) {
+                res = Math.max(res, (i + 1) * matrix[r][heights.get(i)]);
+            }
+
+            prevHeights = heights;
+        }
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int largestSubmatrix(vector<vector<int>>& matrix) {
+        int ROWS = matrix.size(), COLS = matrix[0].size(), res = 0;
+        vector<int> prevHeights;
+
+        for (int r = 0; r < ROWS; r++) {
+            vector<int> heights;
+
+            for (int c : prevHeights) {
+                if (matrix[r][c] == 1) {
+                    matrix[r][c] += matrix[r - 1][c];
+                    heights.push_back(c);
+                }
+            }
+
+            for (int c = 0; c < COLS; c++) {
+                if (matrix[r][c] == 1) {
+                    heights.push_back(c);
+                }
+            }
+
+            for (int i = 0; i < heights.size(); i++) {
+                res = max(res, (i + 1) * matrix[r][heights[i]]);
+            }
+
+            prevHeights = heights;
+        }
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} matrix
+     * @return {number}
+     */
+    largestSubmatrix(matrix) {
+        const ROWS = matrix.length, COLS = matrix[0].length;
+        let res = 0, prevHeights = [];
+
+        for (let r = 0; r < ROWS; r++) {
+            let heights = [];
+
+            for (let c of prevHeights) {
+                if (matrix[r][c] === 1) {
+                    matrix[r][c] += matrix[r - 1][c];
+                    heights.push(c);
+                }
+            }
+
+            for (let c = 0; c < COLS; c++) {
+                if (matrix[r][c] === 1) {
+                    heights.push(c);
+                }
+            }
+
+            for (let i = 0; i < heights.length; i++) {
+                res = Math.max(res, (i + 1) * matrix[r][heights[i]]);
+            }
+
+            prevHeights = heights;
+        }
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(m * n)$
+* Space complexity: $O(n)$
+
+> Where $m$ is the number of rows and $n$ is the number of columns.
\ No newline at end of file
diff --git a/articles/minimum-one-bit-operations-to-make-integers-zero.md b/articles/minimum-one-bit-operations-to-make-integers-zero.md
new file mode 100644
index 000000000..7e4071ce6
--- /dev/null
+++ b/articles/minimum-one-bit-operations-to-make-integers-zero.md
@@ -0,0 +1,313 @@
+## 1. Math (Recursion)
+
+::tabs-start
+
+```python
+class Solution:
+    def minimumOneBitOperations(self, n: int) -> int:
+        if n == 0:
+            return 0
+
+        k = 1
+        while (k << 1) <= n:
+            k <<= 1
+
+        return (k << 1) - 1 - self.minimumOneBitOperations(k ^ n)
+```
+
+```java
+public class Solution {
+    public int minimumOneBitOperations(int n) {
+        if (n == 0) {
+            return 0;
+        }
+
+        int k = 1;
+        while ((k << 1) <= n) {
+            k <<= 1;
+        }
+
+        return (k << 1) - 1 - minimumOneBitOperations(k ^ n);
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int minimumOneBitOperations(int n) {
+        if (n == 0) {
+            return 0;
+        }
+
+        int k = 1;
+        while ((k << 1) <= n) {
+            k <<= 1;
+        }
+
+        return (k << 1) - 1 - minimumOneBitOperations(k ^ n);
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number} n
+     * @return {number}
+     */
+    minimumOneBitOperations(n) {
+        if (n === 0) {
+            return 0;
+        }
+
+        let k = 1;
+        while ((k << 1) <= n) {
+            k <<= 1;
+        }
+
+        return (k << 1) - 1 - this.minimumOneBitOperations(k ^ n);
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(\log n)$
+* Space complexity: $O(\log n)$ for recursion stack.
+
+---
+
+## 2. Math (Iteration) - I
+
+::tabs-start
+
+```python
+class Solution:
+    def minimumOneBitOperations(self, n: int) -> int:
+        res = 0
+        k = 1 << 30
+        sign = 1
+
+        while n:
+            while k > n:
+                k >>= 1
+
+            res += (sign * ((k << 1) - 1))
+            sign *= -1
+            n ^= k
+
+        return res
+```
+
+```java
+public class Solution {
+    public int minimumOneBitOperations(int n) {
+        int res = 0, k = 1 << 30, sign = 1;
+
+        while (n != 0) {
+            while (k > n) {
+                k >>= 1;
+            }
+
+            res += (sign * ((k << 1) - 1));
+            sign *= -1;
+            n ^= k;
+        }
+
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int minimumOneBitOperations(int n) {
+        int res = 0, k = 1 << 30, sign = 1;
+
+        while (n != 0) {
+            while (k > n) {
+                k >>= 1;
+            }
+
+            res += sign * ((k << 1) - 1);
+            sign *= -1;
+            n ^= k;
+        }
+
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number} n
+     * @return {number}
+     */
+    minimumOneBitOperations(n) {
+        let res = 0, k = 1 << 30, sign = 1;
+
+        while (n !== 0) {
+            while (k > n) {
+                k >>= 1;
+            }
+
+            res += sign * ((k << 1) - 1);
+            sign *= -1;
+            n ^= k;
+        }
+
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(\log n)$
+* Space complexity: $O(1)$
+
+---
+
+## 3. Math (Iteration) - II
+
+::tabs-start
+
+```python
+class Solution:
+    def minimumOneBitOperations(self, n: int) -> int:
+        res, sign = 0, 1
+        while n:
+            res += sign * (n ^ (n - 1))
+            n &= (n - 1)
+            sign *= -1
+        return abs(res)
+```
+
+```java
+public class Solution {
+    public int minimumOneBitOperations(int n) {
+        int res = 0, sign = 1;
+        while (n != 0) {
+            res += sign * (n ^ (n - 1));
+            n &= (n - 1);
+            sign *= -1;
+        }
+        return Math.abs(res);
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int minimumOneBitOperations(int n) {
+        int res = 0, sign = 1;
+        while (n != 0) {
+            res += sign * (n ^ (n - 1));
+            n &= (n - 1);
+            sign *= -1;
+        }
+        return abs(res);
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number} n
+     * @return {number}
+     */
+    minimumOneBitOperations(n) {
+        let res = 0, sign = 1;
+        while (n !== 0) {
+            res += sign * (n ^ (n - 1));
+            n &= (n - 1);
+            sign *= -1;
+        }
+        return Math.abs(res);
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(\log n)$
+* Space complexity: $O(1)$
+
+---
+
+## 4. Math (Grey Code)
+
+::tabs-start
+
+```python
+class Solution:
+    def minimumOneBitOperations(self, n: int) -> int:
+        res = n
+        while n:
+            n >>= 1
+            res ^= n
+        return res
+```
+
+```java
+public class Solution {
+    public int minimumOneBitOperations(int n) {
+        int res = n;
+        while (n != 0) {
+            n >>= 1;
+            res ^= n;
+        }
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int minimumOneBitOperations(int n) {
+        int res = n;
+        while (n != 0) {
+            n >>= 1;
+            res ^= n;
+        }
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number} n
+     * @return {number}
+     */
+    minimumOneBitOperations(n) {
+        let res = n;
+        while (n !== 0) {
+            n >>= 1;
+            res ^= n;
+        }
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(\log n)$
+* Space complexity: $O(1)$
\ No newline at end of file
diff --git a/articles/remove-covered-intervals.md b/articles/remove-covered-intervals.md
new file mode 100644
index 000000000..f71a0cfcc
--- /dev/null
+++ b/articles/remove-covered-intervals.md
@@ -0,0 +1,275 @@
+## 1. Brute Force
+
+::tabs-start
+
+```python
+class Solution:
+    def removeCoveredIntervals(self, intervals: List[List[int]]) -> int:
+        n = len(intervals)
+        res = n
+
+        for i in range(n):
+            for j in range(n):
+                if (i != j and intervals[j][0] <= intervals[i][0] and 
+                    intervals[j][1] >= intervals[i][1]
+                ):
+                    res -= 1
+                    break
+
+        return res
+```
+
+```java
+public class Solution {
+    public int removeCoveredIntervals(int[][] intervals) {
+        int n = intervals.length;
+        int res = n;
+
+        for (int i = 0; i < n; i++) {
+            for (int j = 0; j < n; j++) {
+                if (i != j && intervals[j][0] <= intervals[i][0] && 
+                    intervals[j][1] >= intervals[i][1]) {
+                    res--;
+                    break;
+                }
+            }
+        }
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int removeCoveredIntervals(vector<vector<int>>& intervals) {
+        int n = intervals.size();
+        int res = n;
+
+        for (int i = 0; i < n; i++) {
+            for (int j = 0; j < n; j++) {
+                if (i != j && intervals[j][0] <= intervals[i][0] && 
+                    intervals[j][1] >= intervals[i][1]) {
+                    res--;
+                    break;
+                }
+            }
+        }
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} intervals
+     * @return {number}
+     */
+    removeCoveredIntervals(intervals) {
+        let n = intervals.length;
+        let res = n;
+
+        for (let i = 0; i < n; i++) {
+            for (let j = 0; j < n; j++) {
+                if (i !== j && intervals[j][0] <= intervals[i][0] && 
+                    intervals[j][1] >= intervals[i][1]) {
+                    res--;
+                    break;
+                }
+            }
+        }
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n ^ 2)$
+* Space complexity: $O(1)$ extra space.
+
+---
+
+## 2. Sorting - I
+
+::tabs-start
+
+```python
+class Solution:
+    def removeCoveredIntervals(self, intervals: List[List[int]]) -> int:
+        intervals.sort(key=lambda x: (x[0], -x[1]))
+        res = 1
+        prevL, prevR = intervals[0][0], intervals[0][1]
+        for l, r in intervals:
+            if prevL <= l and prevR >= r:
+                continue
+            res += 1
+            prevL, prevR = l, r
+
+        return res
+```
+
+```java
+public class Solution {
+    public int removeCoveredIntervals(int[][] intervals) {
+        Arrays.sort(intervals, (a, b) -> 
+            a[0] == b[0] ? Integer.compare(b[1], a[1]) : Integer.compare(a[0], b[0])
+        );
+        int res = 1, prevL = intervals[0][0], prevR = intervals[0][1];
+        for (int[] interval : intervals) {
+            int l = interval[0], r = interval[1];
+            if (prevL <= l && prevR >= r) {
+                continue;
+            }
+            res++;
+            prevL = l;
+            prevR = r;
+        }
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int removeCoveredIntervals(vector<vector<int>>& intervals) {
+        sort(intervals.begin(), intervals.end(), [](const auto& a, const auto& b) {
+            return a[0] == b[0] ? b[1] < a[1] : a[0] < b[0];
+        });
+
+        int res = 1, prevL = intervals[0][0], prevR = intervals[0][1];
+        for (const auto& interval : intervals) {
+            int l = interval[0], r = interval[1];
+            if (prevL <= l && prevR >= r) {
+                continue;
+            }
+            res++;
+            prevL = l;
+            prevR = r;
+        }
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} intervals
+     * @return {number}
+     */
+    removeCoveredIntervals(intervals) {
+        intervals.sort((a, b) => a[0] === b[0] ? b[1] - a[1] : a[0] - b[0]);
+        let res = 1, [prevL, prevR] = intervals[0];
+        for (const [l, r] of intervals) {
+            if (prevL <= l && prevR >= r) {
+                continue;
+            }
+            res++;
+            prevL = l;
+            prevR = r;
+        }
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n\log n)$
+* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm.
+
+---
+
+## 3. Sorting - II
+
+::tabs-start
+
+```python
+class Solution:
+    def removeCoveredIntervals(self, intervals: List[List[int]]) -> int:
+        intervals.sort()
+        res, start, end = 1, intervals[0][0], intervals[0][1]
+
+        for l, r in intervals:
+            if start < l and end < r:
+                start = l
+                res += 1
+            end = max(end, r)
+
+        return res
+```
+
+```java
+public class Solution {
+    public int removeCoveredIntervals(int[][] intervals) {
+        Arrays.sort(intervals, (a, b) -> a[0] - b[0]);
+        int res = 1, start = intervals[0][0], end = intervals[0][1];
+
+        for (int[] interval : intervals) {
+            int l = interval[0], r = interval[1];
+            if (start < l && end < r) {
+                start = l;
+                res++;
+            }
+            end = Math.max(end, r);
+        }
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int removeCoveredIntervals(vector<vector<int>>& intervals) {
+        sort(intervals.begin(), intervals.end());
+        int res = 1, start = intervals[0][0], end = intervals[0][1];
+
+        for (const auto& interval : intervals) {
+            int l = interval[0], r = interval[1];
+            if (start < l && end < r) {
+                start = l;
+                res++;
+            }
+            end = max(end, r);
+        }
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} intervals
+     * @return {number}
+     */
+    removeCoveredIntervals(intervals) {
+        intervals.sort((a, b) => a[0] - b[0]);
+        let res = 1, start = intervals[0][0], end = intervals[0][1];
+
+        for (const [l, r] of intervals) {
+            if (start < l && end < r) {
+                start = l;
+                res++;
+            }
+            end = Math.max(end, r);
+        }
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n \log n)$
+* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm.
\ No newline at end of file
diff --git a/articles/widest-vertical-area-between-two-points-containing-no-points.md b/articles/widest-vertical-area-between-two-points-containing-no-points.md
new file mode 100644
index 000000000..b41a574f7
--- /dev/null
+++ b/articles/widest-vertical-area-between-two-points-containing-no-points.md
@@ -0,0 +1,212 @@
+## 1. Brute Force
+
+::tabs-start
+
+```python
+class Solution:
+    def maxWidthOfVerticalArea(self, points: List[List[int]]) -> int:
+        n = len(points)
+        res = 0
+
+        for i in range(1, n):
+            x1 = points[i][0]
+            for j in range(i):
+                x2 = points[j][0]
+                hasPoints = False
+                for k in range(n):
+                    if k == i or k == j:
+                        continue
+
+                    x3 = points[k][0]
+                    if x3 > min(x1, x2) and x3 < max(x1, x2):
+                        hasPoints = True
+                        break
+
+                if not hasPoints:
+                    res = max(res, abs(x1 - x2))
+
+        return res
+```
+
+```java
+public class Solution {
+    public int maxWidthOfVerticalArea(int[][] points) {
+        int n = points.length, res = 0;
+
+        for (int i = 1; i < n; i++) {
+            int x1 = points[i][0];
+            for (int j = 0; j < i; j++) {
+                int x2 = points[j][0];
+                boolean hasPoints = false;
+
+                for (int k = 0; k < n; k++) {
+                    if (k == i || k == j) continue;
+                    
+                    int x3 = points[k][0];
+                    if (x3 > Math.min(x1, x2) && x3 < Math.max(x1, x2)) {
+                        hasPoints = true;
+                        break;
+                    }
+                }
+
+                if (!hasPoints) {
+                    res = Math.max(res, Math.abs(x1 - x2));
+                }
+            }
+        }
+
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int maxWidthOfVerticalArea(vector<vector<int>>& points) {
+        int n = points.size(), res = 0;
+
+        for (int i = 1; i < n; i++) {
+            int x1 = points[i][0];
+            for (int j = 0; j < i; j++) {
+                int x2 = points[j][0];
+                bool hasPoints = false;
+
+                for (int k = 0; k < n; k++) {
+                    if (k == i || k == j) continue;
+
+                    int x3 = points[k][0];
+                    if (x3 > min(x1, x2) && x3 < max(x1, x2)) {
+                        hasPoints = true;
+                        break;
+                    }
+                }
+
+                if (!hasPoints) {
+                    res = max(res, abs(x1 - x2));
+                }
+            }
+        }
+
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} points
+     * @return {number}
+     */
+    maxWidthOfVerticalArea(points) {
+        let n = points.length, res = 0;
+
+        for (let i = 1; i < n; i++) {
+            let x1 = points[i][0];
+            for (let j = 0; j < i; j++) {
+                let x2 = points[j][0];
+                let hasPoints = false;
+
+                for (let k = 0; k < n; k++) {
+                    if (k === i || k === j) continue;
+
+                    let x3 = points[k][0];
+                    if (x3 > Math.min(x1, x2) && x3 < Math.max(x1, x2)) {
+                        hasPoints = true;
+                        break;
+                    }
+                }
+
+                if (!hasPoints) {
+                    res = Math.max(res, Math.abs(x1 - x2));
+                }
+            }
+        }
+
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n ^ 3)$
+* Space complexity: $O(1)$
+
+---
+
+## 2. Sorting
+
+::tabs-start
+
+```python
+class Solution:
+    def maxWidthOfVerticalArea(self, points: List[List[int]]) -> int:
+        points.sort()
+        res = 0
+        for i in range(len(points) - 1):
+            res = max(res, points[i + 1][0] - points[i][0])
+        return res
+```
+
+```java
+public class Solution {
+    public int maxWidthOfVerticalArea(int[][] points) {
+        Arrays.sort(points, Comparator.comparingInt(a -> a[0]));
+        int res = 0;
+
+        for (int i = 0; i < points.length - 1; i++) {
+            res = Math.max(res, points[i + 1][0] - points[i][0]);
+        }
+
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int maxWidthOfVerticalArea(vector<vector<int>>& points) {
+        sort(points.begin(), points.end(), [](const auto& a, const auto& b) {
+            return a[0] < b[0];
+        });
+
+        int res = 0;
+        for (int i = 0; i < points.size() - 1; i++) {
+            res = max(res, points[i + 1][0] - points[i][0]);
+        }
+
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} points
+     * @return {number}
+     */
+    maxWidthOfVerticalArea(points) {
+        points.sort((a, b) => a[0] - b[0]);
+        let res = 0;
+
+        for (let i = 0; i < points.length - 1; i++) {
+            res = Math.max(res, points[i + 1][0] - points[i][0]);
+        }
+
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n \log n)$
+* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm.
\ No newline at end of file

From 780cc7d3ce7eda7fdd5908d25038dd4f9fcffcd6 Mon Sep 17 00:00:00 2001
From: Sri Hari <kataresrihari@gmail.com>
Date: Mon, 10 Feb 2025 19:23:14 +0530
Subject: [PATCH 10/13] Batch-5/Neetcode-ALL/Added-articles

---
 articles/score-after-flipping-matrix.md | 253 ++++++++++++++++++++++++
 1 file changed, 253 insertions(+)
 create mode 100644 articles/score-after-flipping-matrix.md

diff --git a/articles/score-after-flipping-matrix.md b/articles/score-after-flipping-matrix.md
new file mode 100644
index 000000000..83c222266
--- /dev/null
+++ b/articles/score-after-flipping-matrix.md
@@ -0,0 +1,253 @@
+## 1. Greedy (Overwriting the Input)
+
+::tabs-start
+
+```python
+class Solution:
+    def matrixScore(self, grid: List[List[int]]) -> int:
+        ROWS, COLS = len(grid), len(grid[0])
+
+        for r in range(ROWS):
+            if grid[r][0] == 0:
+                for c in range(COLS):
+                    grid[r][c] ^= 1
+
+        for c in range(COLS):
+            one_cnt = sum(grid[r][c] for r in range(ROWS))
+            if one_cnt < ROWS - one_cnt:
+                for r in range(ROWS):
+                    grid[r][c] ^= 1
+
+        res = 0
+        for r in range(ROWS):
+            for c in range(COLS):
+                res += grid[r][c] << (COLS - c - 1)
+
+        return res
+```
+
+```java
+public class Solution {
+    public int matrixScore(int[][] grid) {
+        int ROWS = grid.length, COLS = grid[0].length;
+
+        for (int r = 0; r < ROWS; r++) {
+            if (grid[r][0] == 0) {
+                for (int c = 0; c < COLS; c++) {
+                    grid[r][c] ^= 1;
+                }
+            }
+        }
+
+        for (int c = 0; c < COLS; c++) {
+            int oneCnt = 0;
+            for (int r = 0; r < ROWS; r++) {
+                oneCnt += grid[r][c];
+            }
+            if (oneCnt < ROWS - oneCnt) {
+                for (int r = 0; r < ROWS; r++) {
+                    grid[r][c] ^= 1;
+                }
+            }
+        }
+
+        int res = 0;
+        for (int r = 0; r < ROWS; r++) {
+            for (int c = 0; c < COLS; c++) {
+                res += grid[r][c] << (COLS - c - 1);
+            }
+        }
+
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int matrixScore(vector<vector<int>>& grid) {
+        int ROWS = grid.size(), COLS = grid[0].size();
+
+        for (int r = 0; r < ROWS; r++) {
+            if (grid[r][0] == 0) {
+                for (int c = 0; c < COLS; c++) {
+                    grid[r][c] ^= 1;
+                }
+            }
+        }
+
+        for (int c = 0; c < COLS; c++) {
+            int oneCnt = 0;
+            for (int r = 0; r < ROWS; r++) {
+                oneCnt += grid[r][c];
+            }
+            if (oneCnt < ROWS - oneCnt) {
+                for (int r = 0; r < ROWS; r++) {
+                    grid[r][c] ^= 1;
+                }
+            }
+        }
+
+        int res = 0;
+        for (int r = 0; r < ROWS; r++) {
+            for (int c = 0; c < COLS; c++) {
+                res += grid[r][c] << (COLS - c - 1);
+            }
+        }
+
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} grid
+     * @return {number}
+     */
+    matrixScore(grid) {
+        let ROWS = grid.length, COLS = grid[0].length;
+
+        for (let r = 0; r < ROWS; r++) {
+            if (grid[r][0] === 0) {
+                for (let c = 0; c < COLS; c++) {
+                    grid[r][c] ^= 1;
+                }
+            }
+        }
+
+        for (let c = 0; c < COLS; c++) {
+            let oneCnt = 0;
+            for (let r = 0; r < ROWS; r++) {
+                oneCnt += grid[r][c];
+            }
+            if (oneCnt < ROWS - oneCnt) {
+                for (let r = 0; r < ROWS; r++) {
+                    grid[r][c] ^= 1;
+                }
+            }
+        }
+
+        let res = 0;
+        for (let r = 0; r < ROWS; r++) {
+            for (let c = 0; c < COLS; c++) {
+                res += grid[r][c] << (COLS - c - 1);
+            }
+        }
+
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(m * n)$
+* Space complexity: $O(1)$ extra space.
+
+> Where $m$ is the number of rows and $n$ is the number of columns.
+
+---
+
+## 2. Greedy (Optimal)
+
+::tabs-start
+
+```python
+class Solution:
+    def matrixScore(self, grid: List[List[int]]) -> int:
+        ROWS, COLS = len(grid), len(grid[0])
+        res = ROWS * (1 << (COLS - 1))
+
+        for c in range(1, COLS):
+            cnt = 0
+            for r in range(ROWS):
+                if grid[r][c] != grid[r][0]:
+                    cnt += 1
+
+            cnt = max(cnt, ROWS - cnt)
+            res += cnt * (1 << (COLS - c - 1))
+
+        return res
+```
+
+```java
+public class Solution {
+    public int matrixScore(int[][] grid) {
+        int ROWS = grid.length, COLS = grid[0].length;
+        int res = ROWS * (1 << (COLS - 1));
+
+        for (int c = 1; c < COLS; c++) {
+            int cnt = 0;
+            for (int r = 0; r < ROWS; r++) {
+                if (grid[r][c] != grid[r][0]) {
+                    cnt++;
+                }
+            }
+            cnt = Math.max(cnt, ROWS - cnt);
+            res += cnt * (1 << (COLS - c - 1));
+        }
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int matrixScore(vector<vector<int>>& grid) {
+        int ROWS = grid.size(), COLS = grid[0].size();
+        int res = ROWS * (1 << (COLS - 1));
+
+        for (int c = 1; c < COLS; c++) {
+            int cnt = 0;
+            for (int r = 0; r < ROWS; r++) {
+                if (grid[r][c] != grid[r][0]) {
+                    cnt++;
+                }
+            }
+            cnt = max(cnt, ROWS - cnt);
+            res += cnt * (1 << (COLS - c - 1));
+        }
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[][]} grid
+     * @return {number}
+     */
+    matrixScore(grid) {
+        const ROWS = grid.length, COLS = grid[0].length;
+        let res = ROWS * (1 << (COLS - 1));
+
+        for (let c = 1; c < COLS; c++) {
+            let cnt = 0;
+            for (let r = 0; r < ROWS; r++) {
+                if (grid[r][c] !== grid[r][0]) {
+                    cnt++;
+                }
+            }
+            cnt = Math.max(cnt, ROWS - cnt);
+            res += cnt * (1 << (COLS - c - 1));
+        }
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(m * n)$
+* Space complexity: $O(1)$ extra space.
+
+> Where $m$ is the number of rows and $n$ is the number of columns.
\ No newline at end of file

From 6835d33ec754147c73f76b2acc93dad4201a5c4d Mon Sep 17 00:00:00 2001
From: Sri Hari <kataresrihari@gmail.com>
Date: Tue, 11 Feb 2025 23:19:49 +0530
Subject: [PATCH 11/13] Batch-5/Neetcode-ALL/Added-articles

---
 articles/data-stream-as-disjoint-intervals.md | 450 +++++++++++
 .../find-the-maximum-sum-of-node-values.md    | 637 +++++++++++++++
 articles/maximum-score-of-a-good-subarray.md  | 729 ++++++++++++++++++
 ...ring-into-descending-consecutive-values.md | 570 ++++++++++++++
 4 files changed, 2386 insertions(+)
 create mode 100644 articles/data-stream-as-disjoint-intervals.md
 create mode 100644 articles/find-the-maximum-sum-of-node-values.md
 create mode 100644 articles/maximum-score-of-a-good-subarray.md
 create mode 100644 articles/splitting-a-string-into-descending-consecutive-values.md

diff --git a/articles/data-stream-as-disjoint-intervals.md b/articles/data-stream-as-disjoint-intervals.md
new file mode 100644
index 000000000..a39dc70f3
--- /dev/null
+++ b/articles/data-stream-as-disjoint-intervals.md
@@ -0,0 +1,450 @@
+## 1. Brute Force (Sorting)
+
+::tabs-start
+
+```python
+class SummaryRanges:
+
+    def __init__(self):
+        self.arr = []
+
+    def addNum(self, value: int) -> None:
+        self.arr.append(value)
+
+    def getIntervals(self) -> List[List[int]]:
+        if not self.arr:
+            return []
+
+        self.arr.sort()
+        n = len(self.arr)
+        start = self.arr[0]
+        res = []
+        for i in range(1, n):
+            if self.arr[i] - self.arr[i - 1] > 1:
+                res.append([start, self.arr[i - 1]])
+                start = self.arr[i]
+
+        res.append([start, self.arr[n - 1]])
+        return res
+```
+
+```java
+public class SummaryRanges {
+    private List<Integer> arr;
+
+    public SummaryRanges() {
+        arr = new ArrayList<>();
+    }
+
+    public void addNum(int value) {
+        arr.add(value);
+    }
+
+    public List<int[]> getIntervals() {
+        List<int[]> res = new ArrayList<>();
+        if (arr.isEmpty()) return res;
+
+        Collections.sort(arr);
+        int start = arr.get(0);
+        for (int i = 1; i < arr.size(); i++) {
+            if (arr.get(i) - arr.get(i - 1) > 1) {
+                res.add(new int[]{start, arr.get(i - 1)});
+                start = arr.get(i);
+            }
+        }
+        res.add(new int[]{start, arr.get(arr.size() - 1)});
+        return res;
+    }
+}
+```
+
+```cpp
+class SummaryRanges {
+private:
+    vector<int> arr;
+
+public:
+    SummaryRanges() {}
+
+    void addNum(int value) {
+        arr.push_back(value);
+    }
+
+    vector<vector<int>> getIntervals() {
+        vector<vector<int>> res;
+        if (arr.empty()) return res;
+
+        sort(arr.begin(), arr.end());
+        int start = arr[0];
+        for (int i = 1; i < arr.size(); i++) {
+            if (arr[i] - arr[i - 1] > 1) {
+                res.push_back({start, arr[i - 1]});
+                start = arr[i];
+            }
+        }
+        res.push_back({start, arr.back()});
+        return res;
+    }
+};
+```
+
+```javascript
+class SummaryRanges {
+    constructor() {
+        this.arr = [];
+    }
+
+    /** 
+     * @param {number} value
+     * @return {void}
+     */
+    addNum(value) {
+        this.arr.push(value);
+    }
+
+    /**
+     * @return {number[][]}
+     */
+    getIntervals() {
+        if (this.arr.length === 0) return [];
+
+        this.arr.sort((a, b) => a - b);
+        let start = this.arr[0];
+        let res = [];
+
+        for (let i = 1; i < this.arr.length; i++) {
+            if (this.arr[i] - this.arr[i - 1] > 1) {
+                res.push([start, this.arr[i - 1]]);
+                start = this.arr[i];
+            }
+        }
+        res.push([start, this.arr[this.arr.length - 1]]);
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity:
+    * $O(1)$ time for initialization.
+    * $O(1)$ time for each $addNum()$ function call.
+    * $O(n \log n)$ time for each $getIntervals()$ function call.
+* Space complexity: $O(n)$
+
+---
+
+## 2. Hash Set + Sorting
+
+::tabs-start
+
+```python
+class SummaryRanges:
+
+    def __init__(self):
+        self.arr = set()
+
+    def addNum(self, value: int) -> None:
+        self.arr.add(value)
+
+    def getIntervals(self) -> List[List[int]]:
+        if not self.arr:
+            return []
+
+        lst = sorted(list(self.arr))
+        n = len(lst)
+        start = lst[0]
+        res = []
+        for i in range(1, n):
+            if lst[i] - lst[i - 1] > 1:
+                res.append([start, lst[i - 1]])
+                start = lst[i]
+
+        res.append([start, lst[n - 1]])
+        return res
+```
+
+```java
+public class SummaryRanges {
+    private Set<Integer> arr;
+
+    public SummaryRanges() {
+        arr = new TreeSet<>();
+    }
+
+    public void addNum(int value) {
+        arr.add(value);
+    }
+
+    public List<int[]> getIntervals() {
+        List<int[]> res = new ArrayList<>();
+        if (arr.isEmpty()) return res;
+
+        List<Integer> lst = new ArrayList<>(arr);
+        int start = lst.get(0);
+        for (int i = 1; i < lst.size(); i++) {
+            if (lst.get(i) - lst.get(i - 1) > 1) {
+                res.add(new int[]{start, lst.get(i - 1)});
+                start = lst.get(i);
+            }
+        }
+        res.add(new int[]{start, lst.get(lst.size() - 1)});
+        return res;
+    }
+}
+```
+
+```cpp
+class SummaryRanges {
+private:
+    set<int> arr;
+
+public:
+    SummaryRanges() {}
+
+    void addNum(int value) {
+        arr.insert(value);
+    }
+
+    vector<vector<int>> getIntervals() {
+        vector<vector<int>> res;
+        if (arr.empty()) return res;
+
+        vector<int> lst(arr.begin(), arr.end());
+        int start = lst[0];
+
+        for (int i = 1; i < lst.size(); i++) {
+            if (lst[i] - lst[i - 1] > 1) {
+                res.push_back({start, lst[i - 1]});
+                start = lst[i];
+            }
+        }
+        res.push_back({start, lst.back()});
+        return res;
+    }
+};
+```
+
+```javascript
+class SummaryRanges {
+    constructor() {
+        this.arr = new Set();
+    }
+
+    /**
+     * @param {number} value
+     * @return {number[][]}
+     */
+    addNum(value) {
+        this.arr.add(value);
+    }
+
+    /**
+     * @return {number[][]}
+     */
+    getIntervals() {
+        if (this.arr.size === 0) return [];
+
+        let lst = Array.from(this.arr).sort((a, b) => a - b);
+        let start = lst[0];
+        let res = [];
+
+        for (let i = 1; i < lst.length; i++) {
+            if (lst[i] - lst[i - 1] > 1) {
+                res.push([start, lst[i - 1]]);
+                start = lst[i];
+            }
+        }
+        res.push([start, lst[lst.length - 1]]);
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity:
+    * $O(1)$ time for initialization.
+    * $O(1)$ time for each $addNum()$ function call.
+    * $O(n \log n)$ time for each $getIntervals()$ function call.
+* Space complexity: $O(n)$
+
+---
+
+## 3. Ordered Map
+
+::tabs-start
+
+```python
+from sortedcontainers import SortedDict
+
+class SummaryRanges:
+    def __init__(self):
+        self.treeMap = SortedDict()
+
+    def addNum(self, value: int) -> None:
+        self.treeMap[value] = True
+
+    def getIntervals(self) -> List[List[int]]:
+        res = []
+        for n in self.treeMap:
+            if res and res[-1][1] + 1 == n:
+                res[-1][1] = n
+            else:
+                res.append([n, n])
+        return res
+```
+
+```java
+public class SummaryRanges {
+    private TreeMap<Integer, Boolean> treeMap;
+
+    public SummaryRanges() {
+        treeMap = new TreeMap<>();
+    }
+
+    public void addNum(int value) {
+        treeMap.put(value, true);
+    }
+
+    public List<int[]> getIntervals() {
+        List<int[]> res = new ArrayList<>();
+        for (int n : treeMap.keySet()) {
+            if (!res.isEmpty() && res.get(res.size() - 1)[1] + 1 == n) {
+                res.get(res.size() - 1)[1] = n;
+            } else {
+                res.add(new int[]{n, n});
+            }
+        }
+        return res;
+    }
+}
+```
+
+```cpp
+class SummaryRanges {
+private:
+    map<int, bool> treeMap;
+
+public:
+    SummaryRanges() {}
+
+    void addNum(int value) {
+        treeMap[value] = true;
+    }
+
+    vector<vector<int>> getIntervals() {
+        vector<vector<int>> res;
+        for (auto& [n, _] : treeMap) {
+            if (!res.empty() && res.back()[1] + 1 == n) {
+                res.back()[1] = n;
+            } else {
+                res.push_back({n, n});
+            }
+        }
+        return res;
+    }
+};
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity:
+    * $O(1)$ time for initialization.
+    * $O(\log n)$ time for each $addNum()$ function call.
+    * $O(n)$ time for each $getIntervals()$ function call.
+* Space complexity: $O(n)$
+
+---
+
+## 4. Ordered Set
+
+::tabs-start
+
+```python
+from sortedcontainers import SortedSet
+
+class SummaryRanges:
+    def __init__(self):
+        self.orderedSet = SortedSet()
+
+    def addNum(self, value: int) -> None:
+        self.orderedSet.add(value)
+
+    def getIntervals(self) -> List[List[int]]:
+        res = []
+        for n in self.orderedSet:
+            if res and res[-1][1] + 1 == n:
+                res[-1][1] = n
+            else:
+                res.append([n, n])
+        return res
+```
+
+```java
+public class SummaryRanges {
+    private TreeSet<Integer> orderedSet;
+
+    public SummaryRanges() {
+        orderedSet = new TreeSet<>();
+    }
+
+    public void addNum(int value) {
+        orderedSet.add(value);
+    }
+
+    public List<int[]> getIntervals() {
+        List<int[]> res = new ArrayList<>();
+        for (int n : orderedSet) {
+            if (!res.isEmpty() && res.get(res.size() - 1)[1] + 1 == n) {
+                res.get(res.size() - 1)[1] = n;
+            } else {
+                res.add(new int[]{n, n});
+            }
+        }
+        return res;
+    }
+}
+```
+
+```cpp
+class SummaryRanges {
+private:
+    set<int> orderedSet;
+
+public:
+    SummaryRanges() {}
+
+    void addNum(int value) {
+        orderedSet.insert(value);
+    }
+
+    vector<vector<int>> getIntervals() {
+        vector<vector<int>> res;
+        for (int n : orderedSet) {
+            if (!res.empty() && res.back()[1] + 1 == n) {
+                res.back()[1] = n;
+            } else {
+                res.push_back({n, n});
+            }
+        }
+        return res;
+    }
+};
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity:
+    * $O(1)$ time for initialization.
+    * $O(\log n)$ time for each $addNum()$ function call.
+    * $O(n)$ time for each $getIntervals()$ function call.
+* Space complexity: $O(n)$
\ No newline at end of file
diff --git a/articles/find-the-maximum-sum-of-node-values.md b/articles/find-the-maximum-sum-of-node-values.md
new file mode 100644
index 000000000..d48258892
--- /dev/null
+++ b/articles/find-the-maximum-sum-of-node-values.md
@@ -0,0 +1,637 @@
+## 1. Depth First Search
+
+::tabs-start
+
+```python
+class Solution:
+    def maximumValueSum(self, nums: List[int], k: int, edges: List[List[int]]) -> int:
+        adj = [[] for _ in range(len(nums))]
+        for u, v in edges:
+            adj[u].append(v)
+            adj[v].append(u)
+
+        def dfs(node, par):
+            res = [nums[node], nums[node] ^ k]
+            for child in adj[node]:
+                if child == par:
+                    continue
+
+                cur = dfs(child, node)
+                tmp = []
+                tmp.append(max(res[0] + cur[0], res[1] + cur[1]))
+                tmp.append(max(res[1] + cur[0], res[0] + cur[1]))
+                res = tmp
+
+            return res
+
+        return dfs(0, -1)[0]
+```
+
+```java
+public class Solution {
+    public long maximumValueSum(int[] nums, int k, int[][] edges) {
+        int n = nums.length;
+        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]);
+            adj[edge[1]].add(edge[0]);
+        }
+
+        return dfs(0, -1, nums, k, adj)[0];
+    }
+
+    private long[] dfs(int node, int parent, int[] nums, int k, List<Integer>[] adj) {
+        long[] res = { nums[node], nums[node] ^ k };
+        for (int child : adj[node]) {
+            if (child == parent) continue;
+            
+            long[] cur = dfs(child, node, nums, k, adj);
+            long[] tmp = new long[2];
+            tmp[0] = Math.max(res[0] + cur[0], res[1] + cur[1]);
+            tmp[1] = Math.max(res[1] + cur[0], res[0] + cur[1]);
+            res = tmp;
+        }
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+    vector<vector<int>> adj;
+
+public:
+    long long maximumValueSum(vector<int>& nums, int k, vector<vector<int>>& edges) {
+        int n = nums.size();
+        adj.resize(n);
+        for (const auto& edge : edges) {
+            adj[edge[0]].push_back(edge[1]);
+            adj[edge[1]].push_back(edge[0]);
+        }
+
+        return dfs(0, -1, nums, k)[0];
+    }
+
+private:
+    vector<long long> dfs(int node, int parent, vector<int>& nums, int k) {
+        vector<long long> res = { nums[node], nums[node] ^ k };
+        for (int child : adj[node]) {
+            if (child == parent) continue;
+
+            vector<long long> cur = dfs(child, node, nums, k);
+            vector<long long> tmp(2);
+            tmp[0] = max(res[0] + cur[0], res[1] + cur[1]);
+            tmp[1] = max(res[1] + cur[0], res[0] + cur[1]);
+            res = tmp;
+        }
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} nums
+     * @param {number} k
+     * @param {number[][]} edges
+     * @return {number}
+     */
+    maximumValueSum(nums, k, edges) {
+        const n = nums.length;
+        const adj = Array.from({ length: n }, () => []);
+
+        for (const [u, v] of edges) {
+            adj[u].push(v);
+            adj[v].push(u);
+        }
+
+        const dfs = (node, parent) => {
+            let res = [nums[node], nums[node] ^ k];
+
+            for (const child of adj[node]) {
+                if (child === parent) continue;
+
+                const cur = dfs(child, node);
+                const tmp = [];
+                tmp[0] = Math.max(res[0] + cur[0], res[1] + cur[1]);
+                tmp[1] = Math.max(res[1] + cur[0], res[0] + cur[1]);
+                res = tmp;
+            }
+
+            return res;
+        };
+
+        return dfs(0, -1)[0];
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(n)$
+
+---
+
+## 2. Dynamic Programming (Top-Down)
+
+::tabs-start
+
+```python
+class Solution:
+    def maximumValueSum(self, nums: List[int], k: int, edges: List[List[int]]) -> int:
+        dp = [[None] * 2 for _ in range(len(nums))] + [[0, float("-inf")]]
+
+        def dfs(i, xorCnt):
+            if dp[i][xorCnt] is not None:
+                return dp[i][xorCnt]
+
+            res = nums[i] + dfs(i + 1, xorCnt)
+            res = max(res, (nums[i] ^ k) + dfs(i + 1, xorCnt ^ 1))
+            dp[i][xorCnt] = res
+            return res
+
+        return dfs(0, 0)
+```
+
+```java
+public class Solution {
+    private long[][] dp;
+
+    public long maximumValueSum(int[] nums, int k, int[][] edges) {
+        int n = nums.length;
+        dp = new long[n + 1][2];
+        for (long[] row : dp) Arrays.fill(row, Long.MIN_VALUE);
+        dp[n][0] = 0;
+        dp[n][1] = Integer.MIN_VALUE;
+
+        return dfs(0, 0, nums, k);
+    }
+
+    private long dfs(int i, int xorCnt, int[] nums, int k) {
+        if (dp[i][xorCnt] != Long.MIN_VALUE) {
+            return dp[i][xorCnt];
+        }
+
+        long res = nums[i] + dfs(i + 1, xorCnt, nums, k);
+        res = Math.max(res, (nums[i] ^ k) + dfs(i + 1, xorCnt ^ 1, nums, k));
+
+        return dp[i][xorCnt] = res;
+    }
+}
+```
+
+```cpp
+class Solution {
+    vector<vector<long long>> dp;
+
+public:
+    long long maximumValueSum(vector<int>& nums, int k, vector<vector<int>>& edges) {
+        int n = nums.size();
+        dp.assign(n + 1, vector<long long>(2, LLONG_MIN));
+        dp[n][0] = 0;
+        dp[n][1] = INT_MIN;
+
+        return dfs(0, 0, nums, k);
+    }
+
+private:
+    long long dfs(int i, int xorCnt, vector<int>& nums, int k) {
+        if (dp[i][xorCnt] != LLONG_MIN) {
+            return dp[i][xorCnt];
+        }
+
+        long long res = nums[i] + dfs(i + 1, xorCnt, nums, k);
+        res = max(res, (nums[i] ^ k) + dfs(i + 1, xorCnt ^ 1, nums, k));
+        return dp[i][xorCnt] = res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} nums
+     * @param {number} k
+     * @param {number[][]} edges
+     * @return {number}
+     */
+    maximumValueSum(nums, k, edges) {
+        const n = nums.length;
+        const dp = Array.from({ length: n + 1 }, () => [null, null]);
+        dp[n][0] = 0;
+        dp[n][1] = -Infinity;
+
+        const dfs = (i, xorCnt) => {
+            if (dp[i][xorCnt] !== null) return dp[i][xorCnt];
+
+            let res = nums[i] + dfs(i + 1, xorCnt);
+            res = Math.max(res, (nums[i] ^ k) + dfs(i + 1, xorCnt ^ 1));
+            return dp[i][xorCnt] = res;
+        };
+
+        return dfs(0, 0);
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(n)$
+
+---
+
+## 3. Dynamic Programming (Bottom-Up)
+
+::tabs-start
+
+```python
+class Solution:
+    def maximumValueSum(self, nums: List[int], k: int, edges: List[List[int]]) -> int:
+        n = len(nums)
+        dp = [[0, 0] for _ in range(n + 1)]
+        dp[n][1] = float("-inf")
+
+        for i in range(n - 1, -1, -1):
+            dp[i][0] = max(nums[i] + dp[i + 1][0], (nums[i] ^ k) + dp[i + 1][1])
+            dp[i][1] = max(nums[i] + dp[i + 1][1], (nums[i] ^ k) + dp[i + 1][0])
+
+        return dp[0][0]
+```
+
+```java
+public class Solution {
+    public long maximumValueSum(int[] nums, int k, int[][] edges) {
+        int n = nums.length;
+        long[][] dp = new long[n + 1][2];
+        dp[n][1] = Integer.MIN_VALUE;
+
+        for (int i = n - 1; i >= 0; i--) {
+            dp[i][0] = Math.max(nums[i] + dp[i + 1][0], (nums[i] ^ k) + dp[i + 1][1]);
+            dp[i][1] = Math.max(nums[i] + dp[i + 1][1], (nums[i] ^ k) + dp[i + 1][0]);
+        }
+
+        return dp[0][0];
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    long long maximumValueSum(vector<int>& nums, int k, vector<vector<int>>& edges) {
+        int n = nums.size();
+        vector<vector<long long>> dp(n + 1, vector<long long>(2));
+        dp[n][1] = INT_MIN;
+
+        for (int i = n - 1; i >= 0; i--) {
+            dp[i][0] = max(nums[i] + dp[i + 1][0], (nums[i] ^ k) + dp[i + 1][1]);
+            dp[i][1] = max(nums[i] + dp[i + 1][1], (nums[i] ^ k) + dp[i + 1][0]);
+        }
+
+        return dp[0][0];
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} nums
+     * @param {number} k
+     * @param {number[][]} edges
+     * @return {number}
+     */
+    maximumValueSum(nums, k, edges) {
+        const n = nums.length;
+        const dp = Array.from({ length: n + 1 }, () => [0, 0]);
+        dp[n][1] = -Infinity;
+
+        for (let i = n - 1; i >= 0; i--) {
+            dp[i][0] = Math.max(nums[i] + dp[i + 1][0], (nums[i] ^ k) + dp[i + 1][1]);
+            dp[i][1] = Math.max(nums[i] + dp[i + 1][1], (nums[i] ^ k) + dp[i + 1][0]);
+        }
+
+        return dp[0][0];
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(n)$
+
+---
+
+## 4. Dynamic Programming (Space Optimized)
+
+::tabs-start
+
+```python
+class Solution:
+    def maximumValueSum(self, nums: List[int], k: int, edges: List[List[int]]) -> int:
+        dp = [0, float("-inf")]
+
+        for i in range(len(nums) - 1, -1, -1):
+            next_dp = [0, 0]
+            next_dp[0] = max(nums[i] + dp[0], (nums[i] ^ k) + dp[1])
+            next_dp[1] = max(nums[i] + dp[1], (nums[i] ^ k) + dp[0])
+            dp = next_dp
+
+        return dp[0]
+```
+
+```java
+public class Solution {
+    public long maximumValueSum(int[] nums, int k, int[][] edges) {
+        int n = nums.length;
+        long[] dp = {0, Long.MIN_VALUE};
+
+        for (int i = n - 1; i >= 0; i--) {
+            long[] nextDp = new long[2];
+            nextDp[0] = Math.max(nums[i] + dp[0], (nums[i] ^ k) + dp[1]);
+            nextDp[1] = Math.max(nums[i] + dp[1], (nums[i] ^ k) + dp[0]);
+            dp = nextDp;
+        }
+
+        return dp[0];
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    long long maximumValueSum(vector<int>& nums, int k, vector<vector<int>>& edges) {
+        int n = nums.size();
+        vector<long long> dp = {0, LLONG_MIN};
+
+        for (int i = n - 1; i >= 0; i--) {
+            vector<long long> nextDp(2);
+            nextDp[0] = max(nums[i] + dp[0], (nums[i] ^ k) + dp[1]);
+            nextDp[1] = max(nums[i] + dp[1], (nums[i] ^ k) + dp[0]);
+            dp = nextDp;
+        }
+
+        return dp[0];
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} nums
+     * @param {number} k
+     * @param {number[][]} edges
+     * @return {number}
+     */
+    maximumValueSum(nums, k, edges) {
+        const n = nums.length;
+        let dp = [0, -Infinity];
+
+        for (let i = n - 1; i >= 0; i--) {
+            let nextDp = [0, 0];
+            nextDp[0] = Math.max(nums[i] + dp[0], (nums[i] ^ k) + dp[1]);
+            nextDp[1] = Math.max(nums[i] + dp[1], (nums[i] ^ k) + dp[0]);
+            dp = nextDp;
+        }
+
+        return dp[0];
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(1)$ extra space.
+
+---
+
+## 5. Greedy
+
+::tabs-start
+
+```python
+class Solution:
+    def maximumValueSum(self, nums: List[int], k: int, edges: List[List[int]]) -> int:
+        delta = [(num ^ k) - num for num in nums]
+        delta.sort(reverse=True)
+        res = sum(nums)
+
+        for i in range(0, len(nums), 2):
+            if i == len(nums) - 1:
+                break
+            path_delta = delta[i] + delta[i + 1]
+            if path_delta <= 0:
+                break
+            res += path_delta
+
+        return res
+```
+
+```java
+public class Solution {
+    public long maximumValueSum(int[] nums, int k, int[][] edges) {
+        int n = nums.length;
+        int[] delta = new int[n];
+        long res = 0;
+        for (int i = 0; i < n; i++) {
+            res += nums[i];
+            delta[i] = (nums[i] ^ k) - nums[i];
+        }
+
+        Arrays.sort(delta);
+        for (int i = n - 1; i > 0; i -= 2) {
+            int pathDelta = delta[i] + delta[i - 1];
+            if (pathDelta <= 0) {
+                break;
+            }
+            res += pathDelta;
+        }
+
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    long long maximumValueSum(vector<int>& nums, int k, vector<vector<int>>& edges) {
+        int n = nums.size();
+        vector<int> delta(n);
+        long long res = 0;
+        for (int i = 0; i < n; i++) {
+            res += nums[i];
+            delta[i] = (nums[i] ^ k) - nums[i];
+        }
+
+        sort(delta.rbegin(), delta.rend());
+
+        for (int i = 0; i + 1 < n; i += 2) {
+            int pathDelta = delta[i] + delta[i + 1];
+            if (pathDelta <= 0) {
+                break;
+            }
+            res += pathDelta;
+        }
+
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} nums
+     * @param {number} k
+     * @param {number[][]} edges
+     * @return {number}
+     */
+    maximumValueSum(nums, k, edges) {
+        const n = nums.length;
+        let res = 0;
+        let delta = [];
+        for (let i = 0; i < n; i++) {
+            res += nums[i];
+            delta.push((nums[i] ^ k) - nums[i]);
+        }
+
+        delta.sort((a, b) => b - a);
+        for (let i = 0; i + 1 < n; i += 2) {
+            let pathDelta = delta[i] + delta[i + 1];
+            if (pathDelta <= 0) {
+                break;
+            }
+            res += pathDelta;
+        }
+
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n \log n)$
+* Space complexity: $O(n)$
+
+---
+
+## 6. Greedy (Optimal)
+
+::tabs-start
+
+```python
+class Solution:
+    def maximumValueSum(self, nums: List[int], k: int, edges: List[List[int]]) -> int:
+        xorCnt = res = 0
+        minDiff = 1 << 30
+
+        for num in nums:
+            xorNum = num ^ k
+            if xorNum > num:
+                res += xorNum
+                xorCnt ^= 1
+            else:
+                res += num
+            minDiff = min(minDiff, abs(xorNum - num))
+
+        return res - xorCnt * minDiff
+```
+
+```java
+public class Solution {
+    public long maximumValueSum(int[] nums, int k, int[][] edges) {
+        int xorCnt = 0, minDiff = 1 << 30;
+        long res = 0;
+
+        for (int num : nums) {
+            int xorNum = num ^ k;
+            if (xorNum > num) {
+                res += xorNum;
+                xorCnt ^= 1;
+            } else {
+                res += num;
+            }
+            minDiff = Math.min(minDiff, Math.abs(xorNum - num));
+        }
+
+        return res - xorCnt * minDiff;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    long long maximumValueSum(vector<int>& nums, int k, vector<vector<int>>& edges) {
+        int xorCnt = 0, minDiff = 1 << 30;
+        long long res = 0;
+
+        for (int& num : nums) {
+            int xorNum = num ^ k;
+            if (xorNum > num) {
+                res += xorNum;
+                xorCnt ^= 1;
+            } else {
+                res += num;
+            }
+            minDiff = min(minDiff, abs(xorNum - num));
+        }
+
+        return res - (xorCnt * minDiff);
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} nums
+     * @param {number} k
+     * @param {number[][]} edges
+     * @return {number}
+     */
+    maximumValueSum(nums, k, edges) {
+        let xorCnt = 0, res = 0, minDiff = 1 << 30;
+
+        for (let num of nums) {
+            let xorNum = num ^ k;
+            if (xorNum > num) {
+                res += xorNum;
+                xorCnt ^= 1;
+            } else {
+                res += num;
+            }
+            minDiff = Math.min(minDiff, Math.abs(xorNum - num));
+        }
+
+        return res - (xorCnt * minDiff);
+    }
+}
+```
+
+::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/maximum-score-of-a-good-subarray.md b/articles/maximum-score-of-a-good-subarray.md
new file mode 100644
index 000000000..f8b6fbdc0
--- /dev/null
+++ b/articles/maximum-score-of-a-good-subarray.md
@@ -0,0 +1,729 @@
+## 1. Brute Force
+
+::tabs-start
+
+```python
+class Solution:
+    def maximumScore(self, nums: List[int], k: int) -> int:
+        n, res = len(nums), 0
+
+        for i in range(k + 1):
+            minEle = nums[i]
+            for j in range(i, n):
+                minEle = min(minEle, nums[j])
+                if j >= k:
+                    res = max(res, minEle * (j - i + 1))
+
+        return res
+```
+
+```java
+public class Solution {
+    public int maximumScore(int[] nums, int k) {
+        int n = nums.length, res = 0;
+
+        for (int i = 0; i <= k; i++) {
+            int minEle = nums[i];
+            for (int j = i; j < n; j++) {
+                minEle = Math.min(minEle, nums[j]);
+                if (j >= k) {
+                    res = Math.max(res, minEle * (j - i + 1));
+                }
+            }
+        }
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int maximumScore(vector<int>& nums, int k) {
+        int n = nums.size(), res = 0;
+
+        for (int i = 0; i <= k; i++) {
+            int minEle = nums[i];
+            for (int j = i; j < n; j++) {
+                minEle = min(minEle, nums[j]);
+                if (j >= k) {
+                    res = max(res, minEle * (j - i + 1));
+                }
+            }
+        }
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} nums
+     * @param {number} k
+     * @return {number}
+     */
+    maximumScore(nums, k) {
+        let n = nums.length, res = 0;
+
+        for (let i = 0; i <= k; i++) {
+            let minEle = nums[i];
+            for (let j = i; j < n; j++) {
+                minEle = Math.min(minEle, nums[j]);
+                if (j >= k) {
+                    res = Math.max(res, minEle * (j - i + 1));
+                }
+            }
+        }
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n ^ 2)$
+* Space complexity: $O(1)$ extra space.
+
+---
+
+## 2. Binary Search
+
+::tabs-start
+
+```python
+class Solution:
+    def maximumScore(self, nums: List[int], k: int) -> int:
+        n, res = len(nums), 0
+        arr = nums[:]
+
+        for i in range(k - 1, -1, -1):
+            arr[i] = min(arr[i], arr[i + 1])
+        for i in range(k + 1, n):
+            arr[i] = min(arr[i], arr[i - 1])
+
+        left_arr = arr[:k+1]
+        right_arr = arr[k:]
+
+        def find_right(target):
+            lo, hi = 0, len(right_arr) - 1
+            pos = 0
+            while lo <= hi:
+                mid = (lo + hi) // 2
+                if right_arr[mid] >= target:
+                    pos = mid
+                    lo = mid + 1
+                else:
+                    hi = mid - 1
+            return pos
+
+        for minVal in set(arr):
+            l = bisect_left(left_arr, minVal)
+            r = find_right(minVal)
+            res = max(res, minVal * (k - l + 1 + r))
+        return res
+```
+
+```java
+public class Solution {
+    public int maximumScore(int[] nums, int k) {
+        int n = nums.length, res = 0;
+        int[] arr = Arrays.copyOf(nums, n);
+        Set<Integer> candidates = new HashSet<>();
+        candidates.add(arr[k]);
+
+        for (int i = k - 1; i >= 0; i--) {
+            arr[i] = Math.min(arr[i], arr[i + 1]);
+            candidates.add(arr[i]);
+        }
+        for (int i = k + 1; i < n; i++) {
+            arr[i] = Math.min(arr[i], arr[i - 1]);
+            candidates.add(arr[i]);
+        }
+
+        int[] leftArr = Arrays.copyOfRange(arr, 0, k + 1);
+        int[] rightArr = Arrays.copyOfRange(arr, k, n);
+
+        for (int minVal : candidates) {
+            int l = findLeft(leftArr, minVal);
+            int r = findRight(rightArr, minVal);
+            res = Math.max(res, minVal * (k - l + 1 + r));
+        }
+        return res;
+    }
+
+    private int findLeft(int[] arr, int target) {
+        int lo = 0, hi = arr.length - 1;
+        while (lo <= hi) {
+            int mid = (lo + hi) / 2;
+            if (arr[mid] < target) {
+                lo = mid + 1;
+            } else {
+                hi = mid - 1;
+            }
+        }
+        return lo;
+    }
+
+    private int findRight(int[] arr, int target) {
+        int lo = 0, hi = arr.length - 1, pos = 0;
+        while (lo <= hi) {
+            int mid = (lo + hi) / 2;
+            if (arr[mid] >= target) {
+                pos = mid;
+                lo = mid + 1;
+            } else {
+                hi = mid - 1;
+            }
+        }
+        return pos;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int maximumScore(vector<int>& nums, int k) {
+        int n = nums.size(), res = 0;
+        vector<int> arr = nums;
+
+        for (int i = k - 1; i >= 0; i--) {
+            arr[i] = min(arr[i], arr[i + 1]);
+        }
+        for (int i = k + 1; i < n; i++) {
+            arr[i] = min(arr[i], arr[i - 1]);
+        }
+
+        vector<int> leftArr(arr.begin(), arr.begin() + k + 1);
+        vector<int> rightArr(arr.begin() + k, arr.end());
+
+        set<int> candidates(arr.begin(), arr.end());
+        for (int minVal : candidates) {
+            int l = lower_bound(leftArr.begin(), leftArr.end(), minVal) - leftArr.begin();
+            int r = findRight(rightArr, minVal);
+            res = max(res, minVal * (k - l + 1 + r));
+        }
+        return res;
+    }
+
+private:
+    int findRight(vector<int>& arr, int target) {
+        int lo = 0, hi = arr.size() - 1, pos = 0;
+        while (lo <= hi) {
+            int mid = (lo + hi) / 2;
+            if (arr[mid] >= target) {
+                pos = mid;
+                lo = mid + 1;
+            } else {
+                hi = mid - 1;
+            }
+        }
+        return pos;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} nums
+     * @param {number} k
+     * @return {number}
+     */
+    maximumScore(nums, k) {
+        let n = nums.length, res = 0;
+        let arr = [...nums];
+
+        for (let i = k - 1; i >= 0; i--) {
+            arr[i] = Math.min(arr[i], arr[i + 1]);
+        }
+        for (let i = k + 1; i < n; i++) {
+            arr[i] = Math.min(arr[i], arr[i - 1]);
+        }
+
+        let leftArr = arr.slice(0, k + 1);
+        let rightArr = arr.slice(k);
+
+        const findLeft = (target) => {
+            let lo = 0, hi = leftArr.length - 1;
+            while (lo <= hi) {
+                let mid = Math.floor((lo + hi) / 2);
+                if (leftArr[mid] < target) {
+                    lo = mid + 1;
+                } else {
+                    hi = mid - 1;
+                }
+            }
+            return lo;
+        };
+
+        const findRight = (target) => {
+            let lo = 0, hi = rightArr.length - 1, pos = 0;
+            while (lo <= hi) {
+                let mid = Math.floor((lo + hi) / 2);
+                if (rightArr[mid] >= target) {
+                    pos = mid;
+                    lo = mid + 1;
+                } else {
+                    hi = mid - 1;
+                }
+            }
+            return pos;
+        };
+
+        let candidates = [...new Set(arr)];
+        for (let minVal of candidates) {
+            let l = findLeft(minVal);
+            let r = findRight(minVal);
+            res = Math.max(res, minVal * (k - l + 1 + r));
+        }
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n \log n)$
+* Space complexity: $O(n)$
+
+---
+
+## 3. Binary Search (Overwriting the Input)
+
+::tabs-start
+
+```python
+class Solution:
+    def maximumScore(self, nums: List[int], k: int) -> int:
+        n, res = len(nums), 0
+
+        for i in range(k - 1, -1, -1):
+            nums[i] = min(nums[i], nums[i + 1])
+        for i in range(k + 1, n):
+            nums[i] = min(nums[i], nums[i - 1])
+
+        def find_left(target):
+            lo, hi = 0, k
+            while lo <= hi:
+                mid = (lo + hi) // 2
+                if nums[mid] < target:
+                    lo = mid + 1
+                else:
+                    hi = mid - 1
+            return lo
+
+        def find_right(target):
+            lo, hi = k, n - 1
+            while lo <= hi:
+                mid = (lo + hi) // 2
+                if nums[mid] >= target:
+                    lo = mid + 1
+                else:
+                    hi = mid - 1
+            return hi
+
+        for minVal in set(nums):
+            i = find_left(minVal)
+            j = find_right(minVal)
+            res = max(res, minVal * (j - i + 1))
+        return res
+```
+
+```java
+public class Solution {
+    public int maximumScore(int[] nums, int k) {
+        int n = nums.length, res = 0;
+
+        for (int i = k - 1; i >= 0; i--) {
+            nums[i] = Math.min(nums[i], nums[i + 1]);
+        }
+        for (int i = k + 1; i < n; i++) {
+            nums[i] = Math.min(nums[i], nums[i - 1]);
+        }
+
+        Set<Integer> candidates = new TreeSet<>();
+        for (int num : nums) {
+            candidates.add(num);
+        }
+
+        for (int minVal : candidates) {
+            int i = findLeft(nums, k, minVal);
+            int j = findRight(nums, k, minVal);
+            res = Math.max(res, minVal * (j - i + 1));
+        }
+        return res;
+    }
+
+    int findLeft(int[] nums, int k, int target) {
+        int lo = 0, hi = k;
+        while (lo <= hi) {
+            int mid = (lo + hi) / 2;
+            if (nums[mid] < target) {
+                lo = mid + 1;
+            } else {
+                hi = mid - 1;
+            }
+        }
+        return lo;
+    }
+
+    int findRight(int[] nums, int k, int target) {
+        int lo = k, hi = nums.length - 1;
+        while (lo <= hi) {
+            int mid = (lo + hi) / 2;
+            if (nums[mid] >= target) {
+                lo = mid + 1;
+            } else {
+                hi = mid - 1;
+            }
+        }
+        return hi;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int maximumScore(vector<int>& nums, int k) {
+        int n = nums.size(), res = 0;
+
+        for (int i = k - 1; i >= 0; i--) {
+            nums[i] = min(nums[i], nums[i + 1]);
+        }
+        for (int i = k + 1; i < n; i++) {
+            nums[i] = min(nums[i], nums[i - 1]);
+        }
+
+        auto findLeft = [&](int target) {
+            int lo = 0, hi = k;
+            while (lo <= hi) {
+                int mid = (lo + hi) / 2;
+                if (nums[mid] < target) {
+                    lo = mid + 1;
+                } else {
+                    hi = mid - 1;
+                }
+            }
+            return lo;
+        };
+
+        auto findRight = [&](int target) {
+            int lo = k, hi = n - 1;
+            while (lo <= hi) {
+                int mid = (lo + hi) / 2;
+                if (nums[mid] >= target) {
+                    lo = mid + 1;
+                } else {
+                    hi = mid - 1;
+                }
+            }
+            return hi;
+        };
+
+        set<int> candidates(nums.begin(), nums.end());
+        for (int minVal : candidates) {
+            int i = findLeft(minVal);
+            int j = findRight(minVal);
+            res = max(res, minVal * (j - i + 1));
+        }
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} nums
+     * @param {number} k
+     * @return {number}
+     */
+    maximumScore(nums, k) {
+        let n = nums.length, res = 0;
+
+        for (let i = k - 1; i >= 0; i--) {
+            nums[i] = Math.min(nums[i], nums[i + 1]);
+        }
+        for (let i = k + 1; i < n; i++) {
+            nums[i] = Math.min(nums[i], nums[i - 1]);
+        }
+
+        const findLeft = (target) => {
+            let lo = 0, hi = k;
+            while (lo <= hi) {
+                let mid = Math.floor((lo + hi) / 2);
+                if (nums[mid] < target) {
+                    lo = mid + 1;
+                } else {
+                    hi = mid - 1;
+                }
+            }
+            return lo;
+        };
+
+        const findRight = (target) => {
+            let lo = k, hi = n - 1;
+            while (lo <= hi) {
+                let mid = Math.floor((lo + hi) / 2);
+                if (nums[mid] >= target) {
+                    lo = mid + 1;
+                } else {
+                    hi = mid - 1;
+                }
+            }
+            return hi;
+        };
+
+        let candidates = new Set(nums);
+        for (let minVal of candidates) {
+            let i = findLeft(minVal);
+            let j = findRight(minVal);
+            res = Math.max(res, minVal * (j - i + 1));
+        }
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n \log n)$
+* Space complexity: $O(n)$
+
+---
+
+## 4. Monotonic Stack
+
+::tabs-start
+
+```python
+class Solution:
+    def maximumScore(self, nums: List[int], k: int) -> int:
+        n, res = len(nums), 0
+        stack = []
+
+        for i in range(n + 1):
+            while stack and (i == n or nums[stack[-1]] >= nums[i]):
+                mini = nums[stack.pop()]
+                j = stack[-1] if stack else -1
+                if j < k < i:
+                    res = max(res, mini * (i - j - 1))
+            stack.append(i)
+
+        return res
+```
+
+```java
+public class Solution {
+    public int maximumScore(int[] nums, int k) {
+        int n = nums.length, res = 0;
+        Stack<Integer> stack = new Stack<>();
+
+        for (int i = 0; i <= n; i++) {
+            while (!stack.isEmpty() && (i == n || nums[stack.peek()] >= nums[i])) {
+                int mini = nums[stack.pop()];
+                int j = stack.isEmpty() ? -1 : stack.peek();
+                if (j < k && k < i) {
+                    res = Math.max(res, mini * (i - j - 1));
+                }
+            }
+            stack.push(i);
+        }
+
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int maximumScore(vector<int>& nums, int k) {
+        int n = nums.size(), res = 0;
+        stack<int> stk;
+
+        for (int i = 0; i <= n; i++) {
+            while (!stk.empty() && (i == n || nums[stk.top()] >= nums[i])) {
+                int mini = nums[stk.top()];
+                stk.pop();
+                int j = stk.empty() ? -1 : stk.top();
+                if (j < k && k < i) {
+                    res = max(res, mini * (i - j - 1));
+                }
+            }
+            stk.push(i);
+        }
+
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} nums
+     * @param {number} k
+     * @return {number}
+     */
+    maximumScore(nums, k) {
+        let n = nums.length, res = 0;
+        let stack = [];
+
+        for (let i = 0; i <= n; i++) {
+            while (stack.length && (i === n || nums[stack[stack.length - 1]] >= nums[i])) {
+                let mini = nums[stack.pop()];
+                let j = stack.length ? stack[stack.length - 1] : -1;
+                if (j < k && k < i) {
+                    res = Math.max(res, mini * (i - j - 1));
+                }
+            }
+            stack.push(i);
+        }
+
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(n)$
+
+---
+
+## 5. Greedy + Two Pointers
+
+::tabs-start
+
+```python
+class Solution:
+    def maximumScore(self, nums: List[int], k: int) -> int:
+        l = r = k
+        res = nums[k]
+        cur_min = nums[k]
+
+        while l > 0 or r < len(nums) - 1:
+            left = nums[l - 1] if l > 0 else 0
+            right = nums[r + 1] if r < len(nums) - 1 else 0
+
+            if left > right:
+                l -= 1
+                cur_min = min(cur_min, left)
+            else:
+                r += 1
+                cur_min = min(cur_min, right)
+
+            res = max(res, cur_min * (r - l + 1))
+
+        return res
+```
+
+```java
+public class Solution {
+    public int maximumScore(int[] nums, int k) {
+        int l = k, r = k;
+        int res = nums[k];
+        int curMin = nums[k];
+        int n = nums.length;
+
+        while (l > 0 || r < n - 1) {
+            int left = (l > 0) ? nums[l - 1] : 0;
+            int right = (r < n - 1) ? nums[r + 1] : 0;
+
+            if (left > right) {
+                l--;
+                curMin = Math.min(curMin, left);
+            } else {
+                r++;
+                curMin = Math.min(curMin, right);
+            }
+
+            res = Math.max(res, curMin * (r - l + 1));
+        }
+
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int maximumScore(vector<int>& nums, int k) {
+        int l = k, r = k;
+        int res = nums[k];
+        int curMin = nums[k];
+        int n = nums.size();
+
+        while (l > 0 || r < n - 1) {
+            int left = (l > 0) ? nums[l - 1] : 0;
+            int right = (r < n - 1) ? nums[r + 1] : 0;
+
+            if (left > right) {
+                l--;
+                curMin = min(curMin, left);
+            } else {
+                r++;
+                curMin = min(curMin, right);
+            }
+
+            res = max(res, curMin * (r - l + 1));
+        }
+
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} nums
+     * @param {number} k
+     * @return {number}
+     */
+    maximumScore(nums, k) {
+        let l = k, r = k;
+        let res = nums[k];
+        let curMin = nums[k];
+        let n = nums.length;
+
+        while (l > 0 || r < n - 1) {
+            let left = (l > 0) ? nums[l - 1] : 0;
+            let right = (r < n - 1) ? nums[r + 1] : 0;
+
+            if (left > right) {
+                l--;
+                curMin = Math.min(curMin, left);
+            } else {
+                r++;
+                curMin = Math.min(curMin, right);
+            }
+
+            res = Math.max(res, curMin * (r - l + 1));
+        }
+
+        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/splitting-a-string-into-descending-consecutive-values.md b/articles/splitting-a-string-into-descending-consecutive-values.md
new file mode 100644
index 000000000..b736eda11
--- /dev/null
+++ b/articles/splitting-a-string-into-descending-consecutive-values.md
@@ -0,0 +1,570 @@
+## 1. Backtracking
+
+::tabs-start
+
+```python
+class Solution:
+    def splitString(self, s: str) -> bool:
+        n = len(s)
+
+        def isValid(splits):
+            for i in range(1, len(splits)):
+                if splits[i] != splits[i - 1] - 1:
+                    return False
+            return len(splits) > 1
+
+        def dfs(i, splits):
+            if i == n:
+                return isValid(splits)
+            num = 0
+            for j in range(i, n):
+                num = num * 10 + int(s[j])
+                splits.append(num)
+                if dfs(j + 1, splits):
+                    return True
+                splits.pop()
+            return False
+
+        return dfs(0, [])
+```
+
+```java
+public class Solution {
+    public boolean splitString(String s) {
+        return dfs(s, 0, new ArrayList<>());
+    }
+
+    private boolean isValid(List<Long> splits) {
+        for (int i = 1; i < splits.size(); i++) {
+            if (splits.get(i) != splits.get(i - 1) - 1) {
+                return false;
+            }
+        }
+        return splits.size() > 1;
+    }
+
+    private boolean dfs(String s, int i, List<Long> splits) {
+        if (i == s.length()) {
+            return isValid(splits);
+        }
+        long num = 0;
+        for (int j = i; j < s.length(); j++) {
+            num = num * 10 + (s.charAt(j) - '0');
+            splits.add(num);
+            if (dfs(s, j + 1, splits)) {
+                return true;
+            }
+            splits.remove(splits.size() - 1);
+        }
+        return false;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    bool splitString(string s) {
+        vector<long long> splits;
+        return dfs(s, 0, splits);
+    }
+
+private:
+    bool isValid(vector<long long>& splits) {
+        for (int i = 1; i < splits.size(); i++) {
+            if (splits[i] != splits[i - 1] - 1) {
+                return false;
+            }
+        }
+        return splits.size() > 1;
+    }
+
+    bool dfs(string& s, int i, vector<long long>& splits) {
+        if (i == s.size()) {
+            return isValid(splits);
+        }
+        unsigned long long num = 0;
+        for (int j = i; j < s.size(); j++) {
+            num = num * 10 + (s[j] - '0');
+            splits.push_back(num);
+            if (dfs(s, j + 1, splits)) {
+                return true;
+            }
+            splits.pop_back();
+        }
+        return false;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {string} s
+     * @return {boolean}
+     */
+    splitString(s) {
+        const n = s.length;
+
+        const isValid = (splits) => {
+            for (let i = 1; i < splits.length; i++) {
+                if (splits[i] !== splits[i - 1] - 1) {
+                    return false;
+                }
+            }
+            return splits.length > 1;
+        };
+
+        const dfs = (i, splits) => {
+            if (i === n) {
+                return isValid(splits);
+            }
+            let num = 0;
+            for (let j = i; j < n; j++) {
+                num = num * 10 + Number(s[j]);
+                splits.push(num);
+                if (dfs(j + 1, splits)) {
+                    return true;
+                }
+                splits.pop();
+            }
+            return false;
+        };
+
+        return dfs(0, []);
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n ^ n)$
+* Space complexity: $O(n)$
+
+---
+
+## 2. Recursion - I
+
+::tabs-start
+
+```python
+class Solution:
+    def splitString(self, s: str) -> bool:
+        def dfs(index, prev):
+            if index == len(s):
+                return True
+            num = 0
+            for j in range(index, len(s)):
+                num = num * 10 + int(s[j])
+                if num + 1 == prev and dfs(j + 1, num):
+                    return True
+            return False
+
+        val = 0
+        for i in range(len(s) - 1):
+            val = val * 10 + int(s[i])
+            if dfs(i + 1, val):
+                return True
+
+        return False
+```
+
+```java
+public class Solution {
+    public boolean splitString(String s) {
+        int n = s.length();
+        long val = 0;
+        for (int i = 0; i < n - 1; i++) {
+            val = val * 10 + (s.charAt(i) - '0');
+            if (dfs(s, i + 1, val)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean dfs(String s, int index, long prev) {
+        if (index == s.length()) {
+            return true;
+        }
+        long num = 0;
+        for (int j = index; j < s.length(); j++) {
+            num = num * 10 + (s.charAt(j) - '0');
+            if (num + 1 == prev && dfs(s, j + 1, num)) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    bool splitString(string s) {
+        int n = s.size();
+        unsigned long long val = 0;
+        for (int i = 0; i < n - 1; i++) {
+            val = val * 10 + (s[i] - '0');
+            if (dfs(s, i + 1, val)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+private:
+    bool dfs(string& s, int index, long long prev) {
+        if (index == s.size()) {
+            return true;
+        }
+        unsigned long long num = 0;
+        for (int j = index; j < s.size(); j++) {
+            num = num * 10 + (s[j] - '0');
+            if (num + 1 == prev && dfs(s, j + 1, num)) {
+                return true;
+            }
+        }
+        return false;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {string} s
+     * @return {boolean}
+     */
+    splitString(s) {
+        const n = s.length;
+
+        const dfs = (index, prev) => {
+            if (index === n) {
+                return true;
+            }
+            let num = 0;
+            for (let j = index; j < n; j++) {
+                num = num * 10 + Number(s[j]);
+                if (num + 1 === prev && dfs(j + 1, num)) {
+                    return true;
+                }
+            }
+            return false;
+        };
+
+        let val = 0;
+        for (let i = 0; i < n - 1; i++) {
+            val = val * 10 + Number(s[i]);
+            if (dfs(i + 1, val)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n ^ 2)$
+* Space complexity: $O(n)$ for recursion stack.
+
+---
+
+## 3. Recursion - II
+
+::tabs-start
+
+```python
+class Solution:
+    def splitString(self, s: str) -> bool:
+        def dfs(index, prev):
+            if index == len(s):
+                return True
+            num = 0
+            for j in range(index, len(s)):
+                num = num * 10 + int(s[j])
+                if num + 1 == prev and dfs(j + 1, num):
+                    return True
+                if num >= prev:
+                    break
+            return False
+
+        val = 0
+        for i in range(len(s) - 1):
+            val = val * 10 + int(s[i])
+            if dfs(i + 1, val):
+                return True
+
+        return False
+```
+
+```java
+public class Solution {
+    public boolean splitString(String s) {
+        int n = s.length();
+        long val = 0;
+        for (int i = 0; i < n - 1; i++) {
+            val = val * 10 + (s.charAt(i) - '0');
+            if (dfs(s, i + 1, val)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean dfs(String s, int index, long prev) {
+        if (index == s.length()) {
+            return true;
+        }
+        long num = 0;
+        for (int j = index; j < s.length(); j++) {
+            num = num * 10 + (s.charAt(j) - '0');
+            if (num + 1 == prev && dfs(s, j + 1, num)) {
+                return true;
+            }
+            if (num >= prev) {
+                break;
+            }
+        }
+        return false;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    bool splitString(string s) {
+        int n = s.size();
+        unsigned long long val = 0;
+        for (int i = 0; i < n - 1; i++) {
+            val = val * 10 + (s[i] - '0');
+            if (dfs(s, i + 1, val)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+private:
+    bool dfs(string& s, int index, long long prev) {
+        if (index == s.size()) {
+            return true;
+        }
+        unsigned long long num = 0;
+        for (int j = index; j < s.size(); j++) {
+            num = num * 10 + (s[j] - '0');
+            if (num + 1 == prev && dfs(s, j + 1, num)) {
+                return true;
+            }
+            if (num >= prev) {
+                break;
+            }
+        }
+        return false;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {string} s
+     * @return {boolean}
+     */
+    splitString(s) {
+        const n = s.length;
+
+        const dfs = (index, prev) => {
+            if (index === n) {
+                return true;
+            }
+            let num = 0;
+            for (let j = index; j < n; j++) {
+                num = num * 10 + Number(s[j]);
+                if (num + 1 === prev && dfs(j + 1, num)) {
+                    return true;
+                }
+                if (num >= prev) {
+                    break;
+                }
+            }
+            return false;
+        };
+
+        let val = 0;
+        for (let i = 0; i < n - 1; i++) {
+            val = val * 10 + Number(s[i]);
+            if (dfs(i + 1, val)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n ^ 2)$
+* Space complexity: $O(n)$ for recursion stack.
+
+---
+
+## 4. Stack
+
+::tabs-start
+
+```python
+class Solution:
+    def splitString(self, s: str) -> bool:
+        n = len(s)
+        stack = []
+        val = 0
+
+        for i in range(n - 1):
+            val = val * 10 + int(s[i])
+            stack.append((i + 1, val))
+
+            while stack:
+                index, prev = stack.pop()
+                num = 0
+                for j in range(index, n):
+                    num = num * 10 + int(s[j])
+                    if num + 1 == prev:
+                        if j + 1 == n:
+                            return True
+                        stack.append((j + 1, num))
+                    elif num >= prev:
+                        break
+
+        return False
+```
+
+```java
+public class Solution {
+    public boolean splitString(String s) {
+        int n = s.length();
+        Stack<long[]> stack = new Stack<>();
+        long val = 0;
+
+        for (int i = 0; i < n - 1; i++) {
+            val = val * 10 + (s.charAt(i) - '0');
+            stack.push(new long[]{i + 1, val});
+
+            while (!stack.isEmpty()) {
+                long[] top = stack.pop();
+                int index = (int) top[0];
+                long prev = top[1];
+                long num = 0;
+
+                for (int j = index; j < n; j++) {
+                    num = num * 10 + (s.charAt(j) - '0');
+                    if (num + 1 == prev) {
+                        if (j + 1 == n) {
+                            return true;
+                        }
+                        stack.push(new long[]{j + 1, num});
+                    } else if (num >= prev) {
+                        break;
+                    }
+                }
+            }
+        }
+
+        return false;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    bool splitString(string s) {
+        int n = s.size();
+        stack<pair<int, long long>> stack;
+        unsigned long long val = 0;
+
+        for (int i = 0; i < n - 1; i++) {
+            val = val * 10 + (s[i] - '0');
+            stack.push({i + 1, val});
+
+            while (!stack.empty()) {
+                auto [index, prev] = stack.top();
+                stack.pop();
+                unsigned long long num = 0;
+
+                for (int j = index; j < n; j++) {
+                    num = num * 10 + (s[j] - '0');
+                    if (num + 1 == prev) {
+                        if (j + 1 == n) {
+                            return true;
+                        }
+                        stack.push({j + 1, num});
+                    } else if (num >= prev) {
+                        break;
+                    }
+                }
+            }
+        }
+
+        return false;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {string} s
+     * @return {boolean}
+     */
+    splitString(s) {
+        const n = s.length;
+        let stack = [];
+        let val = 0;
+
+        for (let i = 0; i < n - 1; i++) {
+            val = val * 10 + Number(s[i]);
+            stack.push([i + 1, val]);
+
+            while (stack.length) {
+                let [index, prev] = stack.pop();
+                let num = 0;
+
+                for (let j = index; j < n; j++) {
+                    num = num * 10 + Number(s[j]);
+                    if (num + 1 === prev) {
+                        if (j + 1 === n) {
+                            return true;
+                        }
+                        stack.push([j + 1, num]);
+                    } else if (num >= prev) {
+                        break;
+                    }
+                }
+            }
+        }
+
+        return false;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n ^ 2)$
+* Space complexity: $O(n)$
\ No newline at end of file

From 1c4a715d7a373b1a7d86b28ed0b40b83b02f3ccd Mon Sep 17 00:00:00 2001
From: Sri Hari <kataresrihari@gmail.com>
Date: Wed, 12 Feb 2025 22:20:36 +0530
Subject: [PATCH 12/13] Batch-5/Neetcode-ALL/Added-articles

---
 articles/find-unique-binary-string.md         | 685 ++++++++++++++
 ...catenated-string-with-unique-characters.md | 857 ++++++++++++++++++
 .../maximum-score-words-formed-by-letters.md  | 676 ++++++++++++++
 articles/the-number-of-beautiful-subsets.md   | 739 +++++++++++++++
 4 files changed, 2957 insertions(+)
 create mode 100644 articles/find-unique-binary-string.md
 create mode 100644 articles/maximum-length-of-a-concatenated-string-with-unique-characters.md
 create mode 100644 articles/maximum-score-words-formed-by-letters.md
 create mode 100644 articles/the-number-of-beautiful-subsets.md

diff --git a/articles/find-unique-binary-string.md b/articles/find-unique-binary-string.md
new file mode 100644
index 000000000..ea24db9f9
--- /dev/null
+++ b/articles/find-unique-binary-string.md
@@ -0,0 +1,685 @@
+## 1. Backtracking (Recursion)
+
+::tabs-start
+
+```python
+class Solution:
+    def findDifferentBinaryString(self, nums: List[str]) -> str:
+        strSet = {s for s in nums}
+
+        def backtrack(i, cur):
+            if i == len(nums):
+                res = "".join(cur)
+                return None if res in strSet else res
+
+            res = backtrack(i + 1, cur)
+            if res: return res
+
+            cur[i] = "1"
+            return backtrack(i + 1, cur)
+
+        return backtrack(0, ["0" for _ in nums])
+```
+
+```java
+public class Solution {
+    public String findDifferentBinaryString(String[] nums) {
+        Set<String> strSet = new HashSet<>();
+        for (String s : nums) {
+            strSet.add(s);
+        }
+        return backtrack(0, new char[nums.length], strSet, nums.length);
+    }
+
+    private String backtrack(int i, char[] cur, Set<String> strSet, int n) {
+        if (i == n) {
+            String res = new String(cur);
+            return strSet.contains(res) ? null : res;
+        }
+
+        cur[i] = '0';
+        String res = backtrack(i + 1, cur, strSet, n);
+        if (res != null) return res;
+
+        cur[i] = '1';
+        return backtrack(i + 1, cur, strSet, n);
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    string findDifferentBinaryString(vector<string>& nums) {
+        unordered_set<string> strSet(nums.begin(), nums.end());
+        string cur(nums.size(), '0');
+        return backtrack(0, cur, strSet, nums.size());
+    }
+
+private:
+    string backtrack(int i, string& cur, unordered_set<string>& strSet, int n) {
+        if (i == n) {
+            return strSet.count(cur) ? "" : cur;
+        }
+
+        string res = backtrack(i + 1, cur, strSet, n);
+        if (!res.empty()) return res;
+
+        cur[i] = '1';
+        return backtrack(i + 1, cur, strSet, n);
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {string[]} nums
+     * @return {string}
+     */
+    findDifferentBinaryString(nums) {
+        const strSet = new Set(nums);
+        const n = nums.length;
+
+        const backtrack = (i, cur) => {
+            if (i === n) {
+                const res = cur.join("");
+                return strSet.has(res) ? null : res;
+            }
+
+            let res = backtrack(i + 1, cur);
+            if (res) return res;
+
+            cur[i] = "1";
+            return backtrack(i + 1, cur);
+        };
+
+        return backtrack(0, Array(n).fill("0"));
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n ^ 2)$
+* Space complexity: $O(n)$
+
+---
+
+## 2. Backtracking (Iteration)
+
+::tabs-start
+
+```python
+class Solution:
+    def findDifferentBinaryString(self, nums: List[str]) -> str:
+        strSet = set(nums)
+        n = len(nums)
+
+        for num in range(1 << n):  
+            res = bin(num)[2:].zfill(n)  
+            if res not in strSet:
+                return res
+
+        return ""
+```
+
+```java
+public class Solution {
+    public String findDifferentBinaryString(String[] nums) {
+        Set<String> strSet = new HashSet<>();
+        for (String s : nums) {
+            strSet.add(s);
+        }
+        int n = nums.length;
+
+        for (int num = 0; num < (n + 1); num++) {
+            String res = String.format("%" + n + "s", 
+                         Integer.toBinaryString(num)).replace(' ', '0');
+            if (!strSet.contains(res)) {
+                return res;
+            }
+        }
+
+        return "";
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    string findDifferentBinaryString(vector<string>& nums) {
+        unordered_set<string> strSet(nums.begin(), nums.end());
+        int n = nums.size();
+
+        for (int num = 0; num < (n + 1); num++) {
+            string res = toBinaryString(num, n);
+            if (strSet.find(res) == strSet.end()) {
+                return res;
+            }
+        }
+
+        return "";
+    }
+
+private:
+    string toBinaryString(int num, int length) {
+        string res = "";
+        for (int i = length - 1; i >= 0; i--) {
+            res += (num & (1 << i)) ? '1' : '0';
+        }
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {string[]} nums
+     * @return {string}
+     */
+    findDifferentBinaryString(nums) {
+        const strSet = new Set(nums);
+        const n = nums.length;
+
+        for (let num = 0; num < (n + 1); num++) {
+            let res = num.toString(2).padStart(n, '0');
+            if (!strSet.has(res)) {
+                return res;
+            }
+        }
+
+        return "";
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n ^ 2)$
+* Space complexity: $O(n)$
+
+---
+
+## 3. Cantor's Diagonal Argument
+
+::tabs-start
+
+```python
+class Solution:
+    def findDifferentBinaryString(self, nums: List[str]) -> str:
+        res = []
+        for i in range(len(nums)):
+            if nums[i][i] == '0':
+                res.append('1')
+            else:
+                res.append('0')
+        return "".join(res)
+```
+
+```java
+public class Solution {
+    public String findDifferentBinaryString(String[] nums) {
+        StringBuilder res = new StringBuilder();
+        for (int i = 0; i < nums.length; i++) {
+            res.append(nums[i].charAt(i) == '0' ? '1' : '0');
+        }
+        return res.toString();
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    string findDifferentBinaryString(vector<string>& nums) {
+        string res;
+        for (int i = 0; i < nums.size(); i++) {
+            res += (nums[i][i] == '0') ? '1' : '0';
+        }
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {string[]} nums
+     * @return {string}
+     */
+    findDifferentBinaryString(nums) {
+        let res = [];
+        for (let i = 0; i < nums.length; i++) {
+            res.push(nums[i][i] === '0' ? '1' : '0');
+        }
+        return res.join("");
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity:
+    * $O(1)$ extra space.
+    * $O(n)$ space for the output string.
+
+---
+
+## 4. Randomization
+
+::tabs-start
+
+```python
+class Solution:
+    def findDifferentBinaryString(self, nums: List[str]) -> str:
+        strSet = set(nums)
+        n = len(nums)
+
+        while True:
+            res = "".join(random.choice("01") for _ in range(n))
+            if res not in strSet:
+                return res
+```
+
+```java
+public class Solution {
+    public String findDifferentBinaryString(String[] nums) {
+        Set<String> strSet = new HashSet<>();
+        for (String s : nums) {
+            strSet.add(s);
+        }
+        int n = nums.length;
+        Random random = new Random();
+
+        while (true) {
+            StringBuilder res = new StringBuilder();
+            for (int i = 0; i < n; i++) {
+                res.append(random.nextBoolean() ? '1' : '0');
+            }
+            String result = res.toString();
+            if (!strSet.contains(result)) {
+                return result;
+            }
+        }
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    string findDifferentBinaryString(vector<string>& nums) {
+        unordered_set<string> strSet(nums.begin(), nums.end());
+        int n = nums.size();
+
+        while (true) {
+            string res = "";
+            for (int i = 0; i < n; i++) {
+                res += (rand() % 2) ? '1' : '0';
+            }
+            if (strSet.find(res) == strSet.end()) {
+                return res;
+            }
+        }
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {string[]} nums
+     * @return {string}
+     */
+    findDifferentBinaryString(nums) {
+        const strSet = new Set(nums);
+        const n = nums.length;
+
+        while (true) {
+            let res = Array.from({ length: n }, () => 
+                      Math.random() < 0.5 ? '0' : '1').join("");
+            if (!strSet.has(res)) {
+                return res;
+            }
+        }
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(∞)$ in worst case.
+* Space complexity: $O(n)$
+
+---
+
+## 5. Trie
+
+::tabs-start
+
+```python
+class Node:
+    def __init__(self):
+        self.children = [None, None]
+
+    def contains_bit(self, bit: int) -> bool:
+        return self.children[bit] is not None
+
+    def put(self, bit: int):
+        self.children[bit] = Node()
+
+    def get(self, bit: int):
+        return self.children[bit]
+
+class Trie:
+    def __init__(self):
+        self.root = Node()
+
+    def insert(self, s: str):
+        curr = self.root
+        for c in s:
+            bit = int(c)
+            if not curr.contains_bit(bit):
+                curr.put(bit)
+            curr = curr.get(bit)
+
+    def search(self, res: str, curr) -> bool:
+        while curr.contains_bit(0) or curr.contains_bit(1):
+            if not curr.contains_bit(0):
+                res.append('0')
+                return True
+            if not curr.contains_bit(1):
+                res.append('1')
+                return True
+
+            res.append('1')
+            curr = curr.get(1)
+
+        return False
+
+class Solution:
+    def findDifferentBinaryString(self, nums: List[str]) -> str:
+        trie = Trie()
+        for s in nums:
+            trie.insert(s)
+
+        res = []
+        trie.search(res, trie.root)
+
+        while len(res) < len(nums):
+            res.append('1')
+
+        return ''.join(res)
+```
+
+```java
+class Node {
+    Node[] children;
+
+    Node() {
+        this.children = new Node[2];
+    }
+
+    boolean containsBit(int bit) {
+        return this.children[bit] != null;
+    }
+
+    void put(int bit) {
+        this.children[bit] = new Node();
+    }
+
+    Node get(int bit) {
+        return this.children[bit];
+    }
+}
+
+class Trie {
+    Node root;
+
+    Trie() {
+        this.root = new Node();
+    }
+
+    void insert(String s) {
+        Node curr = root;
+        for (char c : s.toCharArray()) {
+            int bit = c - '0';
+            if (!curr.containsBit(bit)) {
+                curr.put(bit);
+            }
+            curr = curr.get(bit);
+        }
+    }
+
+    boolean search(StringBuilder res, Node curr) {
+        while (curr.containsBit(0) || curr.containsBit(1)) {
+            if (!curr.containsBit(0)) {
+                res.append('0');
+                return true;
+            }
+            if (!curr.containsBit(1)) {
+                res.append('1');
+                return true;
+            }
+
+            res.append('1');
+            curr = curr.get(1);
+        }
+
+        return false;
+    }
+}
+
+public class Solution {
+    public String findDifferentBinaryString(String[] nums) {
+        Trie trie = new Trie();
+        for (String s : nums) {
+            trie.insert(s);
+        }
+
+        StringBuilder res = new StringBuilder();
+        trie.search(res, trie.root);
+
+        while (res.length() < nums.length) {
+            res.append('1');
+        }
+
+        return res.toString();
+    }
+}
+```
+
+```cpp
+class Node {
+public:
+    Node *children[2];
+
+    Node() {
+        this->children[0] = nullptr;
+        this->children[1] = nullptr;
+    }
+
+    bool containsBit(int bit) {
+        return this->children[bit] != nullptr;
+    }
+
+    void put(int bit) {
+        this->children[bit] = new Node();
+    }
+
+    Node* get(int bit) {
+        return this->children[bit];
+    }
+};
+
+class Trie {
+public:
+    Node* root;
+
+    Trie() {
+        this->root = new Node();
+    }
+
+    void insert(const string& s) {
+        Node* curr = root;
+        for (char c : s) {
+            int bit = c - '0';
+            if (!curr->containsBit(bit)) {
+                curr->put(bit);
+            }
+            curr = curr->get(bit);
+        }
+    }
+
+    bool search(string& res, Node* curr) {
+        while (curr->containsBit(0) || curr->containsBit(1)) {
+            if (!curr->containsBit(0)) {
+                res += '0';
+                return true;
+            }
+            if (!curr->containsBit(1)) {
+                res += '1';
+                return true;
+            }
+
+            res += '1';
+            curr = curr->get(1);
+        }
+
+        return false;
+    }
+};
+
+class Solution {
+public:
+    string findDifferentBinaryString(vector<string>& nums) {
+        Trie trie;
+        for (const string& s : nums) {
+            trie.insert(s);
+        }
+
+        string res;
+        trie.search(res, trie.root);
+
+        while (res.length() < nums.size()) {
+            res += '1';
+        }
+
+        return res;
+    }
+};
+```
+
+```javascript
+class Node {
+    constructor() {
+        this.children = [null, null];
+    }
+
+    /**
+     * @param {number} bit
+     * @return {boolean}
+     */
+    containsBit(bit) {
+        return this.children[bit] !== null;
+    }
+
+    /**
+     * @param {number} bit
+     */
+    put(bit) {
+        this.children[bit] = new Node();
+    }
+
+    /**
+     * @param {number} bit
+     * @return {Node}
+     */
+    get(bit) {
+        return this.children[bit];
+    }
+}
+
+class Trie {
+    constructor() {
+        this.root = new Node();
+    }
+
+    /**
+     * @param {string} s
+     */
+    insert(s) {
+        let curr = this.root;
+        for (const c of s) {
+            let bit = c === '1' ? 1 : 0;
+            if (!curr.containsBit(bit)) {
+                curr.put(bit);
+            }
+            curr = curr.get(bit);
+        }
+    }
+
+    /**
+     * @param {string[]} res
+     * @param {Node} curr
+     * @return {boolean}
+     */
+    search(res, curr) {
+        while (curr.containsBit(0) || curr.containsBit(1)) {
+            if (!curr.containsBit(0)) {
+                res.push('0');
+                return true;
+            }
+            if (!curr.containsBit(1)) {
+                res.push('1');
+                return true;
+            }
+
+            res.push('1');
+            curr = curr.get(1);
+        }
+        return false;
+    }
+}
+
+class Solution {
+    /**
+     * @param {string[]} nums
+     * @return {string}
+     */
+    findDifferentBinaryString(nums) {
+        let trie = new Trie();
+        for (const s of nums) {
+            trie.insert(s);
+        }
+
+        let res = [];
+        trie.search(res, trie.root);
+
+        while (res.length < nums.length) {
+            res.push('1');
+        }
+
+        return res.join("");
+    }
+}
+```
+
+::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/maximum-length-of-a-concatenated-string-with-unique-characters.md b/articles/maximum-length-of-a-concatenated-string-with-unique-characters.md
new file mode 100644
index 000000000..f8cdea423
--- /dev/null
+++ b/articles/maximum-length-of-a-concatenated-string-with-unique-characters.md
@@ -0,0 +1,857 @@
+## 1. Backtracking (Hash Set)
+
+::tabs-start
+
+```python
+class Solution:
+    def maxLength(self, arr: List[str]) -> int:
+        charSet = set()
+
+        def overlap(charSet, s):
+            prev = set()
+            for c in s:
+                if c in charSet or c in prev:
+                    return True
+                prev.add(c)
+            return False
+
+        def backtrack(i):
+            if i == len(arr):
+                return len(charSet)
+
+            res = 0
+            if not overlap(charSet, arr[i]):
+                for c in arr[i]:
+                    charSet.add(c)
+                res = backtrack(i + 1)
+                for c in arr[i]:
+                    charSet.remove(c)
+
+            return max(res, backtrack(i + 1))
+
+        return backtrack(0)
+```
+
+```java
+public class Solution {
+    public int maxLength(List<String> arr) {
+        Set<Character> charSet = new HashSet<>();
+        return backtrack(0, arr, charSet);
+    }
+
+    private boolean overlap(Set<Character> charSet, String s) {
+        Set<Character> prev = new HashSet<>();
+        for (char c : s.toCharArray()) {
+            if (charSet.contains(c) || prev.contains(c)) {
+                return true;
+            }
+            prev.add(c);
+        }
+        return false;
+    }
+
+    private int backtrack(int i, List<String> arr, Set<Character> charSet) {
+        if (i == arr.size()) {
+            return charSet.size();
+        }
+
+        int res = 0;
+        if (!overlap(charSet, arr.get(i))) {
+            for (char c : arr.get(i).toCharArray()) {
+                charSet.add(c);
+            }
+            res = backtrack(i + 1, arr, charSet);
+            for (char c : arr.get(i).toCharArray()) {
+                charSet.remove(c);
+            }
+        }
+
+        return Math.max(res, backtrack(i + 1, arr, charSet));
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int maxLength(vector<string>& arr) {
+        unordered_set<char> charSet;
+        return backtrack(0, arr, charSet);
+    }
+
+private:
+    bool overlap(unordered_set<char>& charSet, const string& s) {
+        unordered_set<char> prev;
+        for (char c : s) {
+            if (charSet.count(c) || prev.count(c)) {
+                return true;
+            }
+            prev.insert(c);
+        }
+        return false;
+    }
+
+    int backtrack(int i, vector<string>& arr, unordered_set<char>& charSet) {
+        if (i == arr.size()) {
+            return charSet.size();
+        }
+
+        int res = 0;
+        if (!overlap(charSet, arr[i])) {
+            for (char c : arr[i]) {
+                charSet.insert(c);
+            }
+            res = backtrack(i + 1, arr, charSet);
+            for (char c : arr[i]) {
+                charSet.erase(c);
+            }
+        }
+
+        return max(res, backtrack(i + 1, arr, charSet));
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {string[]} arr
+     * @return {number}
+     */
+    maxLength(arr) {
+        let charSet = new Set();
+
+        const overlap = (charSet, s) => {
+            let prev = new Set();
+            for (const c of s) {
+                if (charSet.has(c) || prev.has(c)) {
+                    return true;
+                }
+                prev.add(c);
+            }
+            return false;
+        };
+
+        const backtrack = (i) => {
+            if (i === arr.length) {
+                return charSet.size;
+            }
+
+            let res = 0;
+            if (!overlap(charSet, arr[i])) {
+                for (const c of arr[i]) {
+                    charSet.add(c);
+                }
+                res = backtrack(i + 1);
+                for (const c of arr[i]) {
+                    charSet.delete(c);
+                }
+            }
+
+            return Math.max(res, backtrack(i + 1));
+        };
+
+        return backtrack(0);
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(m * 2 ^ n)$
+* Space complexity: $O(n)$ for recursion stack.
+
+> Where $n$ is the number of strings and $m$ is the maximum length of a string.
+
+---
+
+## 2. Backtracking (Boolean Array)
+
+::tabs-start
+
+```python
+class Solution:
+    def maxLength(self, arr: List[str]) -> int:
+        charSet = [False] * 26
+
+        def getIdx(c):
+            return ord(c) - ord('a')
+
+        def overlap(charSet, s):
+            for i in range(len(s)):
+                c = getIdx(s[i])
+                if charSet[c]:
+                    for j in range(i):
+                        charSet[getIdx(s[j])] = False
+                    return True
+                charSet[c] = True
+            return False
+
+        def backtrack(i):
+            if i == len(arr):
+                return 0
+
+            res = 0
+            if not overlap(charSet, arr[i]):
+                res = len(arr[i]) + backtrack(i + 1)
+                for c in arr[i]:
+                    charSet[getIdx(c)] = False
+            return max(res, backtrack(i + 1))
+
+        return backtrack(0)
+```
+
+```java
+public class Solution {
+    public int maxLength(List<String> arr) {
+        boolean[] charSet = new boolean[26];
+        return backtrack(0, arr, charSet);
+    }
+
+    private int getIdx(char c) {
+        return c - 'a';
+    }
+
+    private boolean overlap(boolean[] charSet, String s) {
+        for (int i = 0; i < s.length(); i++) {
+            int c = getIdx(s.charAt(i));
+            if (charSet[c]) {
+                for (int j = 0; j < i; j++) {
+                    charSet[getIdx(s.charAt(j))] = false;
+                }
+                return true;
+            }
+            charSet[c] = true;
+        }
+        return false;
+    }
+
+    private int backtrack(int i, List<String> arr, boolean[] charSet) {
+        if (i == arr.size()) {
+            return 0;
+        }
+
+        int res = 0;
+        if (!overlap(charSet, arr.get(i))) {
+            res = arr.get(i).length() + backtrack(i + 1, arr, charSet);
+            for (char c : arr.get(i).toCharArray()) {
+                charSet[getIdx(c)] = false;
+            }
+        }
+        return Math.max(res, backtrack(i + 1, arr, charSet));
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int maxLength(vector<string>& arr) {
+        bool charSet[26] = {false};
+        return backtrack(0, arr, charSet);
+    }
+
+private:
+    int getIdx(char c) {
+        return c - 'a';
+    }
+
+    bool overlap(bool charSet[], const string& s) {
+        for (int i = 0; i < s.length(); i++) {
+            int c = getIdx(s[i]);
+            if (charSet[c]) {
+                for (int j = 0; j < i; j++) {
+                    charSet[getIdx(s[j])] = false;
+                }
+                return true;
+            }
+            charSet[c] = true;
+        }
+        return false;
+    }
+
+    int backtrack(int i, vector<string>& arr, bool charSet[]) {
+        if (i == arr.size()) {
+            return 0;
+        }
+
+        int res = 0;
+        if (!overlap(charSet, arr[i])) {
+            res = arr[i].length() + backtrack(i + 1, arr, charSet);
+            for (char c : arr[i]) {
+                charSet[getIdx(c)] = false;
+            }
+        }
+        return max(res, backtrack(i + 1, arr, charSet));
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {string[]} arr
+     * @return {number}
+     */
+    maxLength(arr) {
+        let charSet = new Array(26).fill(false);
+
+        const getIdx = (c) => c.charCodeAt(0) - 'a'.charCodeAt(0);
+
+        const overlap = (charSet, s) => {
+            for (let i = 0; i < s.length; i++) {
+                let c = getIdx(s[i]);
+                if (charSet[c]) {
+                    for (let j = 0; j < i; j++) {
+                        charSet[getIdx(s[j])] = false;
+                    }
+                    return true;
+                }
+                charSet[c] = true;
+            }
+            return false;
+        };
+
+        const backtrack = (i) => {
+            if (i === arr.length) {
+                return 0;
+            }
+
+            let res = 0;
+            if (!overlap(charSet, arr[i])) {
+                res = arr[i].length + backtrack(i + 1);
+                for (const c of arr[i]) {
+                    charSet[getIdx(c)] = false;
+                }
+            }
+            return Math.max(res, backtrack(i + 1));
+        };
+
+        return backtrack(0);
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(m * 2 ^ n)$
+* Space complexity: $O(n)$ for recursion stack.
+
+> Where $n$ is the number of strings and $m$ is the maximum length of a string.
+
+---
+
+## 3. Recursion (Bit Mask) - I
+
+::tabs-start
+
+```python
+class Solution:
+    def maxLength(self, arr: List[str]) -> int:
+        def getIdx(c):
+            return ord(c) - ord('a')
+
+        A = []
+        for s in arr:
+            cur = 0
+            valid = True
+            for c in s:
+                if cur & (1 << getIdx(c)):
+                    valid = False
+                    break
+                cur |= (1 << getIdx(c))
+
+            if valid:
+                A.append([cur, len(s)])
+
+        def dfs(i, subSeq):
+            if i == len(A):
+                return 0
+
+            res = dfs(i + 1, subSeq)
+
+            curSeq, length = A[i][0], A[i][1]
+            if (subSeq & curSeq) == 0:
+                res = max(res, length + dfs(i + 1, subSeq | curSeq))
+            return res
+
+        return dfs(0, 0)
+```
+
+```java
+public class Solution {
+    public int maxLength(List<String> arr) {
+        List<int[]> A = new ArrayList<>();
+
+        for (String s : arr) {
+            int cur = 0;
+            boolean valid = true;
+
+            for (char c : s.toCharArray()) {
+                if ((cur & (1 << (c - 'a'))) != 0) {
+                    valid = false;
+                    break;
+                }
+                cur |= (1 << (c - 'a'));
+            }
+
+            if (valid) {
+                A.add(new int[]{cur, s.length()});
+            }
+        }
+
+        return dfs(0, 0, A);
+    }
+
+    private int dfs(int i, int subSeq, List<int[]> A) {
+        if (i == A.size()) {
+            return 0;
+        }
+
+        int res = dfs(i + 1, subSeq, A);
+
+        int curSeq = A.get(i)[0], length = A.get(i)[1];
+        if ((subSeq & curSeq) == 0) {
+            res = Math.max(res, length + dfs(i + 1, subSeq | curSeq, A));
+        }
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int maxLength(vector<string>& arr) {
+        vector<pair<int, int>> A;
+
+        for (const string& s : arr) {
+            int cur = 0;
+            bool valid = true;
+
+            for (char c : s) {
+                if (cur & (1 << (c - 'a'))) {
+                    valid = false;
+                    break;
+                }
+                cur |= (1 << (c - 'a'));
+            }
+
+            if (valid) {
+                A.emplace_back(cur, s.length());
+            }
+        }
+
+        return dfs(0, 0, A);
+    }
+
+private:
+    int dfs(int i, int subSeq, vector<pair<int, int>>& A) {
+        if (i == A.size()) {
+            return 0;
+        }
+
+        int res = dfs(i + 1, subSeq, A);
+
+        int curSeq = A[i].first, length = A[i].second;
+        if ((subSeq & curSeq) == 0) {
+            res = max(res, length + dfs(i + 1, subSeq | curSeq, A));
+        }
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {string[]} arr
+     * @return {number}
+     */
+    maxLength(arr) {
+        let A = [];
+
+        for (const s of arr) {
+            let cur = 0;
+            let valid = true;
+
+            for (const c of s) {
+                if (cur & (1 << (c.charCodeAt(0) - 97))) {
+                    valid = false;
+                    break;
+                }
+                cur |= (1 << (c.charCodeAt(0) - 97));
+            }
+
+            if (valid) {
+                A.push([cur, s.length]);
+            }
+        }
+
+        const dfs = (i, subSeq) => {
+            if (i === A.length) {
+                return 0;
+            }
+
+            let res = dfs(i + 1, subSeq);
+
+            let [curSeq, length] = A[i];
+            if ((subSeq & curSeq) === 0) {
+                res = Math.max(res, length + dfs(i + 1, subSeq | curSeq));
+            }
+            return res;
+        };
+
+        return dfs(0, 0);
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(m * n + 2 ^ n)$
+* Space complexity: $O(n)$
+
+> Where $n$ is the number of strings and $m$ is the maximum length of a string.
+
+---
+
+## 4. Recursion (Bit Mask) - II
+
+::tabs-start
+
+```python
+class Solution:
+    def maxLength(self, arr: List[str]) -> int:
+        def getIdx(c):
+            return ord(c) - ord('a')
+
+        A = []
+        for s in arr:
+            cur = 0
+            valid = True
+            for c in s:
+                if cur & (1 << getIdx(c)):
+                    valid = False
+                    break
+                cur |= (1 << getIdx(c))
+
+            if valid:
+                A.append([cur, len(s)])
+
+        def dfs(i, subSeq):
+            res = 0
+            for j in range(i, len(A)):
+                curSeq, length = A[j][0], A[j][1]
+                if (subSeq & curSeq) == 0:
+                    res = max(res, length + dfs(j + 1, subSeq | curSeq))
+            return res
+
+        return dfs(0, 0)
+```
+
+```java
+public class Solution {
+    public int maxLength(List<String> arr) {
+        List<int[]> A = new ArrayList<>();
+
+        for (String s : arr) {
+            int cur = 0;
+            boolean valid = true;
+
+            for (char c : s.toCharArray()) {
+                if ((cur & (1 << (c - 'a'))) != 0) {
+                    valid = false;
+                    break;
+                }
+                cur |= (1 << (c - 'a'));
+            }
+
+            if (valid) {
+                A.add(new int[]{cur, s.length()});
+            }
+        }
+
+        return dfs(0, 0, A);
+    }
+
+    private int dfs(int i, int subSeq, List<int[]> A) {
+        int res = 0;
+        for (int j = i; j < A.size(); j++) {
+            int curSeq = A.get(j)[0], length = A.get(j)[1];
+            if ((subSeq & curSeq) == 0) {
+                res = Math.max(res, length + dfs(j + 1, subSeq | curSeq, A));
+            }
+        }
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int maxLength(vector<string>& arr) {
+        vector<pair<int, int>> A;
+
+        for (const string& s : arr) {
+            int cur = 0;
+            bool valid = true;
+
+            for (char c : s) {
+                if (cur & (1 << (c - 'a'))) {
+                    valid = false;
+                    break;
+                }
+                cur |= (1 << (c - 'a'));
+            }
+
+            if (valid) {
+                A.emplace_back(cur, s.length());
+            }
+        }
+
+        return dfs(0, 0, A);
+    }
+
+private:
+    int dfs(int i, int subSeq, vector<pair<int, int>>& A) {
+        int res = 0;
+        for (int j = i; j < A.size(); j++) {
+            int curSeq = A[j].first, length = A[j].second;
+            if ((subSeq & curSeq) == 0) {
+                res = max(res, length + dfs(j + 1, subSeq | curSeq, A));
+            }
+        }
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {string[]} arr
+     * @return {number}
+     */
+    maxLength(arr) {
+        let A = [];
+
+        for (const s of arr) {
+            let cur = 0;
+            let valid = true;
+
+            for (const c of s) {
+                if (cur & (1 << (c.charCodeAt(0) - 97))) {
+                    valid = false;
+                    break;
+                }
+                cur |= (1 << (c.charCodeAt(0) - 97));
+            }
+
+            if (valid) {
+                A.push([cur, s.length]);
+            }
+        }
+
+        const dfs = (i, subSeq) => {
+            let res = 0;
+            for (let j = i; j < A.length; j++) {
+                let [curSeq, length] = A[j];
+                if ((subSeq & curSeq) === 0) {
+                    res = Math.max(res, length + dfs(j + 1, subSeq | curSeq));
+                }
+            }
+            return res;
+        };
+
+        return dfs(0, 0);
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n * (m  + 2 ^ n))$
+* Space complexity: $O(n)$
+
+> Where $n$ is the number of strings and $m$ is the maximum length of a string.
+
+---
+
+## 5. Dynamic Programming
+
+::tabs-start
+
+```python
+class Solution:
+    def maxLength(self, arr: List[str]) -> int:
+        dp = {0}
+        res = 0
+
+        for s in arr:
+            cur = 0
+            valid = True
+
+            for c in s:
+                bit = 1 << (ord(c) - ord('a'))
+                if cur & bit:
+                    valid = False
+                    break
+                cur |= bit
+
+            if not valid:
+                continue
+
+            next_dp = dp.copy()
+            for seq in dp:
+                if (seq & cur) or (seq | cur) in dp:
+                    continue
+                next_dp.add(seq | cur)
+                res = max(res, bin(seq | cur).count('1'))
+            dp = next_dp
+
+        return res
+```
+
+```java
+public class Solution {
+    public int maxLength(List<String> arr) {
+        Set<Integer> dp = new HashSet<>();
+        dp.add(0);
+        int res = 0;
+
+        for (String s : arr) {
+            int cur = 0;
+            boolean valid = true;
+
+            for (char c : s.toCharArray()) {
+                int bit = 1 << (c - 'a');
+                if ((cur & bit) != 0) {
+                    valid = false;
+                    break;
+                }
+                cur |= bit;
+            }
+
+            if (!valid) {
+                continue;
+            }
+
+            Set<Integer> next_dp = new HashSet<>(dp);
+            for (int seq : dp) {
+                if ((seq & cur) != 0 || next_dp.contains(seq | cur)) {
+                    continue;
+                }
+                next_dp.add(seq | cur);
+                res = Math.max(res, Integer.bitCount(seq | cur));
+            }
+            dp = next_dp;
+        }
+
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int maxLength(vector<string>& arr) {
+        unordered_set<int> dp;
+        dp.insert(0);
+        int res = 0;
+
+        for (const string& s : arr) {
+            int cur = 0;
+            bool valid = true;
+
+            for (char c : s) {
+                int bit = 1 << (c - 'a');
+                if (cur & bit) {
+                    valid = false;
+                    break;
+                }
+                cur |= bit;
+            }
+
+            if (!valid) {
+                continue;
+            }
+
+            unordered_set<int> next_dp(dp);
+            for (int seq : dp) {
+                if ((seq & cur) || next_dp.count(seq | cur)) {
+                    continue;
+                }
+                next_dp.insert(seq | cur);
+                res = max(res, __builtin_popcount(seq | cur));
+            }
+            dp = next_dp;
+        }
+
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {string[]} arr
+     * @return {number}
+     */
+    maxLength(arr) {
+        let dp = new Set();
+        dp.add(0);
+        let res = 0;
+
+        for (const s of arr) {
+            let cur = 0;
+            let valid = true;
+
+            for (const c of s) {
+                let bit = 1 << (c.charCodeAt(0) - 97);
+                if (cur & bit) {
+                    valid = false;
+                    break;
+                }
+                cur |= bit;
+            }
+
+            if (!valid) {
+                continue;
+            }
+
+            let next_dp = new Set(dp);
+            for (let seq of dp) {
+                if ((seq & cur) || next_dp.has(seq | cur)) {
+                    continue;
+                }
+                next_dp.add(seq | cur);
+                res = Math.max(res, (seq | cur).toString(2).split('0').join('').length);
+            }
+            dp = next_dp;
+        }
+
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n * (m  + 2 ^ n))$
+* Space complexity: $O(2 ^ n)$
+
+> Where $n$ is the number of strings and $m$ is the maximum length of a string.
\ No newline at end of file
diff --git a/articles/maximum-score-words-formed-by-letters.md b/articles/maximum-score-words-formed-by-letters.md
new file mode 100644
index 000000000..f9b510481
--- /dev/null
+++ b/articles/maximum-score-words-formed-by-letters.md
@@ -0,0 +1,676 @@
+## 1. Backtracking
+
+::tabs-start
+
+```python
+class Solution:
+    def maxScoreWords(self, words: List[str], letters: List[str], score: List[int]) -> int:
+        def can_form_word(w, letter_cnt):
+            word_cnt = Counter(w)
+            for c in word_cnt:
+                if word_cnt[c] > letter_cnt[c]:
+                    return False
+            return True
+
+        def get_score(w):
+            res = 0
+            for c in w:
+                res += score[ord(c) - ord('a')]
+            return res
+
+        letter_cnt = Counter(letters)
+
+        def backtrack(i):
+            if i == len(words):
+                return 0
+
+            res = backtrack(i + 1)  # skip
+            if can_form_word(words[i], letter_cnt):  # include (when possible)
+                for c in words[i]:
+                    letter_cnt[c] -= 1
+                res = max(res, get_score(words[i]) + backtrack(i + 1))
+                for c in words[i]:
+                    letter_cnt[c] += 1
+
+            return res
+
+        return backtrack(0)
+```
+
+```java
+public class Solution {
+    int[] letterCnt;
+    int[] score;
+
+    public int maxScoreWords(String[] words, char[] letters, int[] score) {
+        this.score = score;
+        this.letterCnt = new int[26];
+
+        for (char c : letters) {
+            letterCnt[c - 'a']++;
+        }
+
+        return backtrack(0, words);
+    }
+
+    private int canFormWord(String word) {
+        int[] wordCnt = new int[26];
+        for (char c : word.toCharArray()) {
+            wordCnt[c - 'a']++;
+            if (wordCnt[c - 'a'] > letterCnt[c - 'a']) {
+                return 0;
+            }
+        }
+        return 1;
+    }
+
+    private int getScore(String word) {
+        int res = 0;
+        for (char c : word.toCharArray()) {
+            res += score[c - 'a'];
+        }
+        return res;
+    }
+
+    private int backtrack(int i, String[] words) {
+        if (i == words.length) {
+            return 0;
+        }
+
+        int res = backtrack(i + 1, words);  // skip
+        if (canFormWord(words[i]) == 1) {  // include (when possible)
+            for (char c : words[i].toCharArray()) {
+                letterCnt[c - 'a']--;
+            }
+            res = Math.max(res, getScore(words[i]) + backtrack(i + 1, words));
+            for (char c : words[i].toCharArray()) {
+                letterCnt[c - 'a']++;
+            }
+        }
+
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    vector<int> letterCnt = vector<int>(26, 0);
+    vector<int> score;
+    vector<string> words;
+
+    int maxScoreWords(vector<string>& words, vector<char>& letters, vector<int>& score) {
+        this->words = words;
+        this->score = score;
+
+        for (char c : letters) {
+            letterCnt[c - 'a']++;
+        }
+
+        return backtrack(0);
+    }
+
+    bool canFormWord(string& word) {
+        vector<int> wordCnt(26, 0);
+        for (char c : word) {
+            wordCnt[c - 'a']++;
+            if (wordCnt[c - 'a'] > letterCnt[c - 'a']) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    int getScore(string& word) {
+        int res = 0;
+        for (char c : word) {
+            res += score[c - 'a'];
+        }
+        return res;
+    }
+
+    int backtrack(int i) {
+        if (i == words.size()) {
+            return 0;
+        }
+
+        int res = backtrack(i + 1);  // skip
+        if (canFormWord(words[i])) {  // include (when possible)
+            for (char c : words[i]) {
+                letterCnt[c - 'a']--;
+            }
+            res = max(res, getScore(words[i]) + backtrack(i + 1));
+            for (char c : words[i]) {
+                letterCnt[c - 'a']++;
+            }
+        }
+
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {string[]} words
+     * @param {string[]} letters
+     * @param {number[]} score
+     * @return {number}
+     */
+    maxScoreWords(words, letters, score) {
+        const canFormWord = (w, letterCnt) => {
+            let wordCnt = new Array(26).fill(0);
+            for (let c of w) {
+                let idx = c.charCodeAt(0) - 'a'.charCodeAt(0);
+                wordCnt[idx]++;
+                if (wordCnt[idx] > letterCnt[idx]) {
+                    return false;
+                }
+            }
+            return true;
+        };
+
+        const getScore = (w) => {
+            let res = 0;
+            for (let c of w) {
+                res += score[c.charCodeAt(0) - 'a'.charCodeAt(0)];
+            }
+            return res;
+        };
+
+        let letterCnt = new Array(26).fill(0);
+        for (let c of letters) {
+            letterCnt[c.charCodeAt(0) - 'a'.charCodeAt(0)]++;
+        }
+
+        const backtrack = (i) => {
+            if (i === words.length) {
+                return 0;
+            }
+
+            let res = backtrack(i + 1); // skip
+
+            if (canFormWord(words[i], letterCnt)) { // include (when possible)
+                for (let c of words[i]) {
+                    letterCnt[c.charCodeAt(0) - 'a'.charCodeAt(0)]--;
+                }
+                res = Math.max(res, getScore(words[i]) + backtrack(i + 1));
+                for (let c of words[i]) {
+                    letterCnt[c.charCodeAt(0) - 'a'.charCodeAt(0)]++;
+                }
+            }
+
+            return res;
+        };
+
+        return backtrack(0);
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(2 ^ n * (w + m) + N)$
+* Space complexity: $O(n + w)$
+
+> Where $n$ is the number of words, $w$ is the maximum length of a word, $m$ is the size of the array $scores$, and $N$ is the size of the array $letters$.
+
+---
+
+## 2. Bactracking + Precomputation
+
+::tabs-start
+
+```python
+class Solution:
+    def maxScoreWords(self, words: List[str], letters: List[str], score: List[int]) -> int:
+        letter_cnt = [0] * 26
+        for c in letters:
+            letter_cnt[ord(c) - ord('a')] += 1
+
+        n = len(words)
+        word_scores = [0] * n
+        word_freqs = [[0] * 26 for _ in range(n)]
+
+        for i, word in enumerate(words):
+            for c in word:
+                idx = ord(c) - ord('a')
+                word_freqs[i][idx] += 1
+                word_scores[i] += score[idx]
+
+        def backtrack(i):
+            if i == n:
+                return 0
+
+            res = backtrack(i + 1)  # skip
+            can_include = all(word_freqs[i][j] <= letter_cnt[j] for j in range(26))
+
+            if can_include:  # include (when possible)
+                for j in range(26):
+                    letter_cnt[j] -= word_freqs[i][j]
+                res = max(res, word_scores[i] + backtrack(i + 1))
+                for j in range(26):
+                    letter_cnt[j] += word_freqs[i][j]
+
+            return res
+
+        return backtrack(0)
+```
+
+```java
+public class Solution {
+    private int[] letterCnt = new int[26];
+    private int[] wordScores;
+    private int[][] wordFreqs;
+    private int n;
+
+    public int maxScoreWords(String[] words, char[] letters, int[] score) {
+        Arrays.fill(letterCnt, 0);
+        for (char c : letters) {
+            letterCnt[c - 'a']++;
+        }
+
+        n = words.length;
+        wordScores = new int[n];
+        wordFreqs = new int[n][26];
+
+        for (int i = 0; i < n; i++) {
+            for (char c : words[i].toCharArray()) {
+                int idx = c - 'a';
+                wordFreqs[i][idx]++;
+                wordScores[i] += score[idx];
+            }
+        }
+
+        return backtrack(0, words);
+    }
+
+    private int backtrack(int i, String[] words) {
+        if (i == n) {
+            return 0;
+        }
+
+        int res = backtrack(i + 1, words); // skip
+        boolean canInclude = true;
+
+        for (int j = 0; j < 26; j++) {
+            if (wordFreqs[i][j] > letterCnt[j]) {
+                canInclude = false;
+                break;
+            }
+        }
+
+        if (canInclude) {  // include (when possible)
+            for (int j = 0; j < 26; j++) {
+                letterCnt[j] -= wordFreqs[i][j];
+            }
+            res = Math.max(res, wordScores[i] + backtrack(i + 1, words));
+            for (int j = 0; j < 26; j++) {
+                letterCnt[j] += wordFreqs[i][j];
+            }
+        }
+
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    vector<int> letterCnt = vector<int>(26, 0);
+    vector<int> wordScores;
+    vector<vector<int>> wordFreqs;
+    int n;
+
+    int maxScoreWords(vector<string>& words, vector<char>& letters, vector<int>& score) {
+        fill(letterCnt.begin(), letterCnt.end(), 0);
+        for (char c : letters) {
+            letterCnt[c - 'a']++;
+        }
+
+        n = words.size();
+        wordScores = vector<int>(n, 0);
+        wordFreqs = vector<vector<int>>(n, vector<int>(26, 0));
+
+        for (int i = 0; i < n; i++) {
+            for (char c : words[i]) {
+                int idx = c - 'a';
+                wordFreqs[i][idx]++;
+                wordScores[i] += score[idx];
+            }
+        }
+
+        return backtrack(0, words);
+    }
+
+private:
+    int backtrack(int i, vector<string>& words) {
+        if (i == n) {
+            return 0;
+        }
+
+        int res = backtrack(i + 1, words); // skip
+        bool canInclude = true;
+
+        for (int j = 0; j < 26; j++) {
+            if (wordFreqs[i][j] > letterCnt[j]) {
+                canInclude = false;
+                break;
+            }
+        }
+
+        if (canInclude) {  // include (when possible)
+            for (int j = 0; j < 26; j++) {
+                letterCnt[j] -= wordFreqs[i][j];
+            }
+            res = max(res, wordScores[i] + backtrack(i + 1, words));
+            for (int j = 0; j < 26; j++) {
+                letterCnt[j] += wordFreqs[i][j];
+            }
+        }
+
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {string[]} words
+     * @param {string[]} letters
+     * @param {number[]} score
+     * @return {number}
+     */
+    maxScoreWords(words, letters, score) {
+        let letterCnt = new Array(26).fill(0);
+        for (let c of letters) {
+            letterCnt[c.charCodeAt(0) - 'a'.charCodeAt(0)]++;
+        }
+
+        let n = words.length;
+        let wordScores = new Array(n).fill(0);
+        let wordFreqs = Array.from({ length: n }, () => new Array(26).fill(0));
+
+        for (let i = 0; i < n; i++) {
+            for (let c of words[i]) {
+                let idx = c.charCodeAt(0) - 'a'.charCodeAt(0);
+                wordFreqs[i][idx]++;
+                wordScores[i] += score[idx];
+            }
+        }
+
+        const backtrack = (i) => {
+            if (i === n) {
+                return 0;
+            }
+
+            let res = backtrack(i + 1); // skip
+            let canInclude = true;
+
+            for (let j = 0; j < 26; j++) {
+                if (wordFreqs[i][j] > letterCnt[j]) {
+                    canInclude = false;
+                    break;
+                }
+            }
+
+            if (canInclude) { // include (when possible)
+                for (let j = 0; j < 26; j++) {
+                    letterCnt[j] -= wordFreqs[i][j];
+                }
+                res = Math.max(res, wordScores[i] + backtrack(i + 1));
+                for (let j = 0; j < 26; j++) {
+                    letterCnt[j] += wordFreqs[i][j];
+                }
+            }
+
+            return res;
+        };
+
+        return backtrack(0);
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(m * 2 ^ n + N)$
+* Space complexity: $O(n + w)$
+
+> Where $n$ is the number of words, $w$ is the maximum length of a word, $m$ is the size of the array $scores$, and $N$ is the size of the array $letters$.
+
+---
+
+## 3. Backtracking (Bit Mask)
+
+::tabs-start
+
+```python
+class Solution:
+    def maxScoreWords(self, words: List[str], letters: List[str], score: List[int]) -> int:
+        letter_cnt = [0] * 26
+        for c in letters:
+            letter_cnt[ord(c) - ord('a')] += 1
+
+        n = len(words)
+        word_scores = [0] * n
+        word_freqs = [[0] * 26 for _ in range(n)]
+
+        for i, word in enumerate(words):
+            for c in word:
+                idx = ord(c) - ord('a')
+                word_freqs[i][idx] += 1
+                word_scores[i] += score[idx]
+
+        res = 0
+
+        for mask in range(1 << n):
+            cur_score = 0
+            cur_letter_cnt = letter_cnt[:]
+            valid = True
+
+            for i in range(n):
+                if mask & (1 << i):
+                    for j in range(26):
+                        if word_freqs[i][j] > cur_letter_cnt[j]:
+                            valid = False
+                            break
+                    if not valid:
+                        break
+
+                    for j in range(26):
+                        cur_letter_cnt[j] -= word_freqs[i][j]
+                    
+                    cur_score += word_scores[i]
+
+            if valid:
+                res = max(res, cur_score)
+
+        return res
+```
+
+```java
+public class Solution {
+    public int maxScoreWords(String[] words, char[] letters, int[] score) {
+        int[] letterCnt = new int[26];
+        for (char c : letters) {
+            letterCnt[c - 'a']++;
+        }
+
+        int n = words.length;
+        int[] wordScores = new int[n];
+        int[][] wordFreqs = new int[n][26];
+
+        for (int i = 0; i < n; i++) {
+            for (char c : words[i].toCharArray()) {
+                int idx = c - 'a';
+                wordFreqs[i][idx]++;
+                wordScores[i] += score[idx];
+            }
+        }
+
+        int res = 0;
+        for (int mask = 0; mask < (1 << n); mask++) {
+            int curScore = 0;
+            int[] curLetterCnt = Arrays.copyOf(letterCnt, 26);
+            boolean valid = true;
+
+            for (int i = 0; i < n; i++) {
+                if ((mask & (1 << i)) != 0) {
+                    for (int j = 0; j < 26; j++) {
+                        if (wordFreqs[i][j] > curLetterCnt[j]) {
+                            valid = false;
+                            break;
+                        }
+                    }
+                    if (!valid) break;
+
+                    for (int j = 0; j < 26; j++) {
+                        curLetterCnt[j] -= wordFreqs[i][j];
+                    }
+
+                    curScore += wordScores[i];
+                }
+            }
+
+            if (valid) {
+                res = Math.max(res, curScore);
+            }
+        }
+
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int maxScoreWords(vector<string>& words, vector<char>& letters, vector<int>& score) {
+        vector<int> letterCnt(26, 0);
+        for (char c : letters) {
+            letterCnt[c - 'a']++;
+        }
+
+        int n = words.size();
+        vector<int> wordScores(n, 0);
+        vector<vector<int>> wordFreqs(n, vector<int>(26, 0));
+
+        for (int i = 0; i < n; i++) {
+            for (char c : words[i]) {
+                int idx = c - 'a';
+                wordFreqs[i][idx]++;
+                wordScores[i] += score[idx];
+            }
+        }
+
+        int res = 0;
+        for (int mask = 0; mask < (1 << n); mask++) {
+            int curScore = 0;
+            vector<int> curLetterCnt = letterCnt;
+            bool valid = true;
+
+            for (int i = 0; i < n; i++) {
+                if (mask & (1 << i)) {
+                    for (int j = 0; j < 26; j++) {
+                        if (wordFreqs[i][j] > curLetterCnt[j]) {
+                            valid = false;
+                            break;
+                        }
+                    }
+                    if (!valid) break;
+
+                    for (int j = 0; j < 26; j++) {
+                        curLetterCnt[j] -= wordFreqs[i][j];
+                    }
+
+                    curScore += wordScores[i];
+                }
+            }
+
+            if (valid) {
+                res = max(res, curScore);
+            }
+        }
+
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {string[]} words
+     * @param {string[]} letters
+     * @param {number[]} score
+     * @return {number}
+     */
+    maxScoreWords(words, letters, score) {
+        let letterCnt = new Array(26).fill(0);
+        for (let c of letters) {
+            letterCnt[c.charCodeAt(0) - 'a'.charCodeAt(0)]++;
+        }
+
+        let n = words.length;
+        let wordScores = new Array(n).fill(0);
+        let wordFreqs = Array.from({ length: n }, () => new Array(26).fill(0));
+
+        for (let i = 0; i < n; i++) {
+            for (let c of words[i]) {
+                let idx = c.charCodeAt(0) - 'a'.charCodeAt(0);
+                wordFreqs[i][idx]++;
+                wordScores[i] += score[idx];
+            }
+        }
+
+        let res = 0;
+        for (let mask = 0; mask < (1 << n); mask++) {
+            let curScore = 0;
+            let curLetterCnt = [...letterCnt];
+            let valid = true;
+
+            for (let i = 0; i < n; i++) {
+                if ((mask & (1 << i)) !== 0) {
+                    for (let j = 0; j < 26; j++) {
+                        if (wordFreqs[i][j] > curLetterCnt[j]) {
+                            valid = false;
+                            break;
+                        }
+                    }
+                    if (!valid) break;
+
+                    for (let j = 0; j < 26; j++) {
+                        curLetterCnt[j] -= wordFreqs[i][j];
+                    }
+
+                    curScore += wordScores[i];
+                }
+            }
+
+            if (valid) {
+                res = Math.max(res, curScore);
+            }
+        }
+
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(m * n * 2 ^ n + N)$
+* Space complexity: $O(n + w)$
+
+> Where $n$ is the number of words, $w$ is the maximum length of a word, $m$ is the size of the array $scores$, and $N$ is the size of the array $letters$.
\ No newline at end of file
diff --git a/articles/the-number-of-beautiful-subsets.md b/articles/the-number-of-beautiful-subsets.md
new file mode 100644
index 000000000..1ed55b435
--- /dev/null
+++ b/articles/the-number-of-beautiful-subsets.md
@@ -0,0 +1,739 @@
+## 1. Backtracking
+
+::tabs-start
+
+```python
+class Solution:
+    def beautifulSubsets(self, nums: List[int], k: int) -> int:
+        def helper(i, count):
+            if i == len(nums):
+                return 1
+
+            res = helper(i + 1, count)  # Skip nums[i]
+            if not count[nums[i] + k] and not count[nums[i] - k]:
+                count[nums[i]] += 1
+                res += helper(i + 1, count)
+                count[nums[i]] -= 1
+
+            return res
+
+        return helper(0, defaultdict(int)) - 1
+```
+
+```java
+public class Solution {
+    public int beautifulSubsets(int[] nums, int k) {
+        return helper(0, new HashMap<>(), nums, k) - 1;
+    }
+
+    private int helper(int i, Map<Integer, Integer> count, int[] nums, int k) {
+        if (i == nums.length) {
+            return 1;
+        }
+
+        int res = helper(i + 1, count, nums, k); // Skip nums[i]
+
+        if (!count.containsKey(nums[i] + k) && !count.containsKey(nums[i] - k)) {
+            count.put(nums[i], count.getOrDefault(nums[i], 0) + 1);
+            res += helper(i + 1, count, nums, k);
+            count.put(nums[i], count.get(nums[i]) - 1);
+            if (count.get(nums[i]) == 0) {
+                count.remove(nums[i]);
+            }
+        }
+
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int beautifulSubsets(vector<int>& nums, int k) {
+        unordered_map<int, int> count;
+        return helper(0, count, nums, k) - 1;
+    }
+
+private:
+    int helper(int i, unordered_map<int, int>& count, vector<int>& nums, int k) {
+        if (i == nums.size()) {
+            return 1;
+        }
+
+        int res = helper(i + 1, count, nums, k); // Skip nums[i]
+        if (!count[nums[i] + k] && !count[nums[i] - k]) {
+            count[nums[i]]++;
+            res += helper(i + 1, count, nums, k);
+            count[nums[i]]--;
+        }
+
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} nums
+     * @param {number} k
+     * @return {number}
+     */
+    beautifulSubsets(nums, k) {
+        const helper = (i, count) => {
+            if (i === nums.length) {
+                return 1;
+            }
+
+            let res = helper(i + 1, count); // Skip nums[i]
+
+            if (!count.has(nums[i] + k) && !count.has(nums[i] - k)) {
+                count.set(nums[i], (count.get(nums[i]) || 0) + 1);
+                res += helper(i + 1, count);
+                count.set(nums[i], count.get(nums[i]) - 1);
+                if (count.get(nums[i]) === 0) {
+                    count.delete(nums[i]);
+                }
+            }
+
+            return res;
+        };
+
+        return helper(0, new Map()) - 1;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(2 ^ n)$
+* Space complexity: $O(n)$
+
+---
+
+## 2. Dynamic Programming (Top-Down)
+
+::tabs-start
+
+```python
+class Solution:
+    def beautifulSubsets(self, nums: List[int], k: int) -> int:
+        cnt = Counter(nums)
+        groups = []  # List of dicts
+        cache = {}
+
+        def helper(n, g):
+            if n not in g:
+                return 1
+            if n in cache:
+                return cache[n]
+            
+            skip = helper(n + k, g)
+            include = (2**g[n] - 1) * helper(n + 2 * k, g)
+            cache[n] = skip + include
+            return skip + include
+
+        visit = set()
+        for n in cnt.keys():
+            if n in visit:
+                continue
+            g = {}
+            while n - k in cnt:
+                n -= k
+            while n in cnt:
+                g[n] = cnt[n]
+                visit.add(n)
+                n += k
+            groups.append(g)
+
+        res = 1
+        for g in groups:
+            n = min(g.keys())
+            res *= helper(n, g)
+
+        return res - 1
+```
+
+```java
+public class Solution {
+    private Map<Integer, Integer> cache;
+    private Map<Integer, Integer> cnt;
+    private Set<Integer> visit;
+
+    public int beautifulSubsets(int[] nums, int k) {
+        List<Map<Integer, Integer>> groups = new ArrayList<>();
+        this.cache = new HashMap<>();
+        this.cnt = new HashMap<>();
+        this.visit = new HashSet<>();
+
+        for (int num : nums) {
+            cnt.put(num, cnt.getOrDefault(num, 0) + 1);
+        }
+
+        for (int n : cnt.keySet()) {
+            if (visit.contains(n)) {
+                continue;
+            }
+            Map<Integer, Integer> g = new HashMap<>();
+            while (cnt.containsKey(n - k)) {
+                n -= k;
+            }
+            while (cnt.containsKey(n)) {
+                g.put(n, cnt.get(n));
+                visit.add(n);
+                n += k;
+            }
+            groups.add(g);
+        }
+
+        int res = 1;
+        for (Map<Integer, Integer> g : groups) {
+            int n = Collections.min(g.keySet());
+            res *= helper(n, g, k);
+        }
+
+        return res - 1;
+    }
+
+    private int helper(int n, Map<Integer, Integer> g, int k) {
+        if (!g.containsKey(n)) {
+            return 1;
+        }
+        if (cache.containsKey(n)) {
+            return cache.get(n);
+        }
+
+        int skip = helper(n + k, g, k);
+        int include = (int) ((Math.pow(2, g.get(n)) - 1) * helper(n + 2 * k, g, k));
+        int result = skip + include;
+        cache.put(n, result);
+        return result;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int beautifulSubsets(vector<int>& nums, int k) {
+        vector<unordered_map<int, int>> groups;
+        cache.clear();
+        cnt.clear();
+        visit.clear();
+
+        for (int& num : nums) {
+            cnt[num]++;
+        }
+
+        for (auto it = cnt.begin(); it != cnt.end(); ++it) {
+            int n = it->first;
+            if (visit.count(n)) {
+                continue;
+            }
+            unordered_map<int, int> g;
+            while (cnt.count(n - k)) {
+                n -= k;
+            }
+            while (cnt.count(n)) {
+                g[n] = cnt[n];
+                visit.insert(n);
+                n += k;
+            }
+            groups.push_back(g);
+        }
+
+        int res = 1;
+        for (auto& g : groups) {
+            int n = min_element(g.begin(), g.end())->first;
+            res *= helper(n, g, k);
+        }
+        return res - 1;
+    }
+
+private:
+    unordered_map<int, int> cache;
+    unordered_map<int, int> cnt;
+    unordered_set<int> visit;
+
+    int helper(int n, unordered_map<int, int>& g, int k) {
+        if (!g.count(n)) {
+            return 1;
+        }
+        if (cache.count(n)) {
+            return cache[n];
+        }
+
+        int skip = helper(n + k, g, k);
+        int include = (pow(2, g[n]) - 1) * helper(n + 2 * k, g, k);
+        return cache[n] = skip + include;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} nums
+     * @param {number} k
+     * @return {number}
+     */
+    beautifulSubsets(nums, k) {
+        let cnt = new Map();
+        for (const num of nums) {
+            cnt.set(num, (cnt.get(num) || 0) + 1);
+        }
+
+        let groups = [];
+        let cache = new Map();
+        let visit = new Set();
+
+        for (let n of cnt.keys()) {
+            if (visit.has(n)) {
+                continue;
+            }
+            let g = new Map();
+            while (cnt.has(n - k)) {
+                n -= k;
+            }
+            while (cnt.has(n)) {
+                g.set(n, cnt.get(n));
+                visit.add(n);
+                n += k;
+            }
+            groups.push(g);
+        }
+
+        const helper = (n, g) => {
+            if (!g.has(n)) {
+                return 1;
+            }
+            if (cache.has(n)) {
+                return cache.get(n);
+            }
+
+            let skip = helper(n + k, g);
+            let include = (2 ** g.get(n) - 1) * helper(n + 2 * k, g);
+            let result = skip + include;
+            cache.set(n, result);
+            return result;
+        };
+
+        let res = 1;
+        for (const g of groups) {
+            let n = Math.min(...g.keys());
+            res *= helper(n, g);
+        }
+        return res - 1;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(n)$
+
+---
+
+## 3. Dynamic Programming (Bottom-Up)
+
+::tabs-start
+
+```python
+class Solution:
+    def beautifulSubsets(self, nums: List[int], k: int) -> int:
+        cnt = Counter(nums)
+        groups = []  # List of dicts
+
+        visit = set()
+        for n in cnt.keys():
+            if n in visit:
+                continue
+            g = {}
+            while n - k in cnt:
+                n -= k
+            while n in cnt:
+                g[n] = cnt[n]
+                visit.add(n)
+                n += k
+            groups.append(g)
+
+        res = 1
+        for g in groups:
+            dp = {}
+            prev = None
+
+            for num in sorted(g):
+                count = g[num]
+                if prev is None or prev + k != num:
+                    dp[num] = (dp.get(prev, 1) * (1 + (2 ** count - 1)))
+                else:
+                    dp[num] = dp[prev] + (2 ** count - 1) * dp.get(prev - k, 1)
+                prev = num
+
+            res *= dp[prev]
+
+        return res - 1
+```
+
+```java
+class Solution {
+    public int beautifulSubsets(int[] nums, int k) {
+        Map<Integer, Integer> cnt = new HashMap<>();
+        for (int num : nums) {
+            cnt.put(num, cnt.getOrDefault(num, 0) + 1);
+        }
+
+        List<Map<Integer, Integer>> groups = new ArrayList<>();
+        Set<Integer> visit = new HashSet<>();
+
+        for (int n : cnt.keySet()) {
+            if (visit.contains(n)) {
+                continue;
+            }
+            Map<Integer, Integer> g = new HashMap<>();
+            while (cnt.containsKey(n - k)) {
+                n -= k;
+            }
+            while (cnt.containsKey(n)) {
+                g.put(n, cnt.get(n));
+                visit.add(n);
+                n += k;
+            }
+            groups.add(g);
+        }
+
+        int res = 1;
+        for (Map<Integer, Integer> g : groups) {
+            Map<Integer, Integer> dp = new HashMap<>();
+            Integer prev = null;
+
+            List<Integer> arr = new ArrayList<>(g.keySet());
+            Collections.sort(arr);
+            for (int num : arr) {
+                int count = g.get(num);
+                if (prev == null || prev + k != num) {
+                    dp.put(num, dp.getOrDefault(prev, 1) * (1 + (int) Math.pow(2, count) - 1));
+                } else {
+                    dp.put(num, dp.get(prev) + 
+                          ((int) Math.pow(2, count) - 1) * dp.getOrDefault(prev - k, 1));
+                }
+                prev = num;
+            }
+
+            res *= dp.get(prev);
+        }
+
+        return res - 1;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int beautifulSubsets(vector<int>& nums, int k) {
+        unordered_map<int, int> cnt;
+        for (int num : nums) {
+            cnt[num]++;
+        }
+
+        vector<unordered_map<int, int>> groups;
+        unordered_set<int> visit;
+
+        for (auto it = cnt.begin(); it != cnt.end(); ++it) {
+            int n = it->first;
+            if (visit.count(n)) {
+                continue;
+            }
+            unordered_map<int, int> g;
+            while (cnt.count(n - k)) {
+                n -= k;
+            }
+            while (cnt.count(n)) {
+                g[n] = cnt[n];
+                visit.insert(n);
+                n += k;
+            }
+            groups.push_back(g);
+        }
+
+        int res = 1;
+        for (auto& g : groups) {
+            unordered_map<int, int> dp;
+            int prev = -1;
+
+            vector<int> keys;
+            for (auto& [num, _] : g) {
+                keys.push_back(num);
+            }
+            sort(keys.begin(), keys.end());
+
+            for (int num : keys) {
+                int count = g[num];
+                if (prev == -1 || prev + k != num) {
+                    dp[num] = dp.count(prev) ? dp[prev] * (1 + (1 << count) - 1) : 
+                                               (1 + (1 << count) - 1);
+                } else {
+                    dp[num] = dp[prev] + ((1 << count) - 1) * 
+                              (dp.count(prev - k) ? dp[prev - k] : 1);
+                }
+                prev = num;
+            }
+
+            res *= dp[prev];
+        }
+
+        return res - 1;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} nums
+     * @param {number} k
+     * @return {number}
+     */
+    beautifulSubsets(nums, k) {
+        let cnt = new Map();
+        for (const num of nums) {
+            cnt.set(num, (cnt.get(num) || 0) + 1);
+        }
+
+        let groups = [];
+        let visit = new Set();
+
+        for (const n of cnt.keys()) {
+            if (visit.has(n)) {
+                continue;
+            }
+            let g = new Map();
+            let num = n;
+            while (cnt.has(num - k)) {
+                num -= k;
+            }
+            while (cnt.has(num)) {
+                g.set(num, cnt.get(num));
+                visit.add(num);
+                num += k;
+            }
+            groups.push(g);
+        }
+
+        let res = 1;
+        for (const g of groups) {
+            let dp = new Map();
+            let prev = null;
+
+            for (const num of g.keys()) {
+                let count = g.get(num);
+                if (prev === null || prev + k !== num) {
+                    dp.set(num, (dp.get(prev) || 1) * (1 + (2 ** count - 1)));
+                } else {
+                    dp.set(num, dp.get(prev) + (2 ** count - 1) * (dp.get(prev - k) || 1));
+                }
+                prev = num;
+            }
+
+            res *= dp.get(prev);
+        }
+
+        return res - 1;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n \log n)$
+* Space complexity: $O(n)$
+
+---
+
+## 4. Dynamic Programming (Space Optimized)
+
+::tabs-start
+
+```python
+class Solution:
+    def beautifulSubsets(self, nums: List[int], k: int) -> int:
+        cnt = Counter(nums)
+        groups = defaultdict(dict)
+
+        # Group numbers based on their remainder with k
+        for num in nums:
+            groups[num % k][num] = cnt[num]
+
+        res = 1
+        for g in groups.values():
+            prev = 0
+            dp, ndp = 0, 1
+
+            for num in sorted(g.keys()):
+                count = g[num]
+                have = (1 << count) - 1
+                tmp = ndp
+                ndp += dp
+
+                if prev == 0 or prev + k != num:
+                    dp = have * (tmp + dp)
+                else:
+                    dp = tmp * have
+
+                prev = num
+
+            res *= (dp + ndp)
+
+        return res - 1
+```
+
+```java
+public class Solution {
+    public int beautifulSubsets(int[] nums, int k) {
+        Map<Integer, Map<Integer, Integer>> groups = new HashMap<>();
+        Map<Integer, Integer> cnt = new HashMap<>();
+        for (int num : nums) {
+            cnt.put(num, cnt.getOrDefault(num, 0) + 1);
+        }
+
+        // Group numbers based on remainder with k
+        for (int num : nums) {
+            groups.putIfAbsent(num % k, new HashMap<>());
+            groups.get(num % k).put(num, cnt.get(num));
+        }
+
+        int res = 1;
+        for (Map<Integer, Integer> g : groups.values()) {
+            int prev = 0, dp = 0, ndp = 1;
+            List<Integer> sortedKeys = new ArrayList<>(g.keySet());
+            Collections.sort(sortedKeys);
+
+            for (int num : sortedKeys) {
+                int count = g.get(num);
+                int have = (1 << count) - 1;
+                int tmp = ndp;
+                ndp += dp;
+
+                if (prev == 0 || prev + k != num) {
+                    dp = have * (tmp + dp);
+                } else {
+                    dp = tmp * have;
+                }
+
+                prev = num;
+            }
+
+            res *= (dp + ndp);
+        }
+
+        return res - 1;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int beautifulSubsets(vector<int>& nums, int k) {
+        unordered_map<int, map<int, int>> groups;
+        unordered_map<int, int> cnt;
+        for (int& num : nums) {
+            cnt[num]++;
+        }
+
+        // Group numbers based on remainder with k
+        for (int num : nums) {
+            groups[num % k][num] = cnt[num];
+        }
+
+        int res = 1;
+        for (auto& [rem, g] : groups) {
+            int prev = 0, dp = 0, ndp = 1;
+
+            for (auto& [num, count] : g) {
+                int have = (1 << count) - 1;
+                int tmp = ndp;
+                ndp += dp;
+
+                if (prev == 0 || prev + k != num) {
+                    dp = have * (tmp + dp);
+                } else {
+                    dp = tmp * have;
+                }
+
+                prev = num;
+            }
+
+            res *= (dp + ndp);
+        }
+
+        return res - 1;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} nums
+     * @param {number} k
+     * @return {number}
+     */
+    beautifulSubsets(nums, k) {
+        let groups = new Map();
+        let cnt = new Map();
+        for (const num of nums) {
+            cnt.set(num, (cnt.get(num) || 0) + 1);
+        }
+
+        // Group numbers based on remainder with k
+        for (const num of nums) {
+            if (!groups.has(num % k)) {
+                groups.set(num % k, new Map());
+            }
+            groups.get(num % k).set(num, cnt.get(num));
+        }
+
+        let res = 1;
+        for (const g of groups.values()) {
+            let prev = 0, dp = 0, ndp = 1;
+            let sortedKeys = Array.from(g.keys()).sort((a, b) => a - b);
+
+            for (const num of sortedKeys) {
+                let count = g.get(num);
+                let have = (1 << count) - 1;
+                let tmp = ndp;
+                ndp += dp;
+
+                if (prev === 0 || prev + k !== num) {
+                    dp = have * (tmp + dp);
+                } else {
+                    dp = tmp * have;
+                }
+
+                prev = num;
+            }
+
+            res *= (dp + ndp);
+        }
+
+        return res - 1;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n \log n)$
+* Space complexity: $O(n)$
\ No newline at end of file

From be12d06f47ceda1d938f456f24cc5cf6efe8ecc7 Mon Sep 17 00:00:00 2001
From: Sri Hari <kataresrihari@gmail.com>
Date: Thu, 13 Feb 2025 18:56:57 +0530
Subject: [PATCH 13/13] Batch-5/Neetcode-ALL/Added-articles

---
 articles/concatenated-words.md                | 587 +++++++++++++++
 ...t-all-valid-pickup-and-delivery-options.md | 668 ++++++++++++++++++
 articles/maximize-score-after-n-operations.md | 629 +++++++++++++++++
 ...umber-of-ways-to-divide-a-long-corridor.md | 608 ++++++++++++++++
 4 files changed, 2492 insertions(+)
 create mode 100644 articles/concatenated-words.md
 create mode 100644 articles/count-all-valid-pickup-and-delivery-options.md
 create mode 100644 articles/maximize-score-after-n-operations.md
 create mode 100644 articles/number-of-ways-to-divide-a-long-corridor.md

diff --git a/articles/concatenated-words.md b/articles/concatenated-words.md
new file mode 100644
index 000000000..0d7eaf0d4
--- /dev/null
+++ b/articles/concatenated-words.md
@@ -0,0 +1,587 @@
+## 1. Brute Force (Backtracking)
+
+::tabs-start
+
+```python
+class Solution:
+    def findAllConcatenatedWordsInADict(self, words: List[str]) -> List[str]:
+        n = len(words)
+        res = []
+        wordSet = set(words)
+        maxLen = 0
+        for w in words:
+            maxLen = max(maxLen, len(w))
+
+        def dfs(concatWord, totLen):
+            if len(concatWord) > 1:
+                word = "".join(concatWord)
+                if word in wordSet:
+                    res.append(word)
+                    wordSet.remove(word)
+
+            for i in range(len(words)):
+                if totLen + len(words[i]) > maxLen:
+                    continue
+                concatWord.append(words[i])
+                dfs(concatWord, totLen + len(words[i]))
+                concatWord.pop()
+
+        dfs([], 0)
+        return res
+```
+
+```java
+public class Solution {
+    private Set<String> wordSet;
+    private int maxLen;
+    private List<String> res;
+    private String[] words;
+
+    public List<String> findAllConcatenatedWordsInADict(String[] words) {
+        this.words = words;
+        this.wordSet = new HashSet<>(Arrays.asList(words));
+        this.maxLen = 0;
+        this.res = new ArrayList<>();
+
+        for (String w : words) {
+            maxLen = Math.max(maxLen, w.length());
+        }
+
+        dfs(new ArrayList<>(), 0);
+        return res;
+    }
+
+    private void dfs(List<String> concatWord, int totLen) {
+        if (concatWord.size() > 1) {
+            String word = String.join("", concatWord);
+            if (wordSet.contains(word)) {
+                res.add(word);
+                wordSet.remove(word);
+            }
+        }
+
+        for (String word : words) {
+            if (totLen + word.length() > maxLen) continue;
+            concatWord.add(word);
+            dfs(concatWord, totLen + word.length());
+            concatWord.remove(concatWord.size() - 1);
+        }
+    }
+}
+```
+
+```cpp
+class Solution {
+private:
+    unordered_set<string> wordSet;
+    int maxLen;
+    vector<string> res;
+    vector<string> words;
+
+public:
+    vector<string> findAllConcatenatedWordsInADict(vector<string>& words) {
+        this->words = words;
+        wordSet = unordered_set<string>(words.begin(), words.end());
+        maxLen = 0;
+        res.clear();
+
+        for (const string& w : words) {
+            maxLen = max(maxLen, (int)w.length());
+        }
+
+        vector<string> concatWord;
+        dfs(concatWord, 0);
+        return res;
+    }
+
+private:
+    void dfs(vector<string>& concatWord, int totLen) {
+        if (concatWord.size() > 1) {
+            string word = accumulate(concatWord.begin(), concatWord.end(), string(""));
+            if (wordSet.count(word)) {
+                res.push_back(word);
+                wordSet.erase(word);
+            }
+        }
+
+        for (const string& word : words) {
+            if (totLen + word.size() > maxLen) continue;
+            concatWord.push_back(word);
+            dfs(concatWord, totLen + word.length());
+            concatWord.pop_back();
+        }
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {string[]} words
+     * @return {string[]}
+     */
+    findAllConcatenatedWordsInADict(words) {
+        let n = words.length;
+        let res = [];
+        let wordSet = new Set(words);
+        let maxLen = 0;
+
+        for (let w of words) {
+            maxLen = Math.max(maxLen, w.length);
+        }
+
+        const dfs = (concatWord, totLen) => {
+            if (concatWord.length > 1) {
+                let word = concatWord.join("");
+                if (wordSet.has(word)) {
+                    res.push(word);
+                    wordSet.delete(word);
+                }
+            }
+
+            for (let i = 0; i < words.length; i++) {
+                if (totLen + words[i].length > maxLen) continue;
+                concatWord.push(words[i]);
+                dfs(concatWord, totLen + words[i].length);
+                concatWord.pop();
+            }
+        };
+
+        dfs([], 0);
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(m * n ^ n)$
+* Space complexity: $O(m * n)$
+
+> Where $n$ is the size of the string array $words$ and $m$ is the length of the longest word in the array.
+
+---
+
+## 2. Recursion
+
+::tabs-start
+
+```python
+class Solution:
+    def findAllConcatenatedWordsInADict(self, words: List[str]) -> List[str]:
+        wordSet = set(words)
+
+        def dfs(word):
+            for i in range(1, len(word)):
+                prefix, suffix = word[:i], word[i:]
+                if ((prefix in wordSet and suffix in wordSet) or 
+                    (prefix in wordSet and dfs(suffix))
+                ):
+                    return True
+            return False
+
+        res = []
+        for w in words:
+            if dfs(w):
+                res.append(w)
+        return res
+```
+
+```java
+public class Solution {
+    public List<String> findAllConcatenatedWordsInADict(String[] words) {
+        Set<String> wordSet = new HashSet<>(Arrays.asList(words));
+        List<String> res = new ArrayList<>();
+
+        for (String w : words) {
+            if (dfs(w, wordSet)) {
+                res.add(w);
+            }
+        }
+        return res;
+    }
+
+    private boolean dfs(String word, Set<String> wordSet) {
+        for (int i = 1; i < word.length(); i++) {
+            String prefix = word.substring(0, i);
+            String suffix = word.substring(i);
+
+            if ((wordSet.contains(prefix) && wordSet.contains(suffix)) ||
+                (wordSet.contains(prefix) && dfs(suffix, wordSet))) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    vector<string> findAllConcatenatedWordsInADict(vector<string>& words) {
+        unordered_set<string> wordSet(words.begin(), words.end());
+        vector<string> res;
+
+        for (const string& w : words) {
+            if (dfs(w, wordSet)) {
+                res.push_back(w);
+            }
+        }
+        return res;
+    }
+
+private:
+    bool dfs(const string& word, unordered_set<string>& wordSet) {
+        for (int i = 1; i < word.size(); i++) {
+            string prefix = word.substr(0, i);
+            string suffix = word.substr(i);
+
+            if ((wordSet.count(prefix) && wordSet.count(suffix)) ||
+                (wordSet.count(prefix) && dfs(suffix, wordSet))) {
+                return true;
+            }
+        }
+        return false;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {string[]} words
+     * @return {string[]}
+     */
+    findAllConcatenatedWordsInADict(words) {
+        const wordSet = new Set(words);
+
+        const dfs = (word) => {
+            for (let i = 1; i < word.length; i++) {
+                const prefix = word.substring(0, i);
+                const suffix = word.substring(i);
+
+                if ((wordSet.has(prefix) && wordSet.has(suffix)) || 
+                    (wordSet.has(prefix) && dfs(suffix))) {
+                    return true;
+                }
+            }
+            return false;
+        };
+
+        const res = [];
+        for (let w of words) {
+            if (dfs(w)) {
+                res.push(w);
+            }
+        }
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n * m ^ 4)$
+* Space complexity: $O(n * m)$
+
+> Where $n$ is the size of the string array $words$ and $m$ is the length of the longest word in the array.
+
+---
+
+## 3. Dynamic Programming (Top-Down)
+
+::tabs-start
+
+```python
+class Solution:
+    def findAllConcatenatedWordsInADict(self, words: List[str]) -> List[str]:
+        wordSet = set(words)
+        dp = {}
+
+        def dfs(word):
+            if word in dp:
+                return dp[word]
+
+            for i in range(1, len(word)):
+                prefix, suffix = word[:i], word[i:]
+                if ((prefix in wordSet and suffix in wordSet) or 
+                    (prefix in wordSet and dfs(suffix))
+                ):
+                    dp[word] = True
+                    return True
+            dp[word] = False
+            return False
+
+        res = []
+        for w in words:
+            if dfs(w):
+                res.append(w)
+        return res
+```
+
+```java
+public class Solution {
+    private Map<String, Boolean> dp;
+
+    public List<String> findAllConcatenatedWordsInADict(String[] words) {
+        Set<String> wordSet = new HashSet<>(Arrays.asList(words));
+        List<String> res = new ArrayList<>();
+        dp = new HashMap<>();
+
+        for (String w : words) {
+            if (dfs(w, wordSet)) {
+                res.add(w);
+            }
+        }
+        return res;
+    }
+
+    private boolean dfs(String word, Set<String> wordSet) {
+        if (dp.containsKey(word)) {
+            return dp.get(word);
+        }
+
+        for (int i = 1; i < word.length(); i++) {
+            String prefix = word.substring(0, i);
+            String suffix = word.substring(i);
+
+            if ((wordSet.contains(prefix) && wordSet.contains(suffix)) ||
+                (wordSet.contains(prefix) && dfs(suffix, wordSet))) {
+                dp.put(word, true);
+                return true;
+            }
+        }
+        dp.put(word, false);
+        return false;
+    }
+}
+```
+
+```cpp
+class Solution {
+    unordered_map<string, bool> dp;
+
+public:
+    vector<string> findAllConcatenatedWordsInADict(vector<string>& words) {
+        unordered_set<string> wordSet(words.begin(), words.end());
+        vector<string> res;
+
+        for (const string& w : words) {
+            if (dfs(w, wordSet)) {
+                res.push_back(w);
+            }
+        }
+        return res;
+    }
+
+private:
+    bool dfs(const string& word, unordered_set<string>& wordSet) {
+        if (dp.count(word)) {
+            return dp[word];
+        }
+
+        for (int i = 1; i < word.size(); i++) {
+            string prefix = word.substr(0, i);
+            string suffix = word.substr(i);
+
+            if ((wordSet.count(prefix) && wordSet.count(suffix)) ||
+                (wordSet.count(prefix) && dfs(suffix, wordSet))) {
+                dp[word] = true;
+                return true;
+            }
+        }
+        dp[word] = false;
+        return false;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {string[]} words
+     * @return {string[]}
+     */
+    findAllConcatenatedWordsInADict(words) {
+        const wordSet = new Set(words);
+        const dp = new Map();
+
+        const dfs = (word) => {
+            if (dp.has(word)) {
+                return dp.get(word);
+            }
+
+            for (let i = 1; i < word.length; i++) {
+                const prefix = word.substring(0, i);
+                const suffix = word.substring(i);
+
+                if ((wordSet.has(prefix) && wordSet.has(suffix)) || 
+                    (wordSet.has(prefix) && dfs(suffix))) {
+                    dp.set(word, true);
+                    return true;
+                }
+            }
+            dp.set(word, false);
+            return false;
+        };
+
+        const res = [];
+        for (let w of words) {
+            if (dfs(w)) {
+                res.push(w);
+            }
+        }
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n * m ^ 3)$
+* Space complexity: $O(n * m)$
+
+> Where $n$ is the size of the string array $words$ and $m$ is the length of the longest word in the array.
+
+---
+
+## 4. Dynamic Programming (Bottom-Up)
+
+::tabs-start
+
+```python
+class Solution:
+    def findAllConcatenatedWordsInADict(self, words: List[str]) -> List[str]:
+        wordSet = set(words)
+        res = []
+
+        for word in words:
+            m = len(word)
+
+            dp = [False] * (m + 1)
+            dp[0] = True
+
+            for i in range(1, m + 1):
+                for j in range(i):
+                    if j == 0 and i == m:
+                        continue
+                    if dp[j] and word[j:i] in wordSet:
+                        dp[i] = True
+                        break
+
+            if dp[m]:
+                res.append(word)
+
+        return res
+```
+
+```java
+public class Solution {
+    public List<String> findAllConcatenatedWordsInADict(String[] words) {
+        Set<String> wordSet = new HashSet<>(Arrays.asList(words));
+        List<String> res = new ArrayList<>();
+
+        for (String word : words) {
+            int m = word.length();
+            boolean[] dp = new boolean[m + 1];
+            dp[0] = true;
+
+            for (int i = 1; i <= m; i++) {
+                for (int j = 0; j < i; j++) {
+                    if (j == 0 && i == m) continue;
+                    if (dp[j] && wordSet.contains(word.substring(j, i))) {
+                        dp[i] = true;
+                        break;
+                    }
+                }
+            }
+
+            if (dp[m]) {
+                res.add(word);
+            }
+        }
+        return res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    vector<string> findAllConcatenatedWordsInADict(vector<string>& words) {
+        unordered_set<string> wordSet(words.begin(), words.end());
+        vector<string> res;
+
+        for (string& word : words) {
+            int m = word.length();
+            vector<bool> dp(m + 1, false);
+            dp[0] = true;
+
+            for (int i = 1; i <= m; i++) {
+                for (int j = 0; j < i; j++) {
+                    if (j == 0 && i == m) continue;
+                    if (dp[j] && wordSet.count(word.substr(j, i - j))) {
+                        dp[i] = true;
+                        break;
+                    }
+                }
+            }
+
+            if (dp[m]) {
+                res.push_back(word);
+            }
+        }
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {string[]} words
+     * @return {string[]}
+     */
+    findAllConcatenatedWordsInADict(words) {
+        const wordSet = new Set(words);
+        const res = [];
+
+        for (const word of words) {
+            const m = word.length;
+            const dp = new Array(m + 1).fill(false);
+            dp[0] = true;
+
+            for (let i = 1; i <= m; i++) {
+                for (let j = 0; j < i; j++) {
+                    if (j === 0 && i === m) continue;
+                    if (dp[j] && wordSet.has(word.substring(j, i))) {
+                        dp[i] = true;
+                        break;
+                    }
+                }
+            }
+
+            if (dp[m]) {
+                res.push(word);
+            }
+        }
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n * m ^ 3)$
+* Space complexity: $O(n * m)$
+
+> Where $n$ is the size of the string array $words$ and $m$ is the length of the longest word in the array.
\ No newline at end of file
diff --git a/articles/count-all-valid-pickup-and-delivery-options.md b/articles/count-all-valid-pickup-and-delivery-options.md
new file mode 100644
index 000000000..78b58d069
--- /dev/null
+++ b/articles/count-all-valid-pickup-and-delivery-options.md
@@ -0,0 +1,668 @@
+## 1. Recursion
+
+::tabs-start
+
+```python
+class Solution:
+    def countOrders(self, n: int) -> int:
+        MOD = 1000000007
+
+        def dfs(picked, delivered):
+            if picked == n and delivered == n:
+                return 1
+
+            res = 0
+            if picked < n:
+                res = (res + (n - picked) * dfs(picked + 1, delivered)) % MOD
+            if delivered < picked:
+                res = (res + (picked - delivered) * dfs(picked, delivered + 1)) % MOD
+
+            return res
+
+        return dfs(0, 0)
+```
+
+```java
+public class Solution {
+    private static final int MOD = 1_000_000_007;
+
+    public int countOrders(int n) {
+        return dfs(0, 0, n);
+    }
+
+    private int dfs(int picked, int delivered, int n) {
+        if (picked == n && delivered == n) {
+            return 1;
+        }
+
+        long res = 0;
+        if (picked < n) {
+            res = ((res + (n - picked) * 1L * dfs(picked + 1, delivered, n)) % MOD);
+        }
+        if (delivered < picked) {
+            res = ((res + (picked - delivered) * 1L * dfs(picked, delivered + 1, n)) % MOD);
+        }
+
+        return (int) res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    static const int MOD = 1'000'000'007;
+
+    int countOrders(int n) {
+        return dfs(0, 0, n);
+    }
+
+private:
+    int dfs(int picked, int delivered, int n) {
+        if (picked == n && delivered == n) {
+            return 1;
+        }
+
+        int res = 0;
+        if (picked < n) {
+            res = (res + (n - picked) * 1LL * dfs(picked + 1, delivered, n)) % MOD;
+        }
+        if (delivered < picked) {
+            res = (res + (picked - delivered) * 1LL * dfs(picked, delivered + 1, n)) % MOD;
+        }
+
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number} n
+     * @return {number}
+     */
+    countOrders(n) {
+        const MOD = 1_000_000_007;
+
+        const dfs = (picked, delivered) => {
+            if (picked === n && delivered === n) {
+                return 1;
+            }
+
+            let res = 0;
+            if (picked < n) {
+                res = (res + (n - picked) * dfs(picked + 1, delivered)) % MOD;
+            }
+            if (delivered < picked) {
+                res = (res + (picked - delivered) * dfs(picked, delivered + 1)) % MOD;
+            }
+
+            return res;
+        };
+
+        return dfs(0, 0);
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(2 ^ n)$
+* Space complexity: $O(n)$ for recursion stack.
+
+---
+
+## 2. Dynamic Programming (Top-Down)
+
+::tabs-start
+
+```python
+class Solution:
+    def countOrders(self, n: int) -> int:
+        MOD = 1000000007
+        dp = [[-1] * (n + 1) for _ in range(n + 1)]
+        dp[n][n] = 1
+
+        def dfs(picked, delivered):
+            if dp[picked][delivered] != -1:
+                return dp[picked][delivered]
+
+            res = 0
+            if picked < n:
+                res = (res + (n - picked) * dfs(picked + 1, delivered)) % MOD
+            if delivered < picked:
+                res = (res + (picked - delivered) * dfs(picked, delivered + 1)) % MOD
+
+            dp[picked][delivered] = res
+            return res
+
+        return dfs(0, 0)
+```
+
+```java
+public class Solution {
+    private static final int MOD = 1_000_000_007;
+    private int[][] dp;
+
+    public int countOrders(int n) {
+        dp = new int[n + 1][n + 1];
+        for (int i = 0; i <= n; i++) {
+            for (int j = 0; j <= n; j++) {
+                dp[i][j] = -1;
+            }
+        }
+        dp[n][n] = 1;
+        return dfs(0, 0, n);
+    }
+
+    private int dfs(int picked, int delivered, int n) {
+        if (dp[picked][delivered] != -1) {
+            return dp[picked][delivered];
+        }
+
+        long res = 0;
+        if (picked < n) {
+            res = ((res + (n - picked) * 1L * dfs(picked + 1, delivered, n)) % MOD);
+        }
+        if (delivered < picked) {
+            res = ((res + (picked - delivered) * 1L * dfs(picked, delivered + 1, n)) % MOD);
+        }
+
+        return dp[picked][delivered] = (int)res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    static const int MOD = 1'000'000'007;
+    vector<vector<int>> dp;
+
+    int countOrders(int n) {
+        dp.assign(n + 1, vector<int>(n + 1, -1));
+        dp[n][n] = 1;
+        return dfs(0, 0, n);
+    }
+
+private:
+    int dfs(int picked, int delivered, int n) {
+        if (dp[picked][delivered] != -1) {
+            return dp[picked][delivered];
+        }
+
+        int res = 0;
+        if (picked < n) {
+            res = (res + (n - picked) * 1LL * dfs(picked + 1, delivered, n)) % MOD;
+        }
+        if (delivered < picked) {
+            res = (res + (picked - delivered) * 1LL * dfs(picked, delivered + 1, n)) % MOD;
+        }
+
+        return dp[picked][delivered] = res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number} n
+     * @return {number}
+     */
+    countOrders(n) {
+        const MOD = 1_000_000_007;
+        const dp = Array.from({ length: n + 1 }, () => Array(n + 1).fill(-1));
+
+        const dfs = (picked, delivered) => {
+            if (picked === n && delivered === n) {
+                return 1;
+            }
+            if (dp[picked][delivered] !== -1) {
+                return dp[picked][delivered];
+            }
+
+            let res = 0;
+            if (picked < n) {
+                res = (res + (n - picked) * dfs(picked + 1, delivered)) % MOD;
+            }
+            if (delivered < picked) {
+                res = (res + (picked - delivered) * dfs(picked, delivered + 1)) % MOD;
+            }
+
+            dp[picked][delivered] = res;
+            return res;
+        };
+
+        return dfs(0, 0);
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n ^ 2)$
+* Space complexity: $O(n ^ 2)$
+
+---
+
+## 3. Dynamic Programming (Bottom-Up)
+
+::tabs-start
+
+```python
+class Solution:
+    def countOrders(self, n: int) -> int:
+        MOD = 1000000007
+        dp = [[0] * (n + 1) for _ in range(n + 1)]
+        dp[0][0] = 1
+
+        for picked in range(n + 1):
+            for delivered in range(n + 1):
+                if picked < n:
+                    dp[picked + 1][delivered] = (
+                        (dp[picked + 1][delivered] +
+                        (n - picked) * dp[picked][delivered]) % MOD
+                    )
+
+                if delivered < picked:
+                    dp[picked][delivered + 1] = (
+                        (dp[picked][delivered + 1] +
+                        (picked - delivered) * dp[picked][delivered]) % MOD
+                    )
+
+        return dp[n][n]
+```
+
+```java
+public class Solution {
+    public int countOrders(int n) {
+        final int MOD = 1_000_000_007;
+        int[][] dp = new int[n + 1][n + 1];
+        dp[0][0] = 1;
+
+        for (int picked = 0; picked <= n; picked++) {
+            for (int delivered = 0; delivered <= n; delivered++) {
+                if (picked < n) {
+                    dp[picked + 1][delivered] = (int) ((dp[picked + 1][delivered] + 
+                                                (n - picked) * 1L * dp[picked][delivered]) % MOD);
+                }
+                if (delivered < picked) {
+                    dp[picked][delivered + 1] = (int) ((dp[picked][delivered + 1] + 
+                                                (picked - delivered) * 1L * dp[picked][delivered]) % MOD);
+                }
+            }
+        }
+
+        return dp[n][n];
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int countOrders(int n) {
+        const int MOD = 1'000'000'007;
+        vector<vector<int>> dp(n + 1, vector<int>(n + 1, 0));
+        dp[0][0] = 1;
+
+        for (int picked = 0; picked <= n; picked++) {
+            for (int delivered = 0; delivered <= n; delivered++) {
+                if (picked < n) {
+                    dp[picked + 1][delivered] = (dp[picked + 1][delivered] + 
+                                                (n - picked) * 1LL * dp[picked][delivered]) % MOD;
+                }
+                if (delivered < picked) {
+                    dp[picked][delivered + 1] = (dp[picked][delivered + 1] + 
+                                                (picked - delivered) * 1LL * dp[picked][delivered]) % MOD;
+                }
+            }
+        }
+
+        return dp[n][n];
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number} n
+     * @return {number}
+     */
+    countOrders(n) {
+        const MOD = 1_000_000_007;
+        const dp = Array.from({ length: n + 1 }, () => Array(n + 1).fill(0));
+        dp[0][0] = 1;
+
+        for (let picked = 0; picked <= n; picked++) {
+            for (let delivered = 0; delivered <= n; delivered++) {
+                if (picked < n) {
+                    dp[picked + 1][delivered] = (
+                        (dp[picked + 1][delivered] +
+                        (n - picked) * dp[picked][delivered]) % MOD
+                    );
+                }
+
+                if (delivered < picked) {
+                    dp[picked][delivered + 1] = (
+                        (dp[picked][delivered + 1] + 
+                        (picked - delivered) * dp[picked][delivered]) % MOD
+                    );
+                }
+            }
+        }
+
+        return dp[n][n];
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n ^ 2)$
+* Space complexity: $O(n ^ 2)$
+
+---
+
+## 4. Dynamic Programming (Space Optimized)
+
+::tabs-start
+
+```python
+class Solution:
+    def countOrders(self, n: int) -> int:
+        MOD = 1000000007
+        dp = [0] * (n + 1)
+        dp[0] = 1
+
+        for picked in range(n + 1):
+            for delivered in range(picked):
+                dp[delivered + 1] = (
+                    (dp[delivered + 1] +
+                    (picked - delivered) * dp[delivered]) % MOD
+                )
+
+            if picked < n:
+                next_dp = [0] * (n + 1)
+                for delivered in range(picked + 1):
+                    next_dp[delivered] = (
+                        (next_dp[delivered] +
+                        (n - picked) * dp[delivered]) % MOD
+                    )
+                dp = next_dp
+
+        return dp[n]
+```
+
+```java
+public class Solution {
+    public int countOrders(int n) {
+        int MOD = 1000000007;
+        int[] dp = new int[n + 1];
+        dp[0] = 1;
+
+        for (int picked = 0; picked <= n; picked++) {
+            for (int delivered = 0; delivered < picked; delivered++) {
+                dp[delivered + 1] = (int)((dp[delivered + 1] + 
+                                    (picked - delivered) * 1L * dp[delivered]) % MOD);
+            }
+
+            if (picked < n) {
+                int[] next_dp = new int[n + 1];
+                for (int delivered = 0; delivered <= picked; delivered++) {
+                    next_dp[delivered] = (int)((next_dp[delivered] + 
+                                         (n - picked) *  1L *dp[delivered]) % MOD);
+                }
+                dp = next_dp;
+            }
+        }
+
+        return dp[n];
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int countOrders(int n) {
+        const int MOD = 1000000007;
+        vector<int> dp(n + 1);
+        dp[0] = 1;
+
+        for (int picked = 0; picked <= n; picked++) {
+            for (int delivered = 0; delivered < picked; delivered++) {
+                dp[delivered + 1] = (int)((dp[delivered + 1] + 
+                                    (picked - delivered) * 1LL * dp[delivered]) % MOD);
+            }
+            if (picked < n) {
+                vector<int> next_dp(n + 1);
+                for (int delivered = 0; delivered <= picked; delivered++) {
+                    next_dp[delivered] = (int)((next_dp[delivered] + 
+                                         (n - picked) * 1LL * dp[delivered]) % MOD);
+                }
+                dp = next_dp;
+            }
+        }
+
+        return dp[n];
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number} n
+     * @return {number}
+     */
+    countOrders(n) {
+        const MOD = 1000000007;
+        let dp = new Array(n + 1).fill(0);
+        dp[0] = 1;
+
+        for (let picked = 0; picked <= n; picked++) {
+            for (let delivered = 0; delivered < picked; delivered++) {
+                dp[delivered + 1] = (
+                    (dp[delivered + 1] +
+                    (picked - delivered) * dp[delivered]) % MOD
+                );
+            }
+    
+            if (picked < n) {
+                let next_dp = new Array(n + 1).fill(0);
+                for (let delivered = 0; delivered <= picked; delivered++) {
+                    next_dp[delivered] = (
+                        (next_dp[delivered] +
+                        (n - picked) * dp[delivered]) % MOD
+                    );
+                }
+                dp = next_dp;
+            }
+        }
+
+        return dp[n];
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n ^ 2)$
+* Space complexity: $O(n)$
+
+---
+
+## 5. Combinatorics
+
+::tabs-start
+
+```python
+class Solution:
+    def countOrders(self, n: int) -> int:
+        MOD = 1000000007
+        slots, res = 2 * n, 1
+        while slots > 0:
+            valid_choices = slots * (slots - 1) // 2
+            res = (res * valid_choices) % MOD
+            slots -= 2
+        return res
+```
+
+```java
+public class Solution {
+    public int countOrders(int n) {
+        int MOD = 1000000007;
+        long slots = 2 * n, res = 1;
+
+        while (slots > 0) {
+            long validChoices = slots * (slots - 1) / 2;
+            res = (res * validChoices) % MOD;
+            slots -= 2;
+        }
+        return (int) res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int countOrders(int n) {
+        const int MOD = 1000000007;
+        long long slots = 2 * n, res = 1;
+
+        while (slots > 0) {
+            long long validChoices = slots * (slots - 1) / 2;
+            res = (res * validChoices) % MOD;
+            slots -= 2;
+        }
+        return (int) res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number} n
+     * @return {number}
+     */
+    countOrders(n) {
+        const MOD = 1000000007;
+        let slots = 2 * n, res = 1;
+
+        while (slots > 0) {
+            let validChoices = (slots * (slots - 1)) / 2;
+            res = (res * validChoices) % MOD;
+            slots -= 2;
+        }
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(1)$
+
+---
+
+## 6. Probability
+
+::tabs-start
+
+```python
+class Solution:
+    def countOrders(self, n: int) -> int:
+        MOD = 1000000007
+        res = 1
+
+        for slot in range(1, 2 * n + 1):
+            res  *= slot
+            if slot % 2 == 0:
+                res >>= 1
+            res %= MOD
+
+        return res
+```
+
+```java
+public class Solution {
+    public int countOrders(int n) {
+        int MOD = 1000000007;
+        long res = 1;
+
+        for (int slot = 1; slot <= 2 * n; slot++) {
+            res *= slot;
+            if (slot % 2 == 0) {
+                res >>= 1;
+            }
+            res %= MOD;
+        }
+        return (int) res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int countOrders(int n) {
+        const int MOD = 1000000007;
+        long long res = 1;
+
+        for (int slot = 1; slot <= 2 * n; slot++) {
+            res *= slot;
+            if (slot % 2 == 0) {
+                res >>= 1;
+            }
+            res %= MOD;
+        }
+        return (int) res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number} n
+     * @return {number}
+     */
+    countOrders(n) {
+        const MOD = BigInt(1000000007);
+        let res = BigInt(1);
+
+        for (let slot = 1; slot <= 2 * n; slot++) {
+            res *= BigInt(slot);
+            if (slot % 2 === 0) {
+                res /= BigInt(2);
+            }
+            res %= MOD;
+        }
+        return Number(res);
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(1)$
\ No newline at end of file
diff --git a/articles/maximize-score-after-n-operations.md b/articles/maximize-score-after-n-operations.md
new file mode 100644
index 000000000..bf90e9d55
--- /dev/null
+++ b/articles/maximize-score-after-n-operations.md
@@ -0,0 +1,629 @@
+## 1. Brute Force (Backtracking)
+
+::tabs-start
+
+```python
+class Solution:
+    def maxScore(self, nums: List[int]) -> int:
+        N = len(nums)
+        visit = [False] * N
+
+        def dfs(n):
+            if n > (N // 2):
+                return 0
+
+            res = 0
+            for i in range(N):
+                if visit[i]:
+                    continue
+                visit[i] = True
+                for j in range(i + 1, N):
+                    if visit[j]:
+                        continue
+                    visit[j] = True
+                    g = gcd(nums[i], nums[j])
+                    res = max(res, n * g + dfs(n + 1))
+                    visit[j] = False
+                visit[i] = False
+
+            return res
+
+        return dfs(1)
+```
+
+```java
+public class Solution {
+    public int maxScore(int[] nums) {
+        int N = nums.length;
+        boolean[] visit = new boolean[N];
+        return dfs(nums, visit, 1, N);
+    }
+
+    private int dfs(int[] nums, boolean[] visit, int n, int N) {
+        if (n > N / 2) {
+            return 0;
+        }
+
+        int res = 0;
+        for (int i = 0; i < N; i++) {
+            if (visit[i]) continue;
+            visit[i] = true;
+            for (int j = i + 1; j < N; j++) {
+                if (visit[j]) continue;
+                visit[j] = true;
+                int g = gcd(nums[i], nums[j]);
+                res = Math.max(res, n * g + dfs(nums, visit, n + 1, N));
+                visit[j] = false;
+            }
+            visit[i] = false;
+        }
+
+        return res;
+    }
+
+    private int gcd(int a, int b) {
+        return b == 0 ? a : gcd(b, a % b);
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int maxScore(vector<int>& nums) {
+        int N = nums.size();
+        vector<bool> visit(N, false);
+        return dfs(nums, visit, 1, N);
+    }
+
+private:
+    int dfs(vector<int>& nums, vector<bool>& visit, int n, int N) {
+        if (n > N / 2) {
+            return 0;
+        }
+
+        int res = 0;
+        for (int i = 0; i < N; i++) {
+            if (visit[i]) continue;
+            visit[i] = true;
+            for (int j = i + 1; j < N; j++) {
+                if (visit[j]) continue;
+                visit[j] = true;
+                int g = gcd(nums[i], nums[j]);
+                res = max(res, n * g + dfs(nums, visit, n + 1, N));
+                visit[j] = false;
+            }
+            visit[i] = false;
+        }
+
+        return res;
+    }
+
+    int gcd(int a, int b) {
+        return b == 0 ? a : gcd(b, a % b);
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} nums
+     * @return {number}
+     */
+    maxScore(nums) {
+        const N = nums.length;
+        const visit = new Array(N).fill(false);
+
+        const gcd = (a, b) => {
+            return b === 0 ? a : gcd(b, a % b);
+        };
+        const dfs = (n) => {
+            if (n > N / 2) {
+                return 0;
+            }
+
+            let res = 0;
+            for (let i = 0; i < N; i++) {
+                if (visit[i]) continue;
+                visit[i] = true;
+                for (let j = i + 1; j < N; j++) {
+                    if (visit[j]) continue;
+                    visit[j] = true;
+                    let g = gcd(nums[i], nums[j]);
+                    res = Math.max(res, n * g + dfs(n + 1));
+                    visit[j] = false;
+                }
+                visit[i] = false;
+            }
+
+            return res;
+        };
+
+        return dfs(1);
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n ^ n * \log m)$
+* Space complexity: $O(n)$
+
+> Where $n$ is the size of the array $nums$ and $m$ is the maximum element in the array.
+
+---
+
+## 2. Bitmask DP (Top-Down) - I
+
+::tabs-start
+
+```python
+class Solution:
+    def maxScore(self, nums: List[int]) -> int:
+        cache = collections.defaultdict(int)
+
+        def dfs(mask, op):
+            if mask in cache:
+                return cache[mask]
+
+            for i in range(len(nums)):
+                for j in range(i + 1, len(nums)):
+                    if (1 << i) & mask or (1 << j) & mask:
+                        continue
+
+                    newMask = mask | (1 << i) | (1 << j)
+                    score = op * math.gcd(nums[i], nums[j])
+                    cache[mask] = max(
+                        cache[mask],
+                        score + dfs(newMask, op + 1)
+                    )
+
+            return cache[mask]
+
+        return dfs(0, 1)
+```
+
+```java
+public class Solution {
+    private Map<Integer, Integer> cache;
+
+    public int maxScore(int[] nums) {
+        cache = new HashMap<>();
+        return dfs(0, 1, nums);
+    }
+
+    private int dfs(int mask, int op, int[] nums) {
+        if (cache.containsKey(mask)) {
+            return cache.get(mask);
+        }
+
+        int maxScore = 0;
+        int n = nums.length;
+        for (int i = 0; i < n; i++) {
+            if ((mask & (1 << i)) != 0) continue;
+            for (int j = i + 1; j < n; j++) {
+                if ((mask & (1 << j)) != 0) continue;
+                int newMask = mask | (1 << i) | (1 << j);
+                int score = op * gcd(nums[i], nums[j]) + dfs(newMask, op + 1, nums);
+                maxScore = Math.max(maxScore, score);
+            }
+        }
+
+        cache.put(mask, maxScore);
+        return maxScore;
+    }
+
+    private int gcd(int a, int b) {
+        return b == 0 ? a : gcd(b, a % b);
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int maxScore(vector<int>& nums) {
+        return dfs(0, 1, nums);
+    }
+
+private:
+    unordered_map<int, int> cache;
+
+    int dfs(int mask, int op, vector<int>& nums) {
+        if (cache.count(mask)) {
+            return cache[mask];
+        }
+
+        int maxScore = 0;
+        int n = nums.size();
+        for (int i = 0; i < n; i++) {
+            if ((mask & (1 << i)) != 0) continue;
+            for (int j = i + 1; j < n; j++) {
+                if ((mask & (1 << j)) != 0) continue;
+                int newMask = mask | (1 << i) | (1 << j);
+                int score = op * gcd(nums[i], nums[j]) + dfs(newMask, op + 1, nums);
+                maxScore = max(maxScore, score);
+            }
+        }
+
+        return cache[mask] = maxScore;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} nums
+     * @return {number}
+     */
+    maxScore(nums) {
+        const cache = new Map();
+
+        const gcd = (a, b) => (b === 0 ? a : gcd(b, a % b));
+
+        const dfs = (mask, op) => {
+            if (cache.has(mask)) {
+                return cache.get(mask);
+            }
+
+            let maxScore = 0;
+            const n = nums.length;
+            for (let i = 0; i < n; i++) {
+                if ((mask & (1 << i)) !== 0) continue;
+                for (let j = i + 1; j < n; j++) {
+                    if ((mask & (1 << j)) !== 0) continue;
+                    let newMask = mask | (1 << i) | (1 << j);
+                    let score = op * gcd(nums[i], nums[j]) + dfs(newMask, op + 1);
+                    maxScore = Math.max(maxScore, score);
+                }
+            }
+
+            cache.set(mask, maxScore);
+            return maxScore;
+        };
+
+
+        return dfs(0, 1);
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n ^ 2 * 2 ^ n * \log m)$
+* Space complexity: $O(2 ^ n)$
+
+> Where $n$ is the size of the array $nums$ and $m$ is the maximum element in the array.
+
+---
+
+## 3. Bitmask DP (Top-Down) - II
+
+::tabs-start
+
+```python
+class Solution:
+    def maxScore(self, nums: List[int]) -> int:
+        n = len(nums)
+        GCD = [[0] * n for _ in range(n)]
+        for i in range(n):
+            for j in range(i + 1, n):
+                GCD[i][j] = gcd(nums[i], nums[j])
+
+        dp = [-1] * (1 << n)
+        def dfs(mask, op):
+            if dp[mask] != -1:
+                return dp[mask]
+
+            max_score = 0
+            for i in range(n):
+                if mask & (1 << i): 
+                    continue
+                for j in range(i + 1, n):
+                    if mask & (1 << j): 
+                        continue
+                    new_mask = mask | (1 << i) | (1 << j)
+                    max_score = max(
+                        max_score,
+                        op * GCD[i][j] + dfs(new_mask, op + 1)
+                    )
+
+            dp[mask] = max_score
+            return max_score
+
+        return dfs(0, 1)
+```
+
+```java
+public class Solution {
+    private int[][] GCD;
+    private int[] dp;
+
+    public int maxScore(int[] nums) {
+        int n = nums.length;
+        GCD = new int[n][n];
+        dp = new int[1 << n];
+        Arrays.fill(dp, -1);
+
+        for (int i = 0; i < n; i++) {
+            for (int j = i + 1; j < n; j++) {
+                GCD[i][j] = gcd(nums[i], nums[j]);
+            }
+        }
+
+        return (int) dfs(0, 1, nums);
+    }
+
+    private int dfs(int mask, int op, int[] nums) {
+        if (dp[mask] != -1) return dp[mask];
+
+        int maxScore = 0;
+        for (int i = 0; i < nums.length; i++) {
+            if ((mask & (1 << i)) != 0) continue;
+            for (int j = i + 1; j < nums.length; j++) {
+                if ((mask & (1 << j)) != 0) continue;
+                int newMask = mask | (1 << i) | (1 << j);
+                maxScore = Math.max(
+                    maxScore,
+                    op * GCD[i][j] + dfs(newMask, op + 1, nums)
+                );
+            }
+        }
+        return dp[mask] = maxScore;
+    }
+
+    private int gcd(int a, int b) {
+        return b == 0 ? a : gcd(b, a % b);
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int maxScore(vector<int>& nums) {
+        int n = nums.size();
+        GCD.assign(n, vector<int>(n, 0));
+        dp.assign(1 << n, -1);
+
+        for (int i = 0; i < n; i++) {
+            for (int j = i + 1; j < n; j++) {
+                GCD[i][j] = gcd(nums[i], nums[j]);
+            }
+        }
+
+        return dfs(0, 1, nums);
+    }
+
+private:
+    vector<vector<int>> GCD;
+    vector<int> dp;
+
+    int dfs(int mask, int op, vector<int>& nums) {
+        if (dp[mask] != -1) return dp[mask];
+
+        int maxScore = 0;
+        for (int i = 0; i < nums.size(); i++) {
+            if (mask & (1 << i)) continue;
+            for (int j = i + 1; j < nums.size(); j++) {
+                if (mask & (1 << j)) continue;
+                int newMask = mask | (1 << i) | (1 << j);
+                maxScore = max(
+                    maxScore,
+                    op * GCD[i][j] + dfs(newMask, op + 1, nums)
+                );
+            }
+        }
+        return dp[mask] = maxScore;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} nums
+     * @return {number}
+     */
+    maxScore(nums) {
+        const n = nums.length;
+        const GCD = Array.from({ length: n }, () => Array(n).fill(0));
+        const dp = Array(1 << n).fill(-1);
+
+        const gcd = (a, b) => (b === 0 ? a : gcd(b, a % b));
+        for (let i = 0; i < n; i++) {
+            for (let j = i + 1; j < n; j++) {
+                GCD[i][j] = gcd(nums[i], nums[j]);
+            }
+        }
+
+        const dfs = (mask, op) => {
+            if (dp[mask] !== -1) return dp[mask];
+
+            let maxScore = 0;
+            for (let i = 0; i < n; i++) {
+                if (mask & (1 << i)) continue;
+                for (let j = i + 1; j < n; j++) {
+                    if (mask & (1 << j)) continue;
+                    const newMask = mask | (1 << i) | (1 << j);
+                    maxScore = Math.max(
+                        maxScore,
+                        op * GCD[i][j] + dfs(newMask, op + 1)
+                    );
+                }
+            }
+            return dp[mask] = maxScore;
+        };
+
+        return dfs(0, 1);
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n ^ 2 * (2 ^ n + \log m))$
+* Space complexity: $O(n ^ 2 + 2 ^ n)$
+
+> Where $n$ is the size of the array $nums$ and $m$ is the maximum element in the array.
+
+---
+
+## 4. Bitmask DP (Bottom-Up)
+
+::tabs-start
+
+```python
+class Solution:
+    def maxScore(self, nums: List[int]) -> int:
+        n = len(nums)
+        N = 1 << n
+        GCD = [[0] * n for _ in range(n)]
+        for i in range(n):
+            for j in range(i + 1, n):
+                GCD[i][j] = gcd(nums[i], nums[j])
+
+        dp = [0] * N
+        for mask in range(N - 1, -1, -1):
+            bits = bin(mask).count('1')
+            if bits % 2 == 1:
+                continue
+            op = bits // 2 + 1
+
+            for i in range(n):
+                if mask & (1 << i):
+                    continue
+                for j in range(i + 1, n):
+                    if mask & (1 << j):
+                        continue
+                    new_mask = mask | (1 << i) | (1 << j)
+                    dp[mask] = max(dp[mask], op * GCD[i][j] + dp[new_mask])
+
+        return dp[0]
+```
+
+```java
+public class Solution {
+    public int maxScore(int[] nums) {
+        int n = nums.length;
+        int N = 1 << n;
+        int[][] GCD = new int[n][n];
+
+        for (int i = 0; i < n; i++) {
+            for (int j = i + 1; j < n; j++) {
+                GCD[i][j] = gcd(nums[i], nums[j]);
+            }
+        }
+
+        int[] dp = new int[N];
+        for (int mask = N - 1; mask >= 0; mask--) {
+            int bits = Integer.bitCount(mask);
+            if (bits % 2 == 1) continue;
+            int op = bits / 2 + 1;
+
+            for (int i = 0; i < n; i++) {
+                if ((mask & (1 << i)) != 0) continue;
+                for (int j = i + 1; j < n; j++) {
+                    if ((mask & (1 << j)) != 0) continue;
+                    int newMask = mask | (1 << i) | (1 << j);
+                    dp[mask] = Math.max(dp[mask], op * GCD[i][j] + dp[newMask]);
+                }
+            }
+        }
+        return dp[0];
+    }
+
+    private int gcd(int a, int b) {
+        return b == 0 ? a : gcd(b, a % b);
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int maxScore(vector<int>& nums) {
+        int n = nums.size();
+        int N = 1 << n;
+        vector<vector<int>> GCD(n, vector<int>(n, 0));
+
+        for (int i = 0; i < n; i++) {
+            for (int j = i + 1; j < n; j++) {
+                GCD[i][j] = __gcd(nums[i], nums[j]);
+            }
+        }
+
+        vector<int> dp(N, 0);
+        for (int mask = N - 1; mask >= 0; mask--) {
+            int bits = __builtin_popcount(mask);
+            if (bits % 2 == 1) continue;
+            int op = bits / 2 + 1;
+
+            for (int i = 0; i < n; i++) {
+                if (mask & (1 << i)) continue;
+                for (int j = i + 1; j < n; j++) {
+                    if (mask & (1 << j)) continue;
+                    int newMask = mask | (1 << i) | (1 << j);
+                    dp[mask] = max(dp[mask], op * GCD[i][j] + dp[newMask]);
+                }
+            }
+        }
+        return dp[0];
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {number[]} nums
+     * @return {number}
+     */
+    maxScore(nums) {
+        const n = nums.length;
+        const N = 1 << n;
+        const GCD = Array.from({ length: n }, () => Array(n).fill(0));
+
+        const gcd = (a, b) => (b === 0 ? a : gcd(b, a % b));
+        for (let i = 0; i < n; i++) {
+            for (let j = i + 1; j < n; j++) {
+                GCD[i][j] = gcd(nums[i], nums[j]);
+            }
+        }
+
+        const dp = Array(N).fill(0);
+        for (let mask = N - 1; mask >= 0; mask--) {
+            let bits = mask.toString(2).split("0").join("").length;
+            if (bits % 2 === 1) continue;
+            let op = bits / 2 + 1;
+
+            for (let i = 0; i < n; i++) {
+                if ((mask & (1 << i)) !== 0) continue;
+                for (let j = i + 1; j < n; j++) {
+                    if ((mask & (1 << j)) !== 0) continue;
+                    let newMask = mask | (1 << i) | (1 << j);
+                    dp[mask] = Math.max(dp[mask], op * GCD[i][j] + dp[newMask]);
+                }
+            }
+        }
+        return dp[0];
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n ^ 2 * (2 ^ n + \log m))$
+* Space complexity: $O(n ^ 2 + 2 ^ n)$
+
+> Where $n$ is the size of the array $nums$ and $m$ is the maximum element in the array.
\ No newline at end of file
diff --git a/articles/number-of-ways-to-divide-a-long-corridor.md b/articles/number-of-ways-to-divide-a-long-corridor.md
new file mode 100644
index 000000000..cda191a27
--- /dev/null
+++ b/articles/number-of-ways-to-divide-a-long-corridor.md
@@ -0,0 +1,608 @@
+## 1. Dynamic Programming (Top-Down)
+
+::tabs-start
+
+```python
+class Solution:
+    def numberOfWays(self, corridor: str) -> int:
+        mod = 10**9 + 7
+        cache = [[-1] * 3 for i in range(len(corridor))]  # (i, seats) -> count
+
+        def dfs(i, seats):
+            if i == len(corridor):
+                return 1 if seats == 2 else 0
+            if cache[i][seats] != -1:
+                return cache[i][seats]
+
+            res = 0
+            if seats == 2:
+                if corridor[i] == "S":
+                    res = dfs(i + 1, 1)
+                else:
+                    res = (dfs(i + 1, 0) + dfs(i + 1, 2)) % mod
+            else:
+                if corridor[i] == "S":
+                    res = dfs(i + 1, seats + 1)
+                else:
+                    res = dfs(i + 1, seats)
+
+            cache[i][seats] = res
+            return res
+
+        return dfs(0, 0)
+```
+
+```java
+public class Solution {
+    private static final int MOD = 1_000_000_007;
+    private int[][] dp;
+
+    public int numberOfWays(String corridor) {
+        int n = corridor.length();
+        dp = new int[n][3];
+        for (int i = 0; i < n; i++) {
+            Arrays.fill(dp[i], -1);
+        }
+        return dfs(0, 0, corridor);
+    }
+
+    private int dfs(int i, int seats, String corridor) {
+        if (i == corridor.length()) {
+            return seats == 2 ? 1 : 0;
+        }
+        if (dp[i][seats] != -1) {
+            return dp[i][seats];
+        }
+
+        int res = 0;
+        if (seats == 2) {
+            if (corridor.charAt(i) == 'S') {
+                res = dfs(i + 1, 1, corridor);
+            } else {
+                res = (dfs(i + 1, 0, corridor) + dfs(i + 1, 2, corridor)) % MOD;
+            }
+        } else {
+            if (corridor.charAt(i) == 'S') {
+                res = dfs(i + 1, seats + 1, corridor);
+            } else {
+                res = dfs(i + 1, seats, corridor);
+            }
+        }
+        
+        return dp[i][seats] = res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    static constexpr int MOD = 1'000'000'007;
+    vector<vector<int>> dp;
+
+    int numberOfWays(string corridor) {
+        int n = corridor.size();
+        dp.assign(n, vector<int>(3, -1));
+        return dfs(0, 0, corridor);
+    }
+
+    int dfs(int i, int seats, string& corridor) {
+        if (i == corridor.size()) {
+            return seats == 2 ? 1 : 0;
+        }
+        if (dp[i][seats] != -1) {
+            return dp[i][seats];
+        }
+
+        int res = 0;
+        if (seats == 2) {
+            if (corridor[i] == 'S') {
+                res = dfs(i + 1, 1, corridor);
+            } else {
+                res = (dfs(i + 1, 0, corridor) + dfs(i + 1, 2, corridor)) % MOD;
+            }
+        } else {
+            if (corridor[i] == 'S') {
+                res = dfs(i + 1, seats + 1, corridor);
+            } else {
+                res = dfs(i + 1, seats, corridor);
+            }
+        }
+
+        return dp[i][seats] = res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {string} corridor
+     * @return {number}
+     */
+    numberOfWays(corridor) {
+        const MOD = 1_000_000_007;
+        const n = corridor.length;
+        const dp = Array.from({ length: n }, () => Array(3).fill(-1));
+
+        const dfs = (i, seats) => {
+            if (i === n) return seats === 2 ? 1 : 0;
+            if (dp[i][seats] !== -1) return dp[i][seats];
+
+            let res = 0;
+            if (seats === 2) {
+                if (corridor[i] === 'S') {
+                    res = dfs(i + 1, 1);
+                } else {
+                    res = (dfs(i + 1, 0) + dfs(i + 1, 2)) % MOD;
+                }
+            } else {
+                if (corridor[i] === 'S') {
+                    res = dfs(i + 1, seats + 1);
+                } else {
+                    res = dfs(i + 1, seats);
+                }
+            }
+
+            return (dp[i][seats] = res);
+        };
+
+        return dfs(0, 0);
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(n)$
+
+---
+
+## 2. Dynamic Programming (Bottom-Up)
+
+::tabs-start
+
+```python
+class Solution:
+    def numberOfWays(self, corridor: str) -> int:
+        MOD = 1000000007
+        n = len(corridor)
+        dp = [[0] * 3 for _ in range(n + 1)]
+        dp[n][2] = 1  
+
+        for i in range(n - 1, -1, -1):
+            for seats in range(3):
+                if seats == 2:
+                    if corridor[i] == 'S':
+                        dp[i][seats] = dp[i + 1][1]
+                    else:
+                        dp[i][seats] = (dp[i + 1][0] + dp[i + 1][2]) % MOD
+                else:
+                    if corridor[i] == 'S':
+                        dp[i][seats] = dp[i + 1][seats + 1]
+                    else:
+                        dp[i][seats] = dp[i + 1][seats]
+
+        return dp[0][0]
+```
+
+```java
+public class Solution {
+    public int numberOfWays(String corridor) {
+        int MOD = 1000000007;
+        int n = corridor.length();
+        int[][] dp = new int[n + 1][3];
+        dp[n][2] = 1;
+
+        for (int i = n - 1; i >= 0; i--) {
+            for (int seats = 0; seats < 3; seats++) {
+                if (seats == 2) {
+                    if (corridor.charAt(i) == 'S') {
+                        dp[i][seats] = dp[i + 1][1];
+                    } else {
+                        dp[i][seats] = (dp[i + 1][0] + dp[i + 1][2]) % MOD;
+                    }
+                } else {
+                    if (corridor.charAt(i) == 'S') {
+                        dp[i][seats] = dp[i + 1][seats + 1];
+                    } else {
+                        dp[i][seats] = dp[i + 1][seats];
+                    }
+                }
+            }
+        }
+        return dp[0][0];
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int numberOfWays(string corridor) {
+        int MOD = 1000000007;
+        int n = corridor.size();
+        vector<vector<int>> dp(n + 1, vector<int>(3, 0));
+        dp[n][2] = 1;
+
+        for (int i = n - 1; i >= 0; i--) {
+            for (int seats = 0; seats < 3; seats++) {
+                if (seats == 2) {
+                    if (corridor[i] == 'S') {
+                        dp[i][seats] = dp[i + 1][1];
+                    } else {
+                        dp[i][seats] = (dp[i + 1][0] + dp[i + 1][2]) % MOD;
+                    }
+                } else {
+                    if (corridor[i] == 'S') {
+                        dp[i][seats] = dp[i + 1][seats + 1];
+                    } else {
+                        dp[i][seats] = dp[i + 1][seats];
+                    }
+                }
+            }
+        }
+        return dp[0][0];
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {string} corridor
+     * @return {number}
+     */
+    numberOfWays(corridor) {
+        const MOD = 1000000007;
+        const n = corridor.length;
+        let dp = Array.from({ length: n + 1 }, () => Array(3).fill(0));
+        dp[n][2] = 1;
+
+        for (let i = n - 1; i >= 0; i--) {
+            for (let seats = 0; seats < 3; seats++) {
+                if (seats === 2) {
+                    if (corridor[i] === 'S') {
+                        dp[i][seats] = dp[i + 1][1];
+                    } else {
+                        dp[i][seats] = (dp[i + 1][0] + dp[i + 1][2]) % MOD;
+                    }
+                } else {
+                    if (corridor[i] === 'S') {
+                        dp[i][seats] = dp[i + 1][seats + 1];
+                    } else {
+                        dp[i][seats] = dp[i + 1][seats];
+                    }
+                }
+            }
+        }
+        return dp[0][0];
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(n)$
+
+---
+
+## 3. Dynamic Programming (Space Optimized)
+
+::tabs-start
+
+```python
+class Solution:
+    def numberOfWays(self, corridor: str) -> int:
+        MOD = 1000000007
+        dp = [0, 0, 1]
+
+        for i in reversed(corridor):
+            new_dp = [0] * 3
+            for seats in range(3):
+                if seats == 2:
+                    new_dp[seats] = dp[1] if i == 'S' else (dp[0] + dp[2]) % MOD
+                else:
+                    new_dp[seats] = dp[seats + 1] if i == 'S' else dp[seats]
+            dp = new_dp
+
+        return dp[0]
+```
+
+```java
+public class Solution {
+    public int numberOfWays(String corridor) {
+        int MOD = 1000000007;
+        int[] dp = {0, 0, 1};
+
+        for (int i = corridor.length() - 1; i >= 0; i--) {
+            int[] new_dp = new int[3];
+            for (int seats = 0; seats < 3; seats++) {
+                if (seats == 2) {
+                    new_dp[seats] = corridor.charAt(i) == 'S' ? dp[1] : (dp[0] + dp[2]) % MOD;
+                } else {
+                    new_dp[seats] = corridor.charAt(i) == 'S' ? dp[seats + 1] : dp[seats];
+                }
+            }
+            dp = new_dp;
+        }
+        return dp[0];
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int numberOfWays(string corridor) {
+        const int MOD = 1000000007;
+        vector<int> dp = {0, 0, 1};
+
+        for (int i = corridor.length() - 1; i >= 0; i--) {
+            vector<int> new_dp(3, 0);
+            for (int seats = 0; seats < 3; seats++) {
+                if (seats == 2) {
+                    new_dp[seats] = (corridor[i] == 'S') ? dp[1] : (dp[0] + dp[2]) % MOD;
+                } else {
+                    new_dp[seats] = (corridor[i] == 'S') ? dp[seats + 1] : dp[seats];
+                }
+            }
+            dp = new_dp;
+        }
+        return dp[0];
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {string} corridor
+     * @return {number}
+     */
+    numberOfWays(corridor) {
+        const MOD = 1000000007;
+        let dp = [0, 0, 1];
+
+        for (let i = corridor.length - 1; i >= 0; i--) {
+            let new_dp = [0, 0, 0];
+            for (let seats = 0; seats < 3; seats++) {
+                if (seats === 2) {
+                    new_dp[seats] = corridor[i] === 'S' ? dp[1] : (dp[0] + dp[2]) % MOD;
+                } else {
+                    new_dp[seats] = corridor[i] === 'S' ? dp[seats + 1] : dp[seats];
+                }
+            }
+            dp = new_dp;
+        }
+        return dp[0];
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(1)$
+
+---
+
+## 4. Combinatorics
+
+::tabs-start
+
+```python
+class Solution:
+    def numberOfWays(self, corridor: str) -> int:
+        mod = 10**9 + 7
+        seats = [i for i, c in enumerate(corridor) if c == "S"]
+
+        length = len(seats)
+        if length < 2 or length % 2 == 1:
+            return 0
+
+        res = 1
+        for i in range(1, length - 1, 2):
+            res = (res * (seats[i + 1] - seats[i])) % mod
+
+        return res
+```
+
+```java
+public class Solution {
+    public int numberOfWays(String corridor) {
+        int mod = 1_000_000_007;
+        List<Integer> seats = new ArrayList<>();
+
+        for (int i = 0; i < corridor.length(); i++) {
+            if (corridor.charAt(i) == 'S') {
+                seats.add(i);
+            }
+        }
+
+        int length = seats.size();
+        if (length < 2 || length % 2 == 1) {
+            return 0;
+        }
+
+        long res = 1;
+        for (int i = 1; i < length - 1; i += 2) {
+            res = (res * (seats.get(i + 1) - seats.get(i))) % mod;
+        }
+
+        return (int) res;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int numberOfWays(string corridor) {
+        int mod = 1'000'000'007;
+        vector<int> seats;
+        
+        for (int i = 0; i < corridor.size(); i++) {
+            if (corridor[i] == 'S') {
+                seats.push_back(i);
+            }
+        }
+
+        int length = seats.size();
+        if (length < 2 || length % 2 == 1) {
+            return 0;
+        }
+
+        long long res = 1;
+        for (int i = 1; i < length - 1; i += 2) {
+            res = (res * (seats[i + 1] - seats[i])) % mod;
+        }
+
+        return res;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {string} corridor
+     * @return {number}
+     */
+    numberOfWays(corridor) {
+        const mod = 1_000_000_007;
+        const seats = [];
+
+        for (let i = 0; i < corridor.length; i++) {
+            if (corridor[i] === 'S') {
+                seats.push(i);
+            }
+        }
+
+        const length = seats.length;
+        if (length < 2 || length % 2 === 1) {
+            return 0;
+        }
+
+        let res = 1;
+        for (let i = 1; i < length - 1; i += 2) {
+            res = (res * (seats[i + 1] - seats[i])) % mod;
+        }
+
+        return res;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(n)$
+
+---
+
+## 5. Combinatorics (Optimal)
+
+::tabs-start
+
+```python
+class Solution:
+    def numberOfWays(self, corridor: str) -> int:
+        mod = 1_000_000_007
+        count = 0
+        res = 1
+        prev = -1
+
+        for i, c in enumerate(corridor):
+            if c == 'S':
+                count += 1
+                if count > 2 and count % 2 == 1:
+                    res = (res * (i - prev)) % mod
+                prev = i
+
+        return res if count >= 2 and count % 2 == 0 else 0
+```
+
+```java
+public class Solution {
+    public int numberOfWays(String corridor) {
+        int mod = 1_000_000_007;
+        int count = 0, res = 1, prev = -1;
+
+        for (int i = 0; i < corridor.length(); i++) {
+            if (corridor.charAt(i) == 'S') {
+                count++;
+                if (count > 2 && count % 2 == 1) {
+                    res = (int)((res * (long)(i - prev)) % mod);
+                }
+                prev = i;
+            }
+        }
+
+        return (count >= 2 && count % 2 == 0) ? res : 0;
+    }
+}
+```
+
+```cpp
+class Solution {
+public:
+    int numberOfWays(string corridor) {
+        int mod = 1'000'000'007, count = 0, res = 1, prev = -1;
+
+        for (int i = 0; i < corridor.size(); i++) {
+            if (corridor[i] == 'S') {
+                count++;
+                if (count > 2 && count % 2 == 1) {
+                    res = (1LL * res * (i - prev)) % mod;
+                }
+                prev = i;
+            }
+        }
+
+        return (count >= 2 && count % 2 == 0) ? res : 0;
+    }
+};
+```
+
+```javascript
+class Solution {
+    /**
+     * @param {string} corridor
+     * @return {number}
+     */
+    numberOfWays(corridor) {
+        const mod = 1_000_000_007;
+        let count = 0, res = 1, prev = -1;
+
+        for (let i = 0; i < corridor.length; i++) {
+            if (corridor[i] === 'S') {
+                count++;
+                if (count > 2 && count % 2 === 1) {
+                    res = (res * (i - prev)) % mod;
+                }
+                prev = i;
+            }
+        }
+
+        return count >= 2 && count % 2 === 0 ? res : 0;
+    }
+}
+```
+
+::tabs-end
+
+### Time & Space Complexity
+
+* Time complexity: $O(n)$
+* Space complexity: $O(1)$
\ No newline at end of file
