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