From e3af24d80718b7524c5f13302ed573455b6af173 Mon Sep 17 00:00:00 2001 From: Sri Hari <94112314+Srihari2222@users.noreply.github.com> Date: Wed, 18 Dec 2024 09:37:29 +0530 Subject: [PATCH] Sri Hari: Batch-4/Neetcode-All/Added-articles (#3767) * Batch-4/Neetcode-All/Added-articles * Batch-4/Neetcode-All/Added-articles --- articles/buy-two-chocolates.md | 211 ++++ articles/combinations.md | 456 +++++++ articles/count-sub-islands.md | 564 +++++++++ articles/course-schedule-ii.md | 3 +- articles/course-schedule-iv.md | 705 +++++++++++ articles/extra-characters-in-a-string.md | 1062 +++++++++++++++++ articles/find-eventual-safe-states.md | 308 +++++ articles/find-the-town-judge.md | 199 +++ articles/intersection-of-two-linked-lists.md | 554 +++++++++ articles/island-perimeter.md | 516 ++++++++ articles/maximum-odd-binary-number.md | 264 ++++ articles/merge-in-between-linked-lists.md | 460 +++++++ articles/middle-of-the-linked-list.md | 339 ++++++ articles/open-the-lock.md | 501 ++++++++ articles/palindrome-linked-list.md | 600 ++++++++++ articles/permutations-ii.md | 712 +++++++++++ articles/permutations.md | 10 +- .../remove-duplicates-from-sorted-list.md | 312 +++++ articles/remove-linked-list-elements.md | 514 ++++++++ articles/remove-nodes-from-linked-list.md | 574 +++++++++ ...to-make-all-paths-lead-to-the-city-zero.md | 385 ++++++ articles/restore-ip-addresses.md | 278 +++++ articles/snakes-and-ladders.md | 572 +++++++++ articles/sum-of-all-subset-xor-totals.md | 341 ++++++ articles/verifying-an-alien-dictionary.md | 211 ++++ 25 files changed, 10644 insertions(+), 7 deletions(-) create mode 100644 articles/buy-two-chocolates.md create mode 100644 articles/combinations.md create mode 100644 articles/count-sub-islands.md create mode 100644 articles/course-schedule-iv.md create mode 100644 articles/extra-characters-in-a-string.md create mode 100644 articles/find-eventual-safe-states.md create mode 100644 articles/find-the-town-judge.md create mode 100644 articles/intersection-of-two-linked-lists.md create mode 100644 articles/island-perimeter.md create mode 100644 articles/maximum-odd-binary-number.md create mode 100644 articles/merge-in-between-linked-lists.md create mode 100644 articles/middle-of-the-linked-list.md create mode 100644 articles/open-the-lock.md create mode 100644 articles/palindrome-linked-list.md create mode 100644 articles/permutations-ii.md create mode 100644 articles/remove-duplicates-from-sorted-list.md create mode 100644 articles/remove-linked-list-elements.md create mode 100644 articles/remove-nodes-from-linked-list.md create mode 100644 articles/reorder-routes-to-make-all-paths-lead-to-the-city-zero.md create mode 100644 articles/restore-ip-addresses.md create mode 100644 articles/snakes-and-ladders.md create mode 100644 articles/sum-of-all-subset-xor-totals.md create mode 100644 articles/verifying-an-alien-dictionary.md diff --git a/articles/buy-two-chocolates.md b/articles/buy-two-chocolates.md new file mode 100644 index 000000000..0b6edc79d --- /dev/null +++ b/articles/buy-two-chocolates.md @@ -0,0 +1,211 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def buyChoco(self, prices: List[int], money: int) -> int: + res = -1 + for i in range(len(prices)): + for j in range(i + 1, len(prices)): + if prices[i] + prices[j] <= money: + res = max(res, money - prices[i] - prices[j]) + return res if res != -1 else money +``` + +```java +public class Solution { + public int buyChoco(int[] prices, int money) { + int res = -1; + for (int i = 0; i < prices.length; i++) { + for (int j = i + 1; j < prices.length; j++) { + if (prices[i] + prices[j] <= money) { + res = Math.max(res, money - prices[i] - prices[j]); + } + } + } + return res == -1 ? money : res; + } +} +``` + +```cpp +class Solution { +public: + int buyChoco(vector& prices, int money) { + int res = -1; + for (int i = 0; i < prices.size(); i++) { + for (int j = i + 1; j < prices.size(); j++) { + if (prices[i] + prices[j] <= money) { + res = max(res, money - prices[i] - prices[j]); + } + } + } + return res == -1 ? money : res; + } +}; +``` + +```javascript +class Solution { + buyChoco(prices, money) { + let res = -1; + for (let i = 0; i < prices.length; i++) { + for (let j = i + 1; j < prices.length; j++) { + if (prices[i] + prices[j] <= money) { + res = Math.max(res, money - prices[i] - prices[j]); + } + } + } + return res === -1 ? money : res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(1)$ extra space. + +--- + +## 2. Sorting + +::tabs-start + +```python +class Solution: + def buyChoco(self, prices: List[int], money: int) -> int: + prices.sort() + buy = prices[0] + prices[1] + return money if buy > money else money - buy +``` + +```java +public class Solution { + public int buyChoco(int[] prices, int money) { + Arrays.sort(prices); + int buy = prices[0] + prices[1]; + return buy > money ? money : money - buy; + } +} +``` + +```cpp +class Solution { +public: + int buyChoco(vector& prices, int money) { + sort(prices.begin(), prices.end()); + int buy = prices[0] + prices[1]; + return buy > money ? money : money - buy; + } +}; +``` + +```javascript +class Solution { + buyChoco(prices, money) { + prices.sort((a, b) => a - b); + let buy = prices[0] + prices[1]; + return buy > money ? money : money - buy; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. + +--- + +## 3. Greedy + +::tabs-start + +```python +class Solution: + def buyChoco(self, prices: list[int], money: int) -> int: + min1 = min2 = float('inf') + + for p in prices: + if p < min1: + min1, min2 = p, min1 + elif p < min2: + min2 = p + + leftover = money - min1 - min2 + return leftover if leftover >= 0 else money +``` + +```java +public class Solution { + public int buyChoco(int[] prices, int money) { + int min1 = Integer.MAX_VALUE, min2 = Integer.MAX_VALUE; + + for (int p : prices) { + if (p < min1) { + min2 = min1; + min1 = p; + } else if (p < min2) { + min2 = p; + } + } + + int leftover = money - min1 - min2; + return leftover >= 0 ? leftover : money; + } +} +``` + +```cpp +class Solution { +public: + int buyChoco(vector& prices, int money) { + int min1 = INT_MAX, min2 = INT_MAX; + + for (int p : prices) { + if (p < min1) { + min2 = min1; + min1 = p; + } else if (p < min2) { + min2 = p; + } + } + + int leftover = money - min1 - min2; + return leftover >= 0 ? leftover : money; + } +}; +``` + +```javascript +class Solution { + buyChoco(prices, money) { + let min1 = Infinity, min2 = Infinity; + + for (const p of prices) { + if (p < min1) { + min2 = min1; + min1 = p; + } else if (p < min2) { + min2 = p; + } + } + + const leftover = money - min1 - min2; + return leftover >= 0 ? leftover : money; + } +} +``` + +::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/combinations.md b/articles/combinations.md new file mode 100644 index 000000000..d5e838baf --- /dev/null +++ b/articles/combinations.md @@ -0,0 +1,456 @@ +## 1. Backtracking - I + +::tabs-start + +```python +class Solution: + def combine(self, n: int, k: int) -> List[List[int]]: + res = [] + + def backtrack(i, comb): + if i > n: + if len(comb) == k: + res.append(comb.copy()) + return + + comb.append(i) + backtrack(i + 1, comb) + comb.pop() + backtrack(i + 1, comb) + + backtrack(1, []) + return res +``` + +```java +public class Solution { + private List> res; + + public List> combine(int n, int k) { + res = new ArrayList<>(); + backtrack(1, n, k, new ArrayList<>()); + return res; + } + + private void backtrack(int i, int n, int k, List comb) { + if (i > n) { + if (comb.size() == k) { + res.add(new ArrayList<>(comb)); + } + return; + } + + comb.add(i); + backtrack(i + 1, n, k, comb); + comb.remove(comb.size() - 1); + backtrack(i + 1, n, k, comb); + } +} +``` + +```cpp +class Solution { + vector> res; +public: + vector> combine(int n, int k) { + vector comb; + backtrack(1, n, k, comb); + return res; + } + +private: + void backtrack(int i, int n, int k, vector& comb) { + if (i > n) { + if (comb.size() == k) { + res.push_back(comb); + } + return; + } + + comb.push_back(i); + backtrack(i + 1, n, k, comb); + comb.pop_back(); + backtrack(i + 1, n, k, comb); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number} k + * @return {number[][]} + */ + combine(n, k) { + const res = []; + + const backtrack = (i, comb) => { + if (i > n) { + if (comb.length === k) { + res.push([...comb]); + } + return; + } + + comb.push(i); + backtrack(i + 1, comb); + comb.pop(); + backtrack(i + 1, comb); + }; + + backtrack(1, []); + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(k * \frac {n!}{(n - k)! * k!})$ +* Space complexity: $O(k * \frac {n!}{(n - k)! * k!})$ for the output array. + +> Where $n$ is the number of elements and $k$ is the number of elements to be picked. + +--- + +## 2. Backtracking - II + +::tabs-start + +```python +class Solution: + def combine(self, n: int, k: int) -> List[List[int]]: + res = [] + + def backtrack(start, comb): + if len(comb) == k: + res.append(comb.copy()) + return + + for i in range(start, n + 1): + comb.append(i) + backtrack(i + 1, comb) + comb.pop() + + backtrack(1, []) + return res +``` + +```java +public class Solution { + private List> res; + + public List> combine(int n, int k) { + res = new ArrayList<>(); + backtrack(1, n, k, new ArrayList<>()); + return res; + } + + private void backtrack(int start, int n, int k, List comb) { + if (comb.size() == k) { + res.add(new ArrayList<>(comb)); + return; + } + + for (int i = start; i <= n; i++) { + comb.add(i); + backtrack(i + 1, n, k, comb); + comb.remove(comb.size() - 1); + } + } +} +``` + +```cpp +class Solution { +public: + vector> res; + + vector> combine(int n, int k) { + res.clear(); + vector comb; + backtrack(1, n, k, comb); + return res; + } + + void backtrack(int start, int n, int k, vector& comb) { + if (comb.size() == k) { + res.push_back(comb); + return; + } + + for (int i = start; i <= n; i++) { + comb.push_back(i); + backtrack(i + 1, n, k, comb); + comb.pop_back(); + } + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number} k + * @return {number[][]} + */ + combine(n, k) { + const res = []; + + const backtrack = (start, comb) => { + if (comb.length === k) { + res.push([...comb]); + return; + } + + for (let i = start; i <= n; i++) { + comb.push(i); + backtrack(i + 1, comb); + comb.pop(); + } + }; + + backtrack(1, []); + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(k * \frac {n!}{(n - k)! * k!})$ +* Space complexity: $O(k * \frac {n!}{(n - k)! * k!})$ for the output array. + +> Where $n$ is the number of elements and $k$ is the number of elements to be picked. + +--- + +## 3. Iteration + +::tabs-start + +```python +class Solution: + def combine(self, n: int, k: int) -> List[List[int]]: + res = [] + i = 0 + comb = [0] * k + + while i >= 0: + comb[i] += 1 + if comb[i] > n: + i -= 1 + continue + + if i == k - 1: + res.append(comb.copy()) + else: + i += 1 + comb[i] = comb[i - 1] + + return res +``` + +```java +public class Solution { + public List> combine(int n, int k) { + List> res = new ArrayList<>(); + int[] comb = new int[k]; + int i = 0; + + while (i >= 0) { + comb[i]++; + if (comb[i] > n) { + i--; + continue; + } + + if (i == k - 1) { + List current = new ArrayList<>(); + for (int num : comb) { + current.add(num); + } + res.add(current); + } else { + i++; + comb[i] = comb[i - 1]; + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector> combine(int n, int k) { + vector> res; + vector comb(k, 0); + int i = 0; + + while (i >= 0) { + comb[i]++; + if (comb[i] > n) { + i--; + continue; + } + + if (i == k - 1) { + res.push_back(comb); + } else { + i++; + comb[i] = comb[i - 1]; + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number} k + * @return {number[][]} + */ + combine(n, k) { + const res = []; + const comb = Array(k).fill(0); + let i = 0; + + while (i >= 0) { + comb[i]++; + if (comb[i] > n) { + i--; + continue; + } + + if (i === k - 1) { + res.push([...comb]); + } else { + i++; + comb[i] = comb[i - 1]; + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(k * \frac {n!}{(n - k)! * k!})$ +* Space complexity: $O(k * \frac {n!}{(n - k)! * k!})$ for the output array. + +> Where $n$ is the number of elements and $k$ is the number of elements to be picked. + +--- + +## 4. Bit Manipulation + +::tabs-start + +```python +class Solution: + def combine(self, n: int, k: int) -> List[List[int]]: + res = [] + for mask in range(1 << n): + comb = [] + for bit in range(n): + if mask & (1 << bit): + comb.append(bit + 1) + + if len(comb) == k: + res.append(comb) + return res +``` + +```java +public class Solution { + public List> combine(int n, int k) { + List> res = new ArrayList<>(); + for (int mask = 0; mask < (1 << n); mask++) { + List comb = new ArrayList<>(); + for (int bit = 0; bit < n; bit++) { + if ((mask & (1 << bit)) != 0) { + comb.add(bit + 1); + } + } + if (comb.size() == k) { + res.add(comb); + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + vector> combine(int n, int k) { + vector> res; + for (int mask = 0; mask < (1 << n); ++mask) { + vector comb; + for (int bit = 0; bit < n; ++bit) { + if (mask & (1 << bit)) { + comb.push_back(bit + 1); + } + } + if (comb.size() == k) { + res.push_back(comb); + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number} k + * @return {number[][]} + */ + combine(n, k) { + const res = []; + for (let mask = 0; mask < (1 << n); mask++) { + if (mask.toString(2).split("1").length - 1 !== k) { + continue; + } + + const comb = []; + for (let bit = 0; bit < n; bit++) { + if (mask & (1 << bit)) { + comb.push(bit + 1); + } + } + res.push(comb); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * 2 ^ n)$ +* Space complexity: $O(k * \frac {n!}{(n - k)! * k!})$ for the output array. + +> Where $n$ is the number of elements and $k$ is the number of elements to be picked. \ No newline at end of file diff --git a/articles/count-sub-islands.md b/articles/count-sub-islands.md new file mode 100644 index 000000000..22a7598f7 --- /dev/null +++ b/articles/count-sub-islands.md @@ -0,0 +1,564 @@ +## 1. Depth First Search + +::tabs-start + +```python +class Solution: + def countSubIslands(self, grid1: List[List[int]], grid2: List[List[int]]) -> int: + ROWS, COLS = len(grid1), len(grid1[0]) + visit = set() + + def dfs(r, c): + if (min(r, c) < 0 or r == ROWS or c == COLS or + grid2[r][c] == 0 or (r, c) in visit): + return True + + visit.add((r, c)) + res = grid1[r][c] + + res &= dfs(r - 1, c) + res &= dfs(r + 1, c) + res &= dfs(r, c - 1) + res &= dfs(r, c + 1) + return res + + count = 0 + for r in range(ROWS): + for c in range(COLS): + if grid2[r][c] and (r, c) not in visit: + count += dfs(r, c) + return count +``` + +```java +public class Solution { + private boolean[][] visit; + + public int countSubIslands(int[][] grid1, int[][] grid2) { + int ROWS = grid1.length, COLS = grid1[0].length; + visit = new boolean[ROWS][COLS]; + int count = 0; + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + if (grid2[r][c] == 1 && !visit[r][c] && dfs(r, c, grid1, grid2)) { + count++; + } + } + } + return count; + } + + private boolean dfs(int r, int c, int[][] grid1, int[][] grid2) { + if (r < 0 || c < 0 || r >= grid1.length || c >= grid1[0].length || + grid2[r][c] == 0 || visit[r][c]) { + return true; + } + visit[r][c] = true; + boolean res = grid1[r][c] == 1; + res &= dfs(r - 1, c, grid1, grid2); + res &= dfs(r + 1, c, grid1, grid2); + res &= dfs(r, c - 1, grid1, grid2); + res &= dfs(r, c + 1, grid1, grid2); + return res; + } + +} +``` + +```cpp +class Solution { + vector> visit; + +public: + int countSubIslands(vector>& grid1, vector>& grid2) { + int ROWS = grid1.size(), COLS = grid1[0].size(); + visit.assign(ROWS, vector(COLS, false)); + + int count = 0; + for (int r = 0; r < ROWS; ++r) { + for (int c = 0; c < COLS; ++c) { + if (grid2[r][c] && !visit[r][c]) { + count += dfs(r, c, grid1, grid2); + } + } + } + return count; + } + +private: + bool dfs(int r, int c, vector>& grid1, vector>& grid2) { + if (r < 0 || c < 0 || r >= grid1.size() || c >= grid1[0].size() || + grid2[r][c] == 0 || visit[r][c]) { + return true; + } + + visit[r][c] = true; + bool res = grid1[r][c] == 1; + res &= dfs(r - 1, c, grid1, grid2); + res &= dfs(r + 1, c, grid1, grid2); + res &= dfs(r, c - 1, grid1, grid2); + res &= dfs(r, c + 1, grid1, grid2); + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid1 + * @param {number[][]} grid2 + * @return {number} + */ + countSubIslands(grid1, grid2) { + const ROWS = grid1.length, COLS = grid1[0].length; + const visit = Array.from({ length: ROWS }, () => Array(COLS).fill(false)); + + const dfs = (r, c) => { + if (r < 0 || c < 0 || r >= ROWS || c >= COLS || grid2[r][c] === 0 || visit[r][c]) + return true; + visit[r][c] = true; + let res = grid1[r][c] === 1; + res &= dfs(r - 1, c); + res &= dfs(r + 1, c); + res &= dfs(r, c - 1); + res &= dfs(r, c + 1); + return res; + }; + + let count = 0; + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (grid2[r][c] === 1 && !visit[r][c]) { + if (dfs(r, c)) count++; + } + } + } + return count; + } +} +``` + +::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. + +--- + +## 2. Breadth First Search + +::tabs-start + +```python +class Solution: + def countSubIslands(self, grid1: List[List[int]], grid2: List[List[int]]) -> int: + ROWS, COLS = len(grid1), len(grid1[0]) + visit = [[False] * COLS for _ in range(ROWS)] + directions = [1, 0, -1, 0, 1] + + def bfs(r, c): + queue = deque([(r, c)]) + visit[r][c] = True + res = True + + while queue: + r, c = queue.popleft() + if grid1[r][c] == 0: + res = False + + for i in range(4): + nr, nc = r + directions[i], c + directions[i + 1] + if 0 <= nr < ROWS and 0 <= nc < COLS and not visit[nr][nc] and grid2[nr][nc]: + visit[nr][nc] = True + queue.append((nr, nc)) + return res + + count = 0 + for r in range(ROWS): + for c in range(COLS): + if grid2[r][c] == 1 and not visit[r][c]: + if bfs(r, c): + count += 1 + return count +``` + +```java +public class Solution { + private boolean[][] visit; + private int[] directions = {1, 0, -1, 0, 1}; + + public int countSubIslands(int[][] grid1, int[][] grid2) { + int ROWS = grid1.length, COLS = grid1[0].length; + visit = new boolean[ROWS][COLS]; + int count = 0; + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + if (grid2[r][c] == 1 && !visit[r][c]) { + if (bfs(r, c, grid1, grid2)) { + count++; + } + } + } + } + return count; + } + + private boolean bfs(int r, int c, int[][] grid1, int[][] grid2) { + Queue queue = new LinkedList<>(); + queue.add(new int[]{r, c}); + visit[r][c] = true; + boolean res = true; + + while (!queue.isEmpty()) { + int[] cell = queue.poll(); + int cr = cell[0], cc = cell[1]; + if (grid1[cr][cc] == 0) { + res = false; + } + + for (int i = 0; i < 4; i++) { + int nr = cr + directions[i], nc = cc + directions[i + 1]; + if (nr >= 0 && nr < grid1.length && nc >= 0 && nc < grid1[0].length && + grid2[nr][nc] == 1 && !visit[nr][nc]) { + visit[nr][nc] = true; + queue.add(new int[]{nr, nc}); + } + } + } + return res; + } +} +``` + +```cpp +class Solution { + vector> visit; + vector directions = {1, 0, -1, 0, 1}; + +public: + int countSubIslands(vector>& grid1, vector>& grid2) { + int ROWS = grid1.size(), COLS = grid1[0].size(); + visit.assign(ROWS, vector(COLS, false)); + int count = 0; + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + if (grid2[r][c] == 1 && !visit[r][c]) { + if (bfs(r, c, grid1, grid2)) { + count++; + } + } + } + } + return count; + } + +private: + bool bfs(int r, int c, vector>& grid1, vector>& grid2) { + queue> q; + q.push({r, c}); + visit[r][c] = true; + bool res = true; + + while (!q.empty()) { + auto [cr, cc] = q.front(); q.pop(); + + if (grid1[cr][cc] == 0) res = false; + + for (int i = 0; i < 4; i++) { + int nr = cr + directions[i], nc = cc + directions[i + 1]; + if (nr >= 0 && nr < grid1.size() && nc >= 0 && nc < grid1[0].size() && + grid2[nr][nc] == 1 && !visit[nr][nc]) { + visit[nr][nc] = true; + q.push({nr, nc}); + } + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid1 + * @param {number[][]} grid2 + * @return {number} + */ + countSubIslands(grid1, grid2) { + const ROWS = grid1.length, COLS = grid1[0].length; + const visit = Array.from({ length: ROWS }, () => Array(COLS).fill(false)); + const directions = [1, 0, -1, 0, 1]; + let count = 0; + + const bfs = (sr, sc) => { + const queue = new Queue([[sr, sc]]); + visit[sr][sc] = true; + let res = true; + + while (!queue.isEmpty()) { + const [r, c] = queue.pop(); + if (grid1[r][c] === 0) res = false; + + for (let i = 0; i < 4; i++) { + const nr = r + directions[i], nc = c + directions[i + 1]; + if (nr >= 0 && nr < ROWS && nc >= 0 && nc < COLS && + grid2[nr][nc] === 1 && !visit[nr][nc]) { + visit[nr][nc] = true; + queue.push([nr, nc]); + } + } + } + return res; + }; + + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (grid2[r][c] === 1 && !visit[r][c]) { + if (bfs(r, c)) count++; + } + } + } + return count; + } +} +``` + +::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. + +--- + +## 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 = self.find(u) + pv = self.find(v) + if pu == pv: + return False + if self.Size[pu] < self.Size[pv]: + pu, pv = pv, pu + self.Size[pu] += self.Size[pv] + self.Parent[pv] = pu + return True + +class Solution: + def countSubIslands(self, grid1, grid2): + ROWS, COLS = len(grid1), len(grid1[0]) + N = ROWS * COLS + dsu = DSU(N) + + def getId(r, c): + return r * COLS + c + + land = unions = 0 + for r in range(ROWS): + for c in range(COLS): + if not grid2[r][c]: + continue + land += 1 + if r + 1 < ROWS and grid2[r + 1][c]: + unions += dsu.union(getId(r, c), getId(r + 1, c)) + if c + 1 < COLS and grid2[r][c + 1]: + unions += dsu.union(getId(r, c), getId(r, c + 1)) + if not grid1[r][c]: + unions += dsu.union(getId(r, c), N) + + return land - unions +``` + +```java +class DSU { + int[] Parent, Size; + + DSU(int n) { + Parent = new int[n + 1]; + Size = new int[n + 1]; + for (int i = 0; i <= n; i++) Parent[i] = i; + } + + int find(int node) { + if (Parent[node] != node) Parent[node] = find(Parent[node]); + return Parent[node]; + } + + int union(int u, int v) { + int pu = find(u), pv = find(v); + if (pu == pv) return 0; + if (Size[pu] < Size[pv]) { + int temp = pu; pu = pv; pv = temp; + } + Size[pu] += Size[pv]; + Parent[pv] = pu; + return 1; + } +} + +public class Solution { + public int countSubIslands(int[][] grid1, int[][] grid2) { + int ROWS = grid1.length, COLS = grid1[0].length, N = ROWS * COLS; + DSU dsu = new DSU(N); + + int land = 0, unions = 0; + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + if (grid2[r][c] == 0) continue; + land++; + if (r + 1 < ROWS && grid2[r + 1][c] == 1) + unions += dsu.union(r * COLS + c, (r + 1) * COLS + c); + if (c + 1 < COLS && grid2[r][c + 1] == 1) + unions += dsu.union(r * COLS + c, r * COLS + c + 1); + if (grid1[r][c] == 0) + unions += dsu.union(r * COLS + c, N); + } + } + return land - unions; + } +} +``` + +```cpp +class DSU { + vector Parent, Size; + +public: + DSU(int n) { + Parent.resize(n + 1); + Size.assign(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]) swap(pu, pv); + Size[pu] += Size[pv]; + Parent[pv] = pu; + return true; + } +}; + +class Solution { +public: + int countSubIslands(vector>& grid1, vector>& grid2) { + int ROWS = grid1.size(), COLS = grid1[0].size(), N = ROWS * COLS; + DSU dsu(N); + + int land = 0, unions = 0; + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + if (!grid2[r][c]) continue; + land++; + if (r + 1 < ROWS && grid2[r + 1][c]) + unions += dsu.unionSets(r * COLS + c, (r + 1) * COLS + c); + if (c + 1 < COLS && grid2[r][c + 1]) + unions += dsu.unionSets(r * COLS + c, r * COLS + c + 1); + if (!grid1[r][c]) + unions += dsu.unionSets(r * COLS + c, N); + } + } + return land - unions; + } +}; +``` + +```javascript +class DSU { + constructor(n) { + this.Parent = Array.from({ length: n + 1 }, (_, i) => i); + this.Size = Array(n + 1).fill(1); + } + + /** + * @param {number} node + * @return {number} + */ + find(node) { + if (this.Parent[node] !== node) { + this.Parent[node] = this.find(this.Parent[node]); + } + return this.Parent[node]; + } + + /** + * @param {number} u + * @param {number} v + * @return {boolean} + */ + union(u, v) { + let pu = this.find(u), pv = this.find(v); + if (pu === pv) return false; + if (this.Size[pu] < this.Size[pv]) [pu, pv] = [pv, pu]; + this.Size[pu] += this.Size[pv]; + this.Parent[pv] = pu; + return true; + } +} + +class Solution { + /** + * @param {number[][]} grid1 + * @param {number[][]} grid2 + * @return {number} + */ + countSubIslands(grid1, grid2) { + const ROWS = grid1.length, COLS = grid1[0].length, N = ROWS * COLS; + const dsu = new DSU(N); + + const getId = (r, c) => r * COLS + c; + + let land = 0, unions = 0; + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (grid2[r][c] === 0) continue; + land++; + if (r + 1 < ROWS && grid2[r + 1][c] === 1) + unions += dsu.union(getId(r, c), getId(r + 1, c)); + if (c + 1 < COLS && grid2[r][c + 1] === 1) + unions += dsu.union(getId(r, c), getId(r, c + 1)); + if (grid1[r][c] === 0) + unions += dsu.union(getId(r, c), N); + } + } + return land - unions; + } +} +``` + +::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. \ No newline at end of file diff --git a/articles/course-schedule-ii.md b/articles/course-schedule-ii.md index 2773ec9ae..7980e9e5e 100644 --- a/articles/course-schedule-ii.md +++ b/articles/course-schedule-ii.md @@ -71,8 +71,7 @@ public class Solution { } cycle.add(course); - for (int pre : prereq.getOrDefault(course, - Collections.emptyList())) { + for (int pre : prereq.getOrDefault(course, Collections.emptyList())) { if (!dfs(pre, prereq, visit, cycle, output)) { return false; } diff --git a/articles/course-schedule-iv.md b/articles/course-schedule-iv.md new file mode 100644 index 000000000..0768d9038 --- /dev/null +++ b/articles/course-schedule-iv.md @@ -0,0 +1,705 @@ +## 1. Brute Force (DFS) + +::tabs-start + +```python +class Solution: + def checkIfPrerequisite(self, numCourses: int, prerequisites: List[List[int]], queries: List[List[int]]) -> List[bool]: + adj = [[] for _ in range(numCourses)] + for u, v in prerequisites: + adj[u].append(v) + + def dfs(node, target): + if node == target: + return True + for nei in adj[node]: + if dfs(nei, target): + return True + return False + + res = [] + for u, v in queries: + res.append(dfs(u, v)) + return res +``` + +```java +public class Solution { + private List[] adj; + + public List checkIfPrerequisite(int numCourses, int[][] prerequisites, int[][] queries) { + adj = new ArrayList[numCourses]; + for (int i = 0; i < numCourses; i++) adj[i] = new ArrayList<>(); + for (int[] pre : prerequisites) adj[pre[0]].add(pre[1]); + + List res = new ArrayList<>(); + for (int[] query : queries) { + res.add(dfs(query[0], query[1])); + } + return res; + } + + private boolean dfs(int node, int target) { + if (node == target) return true; + for (int nei : adj[node]) { + if (dfs(nei, target)) return true; + } + return false; + } +} +``` + +```cpp +class Solution { + vector> adj; + +public: + vector checkIfPrerequisite(int numCourses, vector>& prerequisites, vector>& queries) { + adj.assign(numCourses, vector()); + for (auto& pre : prerequisites) { + adj[pre[0]].push_back(pre[1]); + } + + vector res; + for (auto& query : queries) { + res.push_back(dfs(query[0], query[1])); + } + return res; + } + +private: + bool dfs(int node, int target) { + if (node == target) return true; + for (int nei : adj[node]) { + if (dfs(nei, target)) return true; + } + return false; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} numCourses + * @param {number[][]} prerequisites + * @param {number[][]} queries + * @return {boolean[]} + */ + checkIfPrerequisite(numCourses, prerequisites, queries) { + const adj = Array.from({ length: numCourses }, () => []); + for (const [u, v] of prerequisites) { + adj[u].push(v); + } + + const dfs = (node, target) => { + if (node === target) return true; + for (const nei of adj[node]) { + if (dfs(nei, target)) return true; + } + return false; + }; + + const res = []; + for (const [u, v] of queries) { + res.push(dfs(u, v)); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O((V + E) * m)$ +* Space complexity: $O(V + E + m)$ + +> Where $m$ is the number of queries, $V$ is the number of courses, and $E$ is the number of prerequisites. + +--- + +## 2. Depth First Search (Hash Set) + +::tabs-start + +```python +class Solution: + def checkIfPrerequisite(self, numCourses: int, prerequisites: List[List[int]], queries: List[List[int]]) -> List[bool]: + adj = defaultdict(list) + for prereq, crs in prerequisites: + adj[crs].append(prereq) + + def dfs(crs): + if crs not in prereqMap: + prereqMap[crs] = set() + for prereq in adj[crs]: + prereqMap[crs] |= dfs(prereq) + prereqMap[crs].add(crs) + return prereqMap[crs] + + prereqMap = {} + for crs in range(numCourses): + dfs(crs) + + res = [] + for u, v in queries: + res.append(u in prereqMap[v]) + return res +``` + +```java +public class Solution { + private List[] adj; + private Map> prereqMap; + + public List checkIfPrerequisite(int numCourses, int[][] prerequisites, int[][] queries) { + adj = new ArrayList[numCourses]; + prereqMap = new HashMap<>(); + for (int i = 0; i < numCourses; i++) adj[i] = new ArrayList<>(); + for (int[] pre : prerequisites) adj[pre[1]].add(pre[0]); + + for (int crs = 0; crs < numCourses; crs++) dfs(crs); + + List res = new ArrayList<>(); + for (int[] query : queries) { + res.add(prereqMap.get(query[1]).contains(query[0])); + } + return res; + } + + private Set dfs(int crs) { + if (prereqMap.containsKey(crs)) return prereqMap.get(crs); + Set prereqs = new HashSet<>(); + for (int pre : adj[crs]) { + prereqs.addAll(dfs(pre)); + } + prereqs.add(crs); + prereqMap.put(crs, prereqs); + return prereqs; + } +} +``` + +```cpp + +class Solution { + vector> adj; + unordered_map> prereqMap; + +public: + vector checkIfPrerequisite(int numCourses, vector>& prerequisites, vector>& queries) { + adj.assign(numCourses, vector()); + for (auto& pre : prerequisites) { + adj[pre[1]].push_back(pre[0]); + } + for (int crs = 0; crs < numCourses; crs++) { + dfs(crs); + } + + vector res; + for (auto& query : queries) { + res.push_back(prereqMap[query[1]].count(query[0])); + } + return res; + } + +private: + unordered_set& dfs(int crs) { + if (prereqMap.count(crs)) { + return prereqMap[crs]; + } + prereqMap[crs] = unordered_set(); + for (int pre : adj[crs]) { + auto& cur = dfs(pre); + prereqMap[crs].insert(cur.begin(), cur.end()); + } + prereqMap[crs].insert(crs); + return prereqMap[crs]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} numCourses + * @param {number[][]} prerequisites + * @param {number[][]} queries + * @return {boolean[]} + */ + checkIfPrerequisite(numCourses, prerequisites, queries) { + const adj = Array.from({ length: numCourses }, () => []); + const prereqMap = new Map(); + + for (const [pre, crs] of prerequisites) { + adj[crs].push(pre); + } + + + const dfs = (crs) => { + if (prereqMap.has(crs)) { + return prereqMap.get(crs); + } + const prereqs = new Set(); + for (const pre of adj[crs]) { + for (const p of dfs(pre)) prereqs.add(p); + } + prereqs.add(crs); + prereqMap.set(crs, prereqs); + return prereqs; + }; + + for (let crs = 0; crs < numCourses; crs++) { + dfs(crs); + } + return queries.map(([u, v]) => prereqMap.get(v).has(u)); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(V * (V + E) + m)$ +* Space complexity: $O(V ^ 2 + E + m)$ + +> Where $m$ is the number of queries, $V$ is the number of courses, and $E$ is the number of prerequisites. + +--- + +## 3. Depth First Search (Memoization) + +::tabs-start + +```python +class Solution: + def checkIfPrerequisite(self, numCourses: int, prerequisites: List[List[int]], queries: List[List[int]]) -> List[bool]: + adj = [[] for _ in range(numCourses)] + isPrereq = [[-1] * numCourses for _ in range(numCourses)] + for prereq, crs in prerequisites: + adj[crs].append(prereq) + isPrereq[crs][prereq] = True + + def dfs(crs, prereq): + if isPrereq[crs][prereq] != -1: + return isPrereq[crs][prereq] == 1 + + for pre in adj[crs]: + if pre == prereq or dfs(pre, prereq): + isPrereq[crs][prereq] = 1 + return True + + isPrereq[crs][prereq] = 0 + return False + + res = [] + for u, v in queries: + res.append(dfs(v, u)) + return res +``` + +```java +public class Solution { + private List[] adj; + private int[][] isPrereq; + + public List checkIfPrerequisite(int numCourses, int[][] prerequisites, int[][] queries) { + adj = new ArrayList[numCourses]; + isPrereq = new int[numCourses][numCourses]; + for (int i = 0; i < numCourses; i++) { + adj[i] = new ArrayList<>(); + Arrays.fill(isPrereq[i], -1); + } + + for (int[] pre : prerequisites) { + adj[pre[1]].add(pre[0]); + isPrereq[pre[1]][pre[0]] = 1; + } + + List res = new ArrayList<>(); + for (int[] query : queries) { + res.add(dfs(query[1], query[0])); + } + return res; + } + + private boolean dfs(int crs, int prereq) { + if (isPrereq[crs][prereq] != -1) { + return isPrereq[crs][prereq] == 1; + } + for (int pre : adj[crs]) { + if (pre == prereq || dfs(pre, prereq)) { + isPrereq[crs][prereq] = 1; + return true; + } + } + isPrereq[crs][prereq] = 0; + return false; + } +} +``` + +```cpp +class Solution { + vector> adj; + vector> isPrereq; + +public: + vector checkIfPrerequisite(int numCourses, vector>& prerequisites, vector>& queries) { + adj.assign(numCourses, vector()); + isPrereq.assign(numCourses, vector(numCourses, -1)); + + for (auto& pre : prerequisites) { + adj[pre[1]].push_back(pre[0]); + isPrereq[pre[1]][pre[0]] = 1; + } + + vector res; + for (auto& query : queries) { + res.push_back(dfs(query[1], query[0])); + } + return res; + } + +private: + bool dfs(int crs, int prereq) { + if (isPrereq[crs][prereq] != -1) { + return isPrereq[crs][prereq] == 1; + } + for (int pre : adj[crs]) { + if (pre == prereq || dfs(pre, prereq)) { + isPrereq[crs][prereq] = 1; + return true; + } + } + isPrereq[crs][prereq] = 0; + return false; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} numCourses + * @param {number[][]} prerequisites + * @param {number[][]} queries + * @return {boolean[]} + */ + checkIfPrerequisite(numCourses, prerequisites, queries) { + const adj = Array.from({ length: numCourses }, () => []); + const isPrereq = Array.from({ length: numCourses }, () => Array(numCourses).fill(-1)); + for (const [prereq, crs] of prerequisites) { + adj[crs].push(prereq); + isPrereq[crs][prereq] = 1; + } + + const dfs = (crs, prereq) => { + if (isPrereq[crs][prereq] !== -1) { + return isPrereq[crs][prereq] === 1; + } + for (const pre of adj[crs]) { + if (pre === prereq || dfs(pre, prereq)) { + isPrereq[crs][prereq] = 1; + return true; + } + } + isPrereq[crs][prereq] = 0; + return false; + }; + + return queries.map(([u, v]) => dfs(v, u)); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(V * (V + E) + m)$ +* Space complexity: $O(V ^ 2 + E + m)$ + +> Where $m$ is the number of queries, $V$ is the number of courses, and $E$ is the number of prerequisites. + +--- + +## 4. Topological Sort (Kahn's Algorithm) + +::tabs-start + +```python +class Solution: + def checkIfPrerequisite(self, numCourses: int, prerequisites: List[List[int]], queries: List[List[int]]) -> List[bool]: + adj = [set() for _ in range(numCourses)] + indegree = [0] * numCourses + isPrereq = [set() for _ in range(numCourses)] + + for pre, crs in prerequisites: + adj[pre].add(crs) + indegree[crs] += 1 + + q = deque([i for i in range(numCourses) if indegree[i] == 0]) + + while q: + node = q.popleft() + for neighbor in adj[node]: + isPrereq[neighbor].add(node) + isPrereq[neighbor].update(isPrereq[node]) + indegree[neighbor] -= 1 + if indegree[neighbor] == 0: + q.append(neighbor) + + return [u in isPrereq[v] for u, v in queries] +``` + +```java +public class Solution { + public List checkIfPrerequisite(int numCourses, int[][] prerequisites, int[][] queries) { + List> adj = new ArrayList<>(); + List> isPrereq = new ArrayList<>(); + int[] indegree = new int[numCourses]; + for (int i = 0; i < numCourses; i++) { + adj.add(new HashSet<>()); + isPrereq.add(new HashSet<>()); + } + + for (int[] pre : prerequisites) { + adj.get(pre[0]).add(pre[1]); + indegree[pre[1]]++; + } + + Queue q = new LinkedList<>(); + for (int i = 0; i < numCourses; i++) { + if (indegree[i] == 0) q.offer(i); + } + + while (!q.isEmpty()) { + int node = q.poll(); + for (int neighbor : adj.get(node)) { + isPrereq.get(neighbor).add(node); + isPrereq.get(neighbor).addAll(isPrereq.get(node)); + indegree[neighbor]--; + if (indegree[neighbor] == 0) q.offer(neighbor); + } + } + + List res = new ArrayList<>(); + for (int[] query : queries) { + res.add(isPrereq.get(query[1]).contains(query[0])); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + vector checkIfPrerequisite(int numCourses, vector>& prerequisites, vector>& queries) { + vector> adj(numCourses), isPrereq(numCourses); + vector indegree(numCourses, 0); + + for (auto& pre : prerequisites) { + adj[pre[0]].insert(pre[1]); + indegree[pre[1]]++; + } + + queue q; + for (int i = 0; i < numCourses; i++) { + if (indegree[i] == 0) q.push(i); + } + + while (!q.empty()) { + int node = q.front(); q.pop(); + for (int neighbor : adj[node]) { + isPrereq[neighbor].insert(node); + isPrereq[neighbor].insert(isPrereq[node].begin(), isPrereq[node].end()); + indegree[neighbor]--; + if (indegree[neighbor] == 0) q.push(neighbor); + } + } + + vector res; + for (auto& query : queries) { + res.push_back(isPrereq[query[1]].count(query[0])); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} numCourses + * @param {number[][]} prerequisites + * @param {number[][]} queries + * @return {boolean[]} + */ + checkIfPrerequisite(numCourses, prerequisites, queries) { + const adj = Array.from({ length: numCourses }, () => new Set()); + const isPrereq = Array.from({ length: numCourses }, () => new Set()); + const indegree = Array(numCourses).fill(0); + + for (const [pre, crs] of prerequisites) { + adj[pre].add(crs); + indegree[crs]++; + } + + const q = new Queue(); + for (let i = 0; i < numCourses; i++) { + if (indegree[i] === 0) q.push(i); + } + + while (!q.isEmpty()) { + const node = q.pop(); + for (const neighbor of adj[node]) { + isPrereq[neighbor].add(node); + for (const it of isPrereq[node]) { + isPrereq[neighbor].add(it); + } + indegree[neighbor]--; + if (indegree[neighbor] === 0) q.push(neighbor); + } + } + + return queries.map(([u, v]) => isPrereq[v].has(u)); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(V * (V + E) + m)$ +* Space complexity: $O(V ^ 2 + E + m)$ + +> Where $m$ is the number of queries, $V$ is the number of courses, and $E$ is the number of prerequisites. + +--- + +## 5. Floyd Warshall Algorithm + +::tabs-start + +```python +class Solution: + def checkIfPrerequisite(self, numCourses: int, prerequisites: List[List[int]], queries: List[List[int]]) -> List[bool]: + res = [] + adj = [[False] * numCourses for _ in range(numCourses)] + + for pre, crs in prerequisites: + adj[pre][crs] = True + + for k in range(numCourses): + for i in range(numCourses): + for j in range(numCourses): + adj[i][j] = adj[i][j] or (adj[i][k] and adj[k][j]) + + for u, v in queries: + res.append(adj[u][v]) + + return res +``` + +```java +public class Solution { + public List checkIfPrerequisite(int numCourses, int[][] prerequisites, int[][] queries) { + boolean[][] adj = new boolean[numCourses][numCourses]; + List res = new ArrayList<>(); + + for (int[] pre : prerequisites) { + adj[pre[0]][pre[1]] = true; + } + + for (int k = 0; k < numCourses; k++) { + for (int i = 0; i < numCourses; i++) { + for (int j = 0; j < numCourses; j++) { + adj[i][j] = adj[i][j] || (adj[i][k] && adj[k][j]); + } + } + } + + for (int[] q : queries) { + res.add(adj[q[0]][q[1]]); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector checkIfPrerequisite(int numCourses, vector>& prerequisites, vector>& queries) { + vector> adj(numCourses, vector(numCourses, false)); + vector res; + + for (auto& pre : prerequisites) { + adj[pre[0]][pre[1]] = true; + } + + for (int k = 0; k < numCourses; k++) { + for (int i = 0; i < numCourses; i++) { + for (int j = 0; j < numCourses; j++) { + adj[i][j] = adj[i][j] || (adj[i][k] && adj[k][j]); + } + } + } + + for (auto& q : queries) { + res.push_back(adj[q[0]][q[1]]); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} numCourses + * @param {number[][]} prerequisites + * @param {number[][]} queries + * @return {boolean[]} + */ + checkIfPrerequisite(numCourses, prerequisites, queries) { + let adj = Array.from({ length: numCourses }, () => Array(numCourses).fill(false)); + let res = []; + + for (let [pre, crs] of prerequisites) { + adj[pre][crs] = true; + } + + for (let k = 0; k < numCourses; k++) { + for (let i = 0; i < numCourses; i++) { + for (let j = 0; j < numCourses; j++) { + adj[i][j] = adj[i][j] || (adj[i][k] && adj[k][j]); + } + } + } + + for (let [u, v] of queries) { + res.push(adj[u][v]); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(V ^ 3 + E + m)$ +* Space complexity: $O(V ^ 2 + E + m)$ + +> Where $m$ is the number of queries, $V$ is the number of courses, and $E$ is the number of prerequisites. \ No newline at end of file diff --git a/articles/extra-characters-in-a-string.md b/articles/extra-characters-in-a-string.md new file mode 100644 index 000000000..b41af1f45 --- /dev/null +++ b/articles/extra-characters-in-a-string.md @@ -0,0 +1,1062 @@ +## 1. Recursion + +::tabs-start + +```python +class Solution: + def minExtraChar(self, s: str, dictionary: List[str]) -> int: + words = set(dictionary) + + def dfs(i): + if i == len(s): + return 0 + + res = 1 + dfs(i + 1) + for j in range(i, len(s)): + if s[i:j + 1] in words: + res = min(res, dfs(j + 1)) + + return res + + return dfs(0) +``` + +```java +public class Solution { + public int minExtraChar(String s, String[] dictionary) { + Set words = new HashSet<>(); + for (String word : dictionary) { + words.add(word); + } + return dfs(0, s, words); + } + + private int dfs(int i, String s, Set words) { + if (i == s.length()) { + return 0; + } + + int res = 1 + dfs(i + 1, s, words); + for (int j = i; j < s.length(); j++) { + if (words.contains(s.substring(i, j + 1))) { + res = Math.min(res, dfs(j + 1, s, words)); + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int minExtraChar(string s, vector& dictionary) { + unordered_set words(dictionary.begin(), dictionary.end()); + return dfs(0, s, words); + } + +private: + int dfs(int i, const string& s, unordered_set& words) { + if (i == s.size()) { + return 0; + } + + int res = 1 + dfs(i + 1, s, words); + for (int j = i; j < s.size(); j++) { + if (words.count(s.substr(i, j - i + 1))) { + res = min(res, dfs(j + 1, s, words)); + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @param {string[]} dictionary + * @return {number} + */ + minExtraChar(s, dictionary) { + const words = new Set(dictionary); + + const dfs = (i) => { + if (i === s.length) { + return 0; + } + + let res = 1 + dfs(i + 1); + for (let j = i; j < s.length; j++) { + if (words.has(s.slice(i, j + 1))) { + res = Math.min(res, dfs(j + 1)); + } + } + + return res; + }; + + return dfs(0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * 2 ^ n + m * k)$ +* Space complexity: $O(n + m * k)$ + +> Where $n$ is the length of the string $s$, $m$ is the number of words in the dictionary, and $k$ is the average length of a word in the dictionary. + +--- + +## 2. Dynamic Programming (Top-Down) Using Hash Set + +::tabs-start + +```python +class Solution: + def minExtraChar(self, s: str, dictionary: List[str]) -> int: + words = set(dictionary) + dp = {len(s): 0} + + def dfs(i): + if i in dp: + return dp[i] + res = 1 + dfs(i + 1) + for j in range(i, len(s)): + if s[i:j + 1] in words: + res = min(res, dfs(j + 1)) + dp[i] = res + return res + + return dfs(0) +``` + +```java +public class Solution { + public int minExtraChar(String s, String[] dictionary) { + Set words = new HashSet<>(Arrays.asList(dictionary)); + int n = s.length(); + int[] dp = new int[n + 1]; + Arrays.fill(dp, -1); + dp[n] = 0; + + return dfs(0, s, words, dp); + } + + private int dfs(int i, String s, Set words, int[] dp) { + if (dp[i] != -1) return dp[i]; + int res = 1 + dfs(i + 1, s, words, dp); + for (int j = i; j < s.length(); j++) { + if (words.contains(s.substring(i, j + 1))) { + res = Math.min(res, dfs(j + 1, s, words, dp)); + } + } + dp[i] = res; + return res; + } +} +``` + +```cpp +class Solution { +public: + int minExtraChar(string s, vector& dictionary) { + unordered_set words(dictionary.begin(), dictionary.end()); + int n = s.size(); + vector dp(n + 1, -1); + dp[n] = 0; + return dfs(0, s, words, dp); + } + +private: + int dfs(int i, string& s, unordered_set& words, vector& dp) { + if (dp[i] != -1) return dp[i]; + int res = 1 + dfs(i + 1, s, words, dp); + for (int j = i; j < s.size(); j++) { + if (words.count(s.substr(i, j - i + 1))) { + res = min(res, dfs(j + 1, s, words, dp)); + } + } + dp[i] = res; + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @param {string[]} dictionary + * @return {number} + */ + minExtraChar(s, dictionary) { + const words = new Set(dictionary); + const n = s.length; + const dp = new Array(n + 1).fill(-1); + dp[n] = 0; + + const dfs = (i) => { + if (dp[i] !== -1) return dp[i]; + let res = 1 + dfs(i + 1); + for (let j = i; j < n; j++) { + if (words.has(s.slice(i, j + 1))) { + res = Math.min(res, dfs(j + 1)); + } + } + dp[i] = res; + return res; + }; + + return dfs(0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 3 + m * k)$ +* Space complexity: $O(n + m * k)$ + +> Where $n$ is the length of the string $s$, $m$ is the number of words in the dictionary, and $k$ is the average length of a word in the dictionary. + +--- + +## 3. Dynamic Programming (Bottom-Up) Using Hash Set + +::tabs-start + +```python +class Solution: + def minExtraChar(self, s: str, dictionary: List[str]) -> int: + words = set(dictionary) + n = len(s) + dp = [0] * (n + 1) + + for i in range(n - 1, -1, -1): + dp[i] = 1 + dp[i + 1] + for j in range(i, n): + if s[i:j + 1] in words: + dp[i] = min(dp[i], dp[j + 1]) + return dp[0] +``` + +```java +public class Solution { + public int minExtraChar(String s, String[] dictionary) { + Set words = new HashSet<>(Arrays.asList(dictionary)); + int n = s.length(); + int[] dp = new int[n + 1]; + + for (int i = n - 1; i >= 0; i--) { + dp[i] = 1 + dp[i + 1]; + for (int j = i; j < n; j++) { + if (words.contains(s.substring(i, j + 1))) { + dp[i] = Math.min(dp[i], dp[j + 1]); + } + } + } + return dp[0]; + } +} +``` + +```cpp +class Solution { +public: + int minExtraChar(string s, vector& dictionary) { + unordered_set words(dictionary.begin(), dictionary.end()); + int n = s.size(); + vector dp(n + 1, 0); + + for (int i = n - 1; i >= 0; i--) { + dp[i] = 1 + dp[i + 1]; + for (int j = i; j < n; j++) { + if (words.count(s.substr(i, j - i + 1))) { + dp[i] = min(dp[i], dp[j + 1]); + } + } + } + return dp[0]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @param {string[]} dictionary + * @return {number} + */ + minExtraChar(s, dictionary) { + const words = new Set(dictionary); + const n = s.length; + const dp = new Array(n + 1).fill(0); + + for (let i = n - 1; i >= 0; i--) { + dp[i] = 1 + dp[i + 1]; + for (let j = i; j < n; j++) { + if (words.has(s.slice(i, j + 1))) { + dp[i] = Math.min(dp[i], dp[j + 1]); + } + } + } + return dp[0]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 3 + m * k)$ +* Space complexity: $O(n + m * k)$ + +> Where $n$ is the length of the string $s$, $m$ is the number of words in the dictionary, and $k$ is the average length of a word in the dictionary. + +--- + +## 4. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def minExtraChar(self, s: str, dictionary: List[str]) -> int: + dp = {len(s) : 0} + + def dfs(i): + if i in dp: + return dp[i] + + res = 1 + dfs(i + 1) + for word in dictionary: + if i + len(word) > len(s): + continue + + flag = True + for j in range(len(word)): + if s[i + j] != word[j]: + flag = False + break + if flag: + res = min(res, dfs(i + len(word))) + + dp[i] = res + return res + + return dfs(0) +``` + +```java +public class Solution { + public int minExtraChar(String s, String[] dictionary) { + Map dp = new HashMap<>(); + dp.put(s.length(), 0); + return dfs(0, s, dictionary, dp); + } + + private int dfs(int i, String s, String[] dictionary, Map dp) { + if (dp.containsKey(i)) { + return dp.get(i); + } + + int res = 1 + dfs(i + 1, s, dictionary, dp); + for (String word : dictionary) { + if (i + word.length() > s.length()) continue; + + boolean flag = true; + for (int j = 0; j < word.length(); j++) { + if (s.charAt(i + j) != word.charAt(j)) { + flag = false; + break; + } + } + if (flag) { + res = Math.min(res, dfs(i + word.length(), s, dictionary, dp)); + } + } + dp.put(i, res); + return res; + } +} +``` + +```cpp +class Solution { + unordered_map dp; + +public: + int minExtraChar(string s, vector& dictionary) { + dp[s.size()] = 0; + return dfs(0, s, dictionary); + } + +private: + int dfs(int i, string& s, vector& dictionary) { + if (dp.count(i)) { + return dp[i]; + } + + int res = 1 + dfs(i + 1, s, dictionary); + for (const string& word : dictionary) { + if (i + word.size() > s.size()) continue; + + bool flag = true; + for (int j = 0; j < word.size(); j++) { + if (s[i + j] != word[j]) { + flag = false; + break; + } + } + if (flag) { + res = min(res, dfs(i + word.size(), s, dictionary)); + } + } + return dp[i] = res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @param {string[]} dictionary + * @return {number} + */ + minExtraChar(s, dictionary) { + const dp = new Map(); + dp.set(s.length, 0); + + const dfs = (i) => { + if (dp.has(i)) return dp.get(i); + + let res = 1 + dfs(i + 1); + for (const word of dictionary) { + if (i + word.length > s.length) continue; + + let flag = true; + for (let j = 0; j < word.length; j++) { + if (s[i + j] !== word[j]) { + flag = false; + break; + } + } + if (flag) { + res = Math.min(res, dfs(i + word.length)); + } + } + dp.set(i, res); + return res; + }; + + return dfs(0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * m * k)$ +* Space complexity: $O(n)$ + +> Where $n$ is the length of the string $s$, $m$ is the number of words in the dictionary, and $k$ is the average length of a word in the dictionary. + +--- + +## 5. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def minExtraChar(self, s: str, dictionary: List[str]) -> int: + n = len(s) + dp = [0] * (n + 1) + + for i in range(n - 1, -1, -1): + dp[i] = 1 + dp[i + 1] + for word in dictionary: + if i + len(word) <= n and s[i:i + len(word)] == word: + dp[i] = min(dp[i], dp[i + len(word)]) + + return dp[0] +``` + +```java +public class Solution { + public int minExtraChar(String s, String[] dictionary) { + int n = s.length(); + int[] dp = new int[n + 1]; + + for (int i = n - 1; i >= 0; i--) { + dp[i] = 1 + dp[i + 1]; + for (String word : dictionary) { + if (i + word.length() <= n && s.startsWith(word, i)) { + dp[i] = Math.min(dp[i], dp[i + word.length()]); + } + } + } + + return dp[0]; + } +} +``` + +```cpp +class Solution { +public: + int minExtraChar(string s, vector& dictionary) { + int n = s.size(); + vector dp(n + 1, 0); + + for (int i = n - 1; i >= 0; i--) { + dp[i] = 1 + dp[i + 1]; + for (const string& word : dictionary) { + if (i + word.size() <= n && s.substr(i, word.size()) == word) { + dp[i] = min(dp[i], dp[i + word.size()]); + } + } + } + + return dp[0]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @param {string[]} dictionary + * @return {number} + */ + minExtraChar(s, dictionary) { + const n = s.length; + const dp = new Array(n + 1).fill(0); + + for (let i = n - 1; i >= 0; i--) { + dp[i] = 1 + dp[i + 1]; + for (const word of dictionary) { + if (i + word.length <= n && s.slice(i, i + word.length) === word) { + dp[i] = Math.min(dp[i], dp[i + word.length]); + } + } + } + + return dp[0]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * m * k)$ +* Space complexity: $O(n)$ + +> Where $n$ is the length of the string $s$, $m$ is the number of words in the dictionary, and $k$ is the average length of a word in the dictionary. + +--- + +## 6. Dynamic Programming (Top-Down) Using Trie + +::tabs-start + +```python +class TrieNode: + def __init__(self): + self.children = {} + self.isWord = False + +class Trie: + def __init__(self): + self.root = TrieNode() + + def addWord(self, word): + curr = self.root + for c in word: + if c not in curr.children: + curr.children[c] = TrieNode() + curr = curr.children[c] + curr.isWord = True + +class Solution: + def minExtraChar(self, s: str, dictionary: List[str]) -> int: + trie = Trie() + for w in dictionary: + trie.addWord(w) + + dp = {len(s): 0} + + def dfs(i): + if i in dp: + return dp[i] + res = 1 + dfs(i + 1) + curr = trie.root + for j in range(i, len(s)): + if s[j] not in curr.children: + break + curr = curr.children[s[j]] + if curr.isWord: + res = min(res, dfs(j + 1)) + + dp[i] = res + return res + + return dfs(0) +``` + +```java +class TrieNode { + TrieNode[] children; + boolean isWord; + + TrieNode() { + children = new TrieNode[26]; + isWord = false; + } +} + +class Trie { + TrieNode root; + + Trie() { + root = new TrieNode(); + } + + void addWord(String word) { + TrieNode curr = root; + for (char c : word.toCharArray()) { + if (curr.children[c - 'a'] == null) { + curr.children[c - 'a'] = new TrieNode(); + } + curr = curr.children[c - 'a']; + } + curr.isWord = true; + } +} + +public class Solution { + public int minExtraChar(String s, String[] dictionary) { + Trie trie = new Trie(); + for (String word : dictionary) { + trie.addWord(word); + } + + int[] dp = new int[s.length() + 1]; + Arrays.fill(dp, -1); + + return dfs(0, s, trie, dp); + } + + private int dfs(int i, String s, Trie trie, int[] dp) { + if (i == s.length()) return 0; + if (dp[i] != -1) return dp[i]; + + int res = 1 + dfs(i + 1, s, trie, dp); + TrieNode curr = trie.root; + + for (int j = i; j < s.length(); j++) { + if (curr.children[s.charAt(j) - 'a'] == null) break; + curr = curr.children[s.charAt(j) - 'a']; + if (curr.isWord) { + res = Math.min(res, dfs(j + 1, s, trie, dp)); + } + } + + dp[i] = res; + return res; + } +} +``` + +```cpp +class TrieNode { +public: + TrieNode* children[26]; + bool isWord; + + TrieNode() { + for (int i = 0; i < 26; ++i) children[i] = nullptr; + isWord = false; + } +}; + +class Trie { +public: + TrieNode* root; + + Trie() { + root = new TrieNode(); + } + + void addWord(const string& word) { + TrieNode* curr = root; + for (char c : word) { + if (!curr->children[c - 'a']) { + curr->children[c - 'a'] = new TrieNode(); + } + curr = curr->children[c - 'a']; + } + curr->isWord = true; + } +}; + +class Solution { +public: + int minExtraChar(string s, vector& dictionary) { + Trie trie; + for (const string& word : dictionary) { + trie.addWord(word); + } + + vector dp(s.size() + 1, -1); + return dfs(0, s, trie, dp); + } + +private: + int dfs(int i, const string& s, Trie& trie, vector& dp) { + if (i == s.size()) return 0; + if (dp[i] != -1) return dp[i]; + + int res = 1 + dfs(i + 1, s, trie, dp); + TrieNode* curr = trie.root; + + for (int j = i; j < s.size(); ++j) { + if (!curr->children[s[j] - 'a']) break; + curr = curr->children[s[j] - 'a']; + if (curr->isWord) { + res = min(res, dfs(j + 1, s, trie, dp)); + } + } + + dp[i] = res; + return res; + } +}; +``` + +```javascript +class TrieNode { + constructor() { + this.children = {}; + this.isWord = false; + } +} + +class Trie { + constructor() { + this.root = new TrieNode(); + } + + /** + * @param {string} word + * @return {void} + */ + addWord(word) { + let curr = this.root; + for (const c of word) { + if (!curr.children[c]) { + curr.children[c] = new TrieNode(); + } + curr = curr.children[c]; + } + curr.isWord = true; + } +} + +class Solution { + /** + * @param {string} s + * @param {string[]} dictionary + * @return {number} + */ + minExtraChar(s, dictionary) { + const trie = new Trie(); + for (const word of dictionary) { + trie.addWord(word); + } + + const dp = Array(s.length + 1).fill(-1); + + const dfs = (i) => { + if (i === s.length) return 0; + if (dp[i] !== -1) return dp[i]; + + let res = 1 + dfs(i + 1); + let curr = trie.root; + + for (let j = i; j < s.length; j++) { + if (!curr.children[s[j]]) break; + curr = curr.children[s[j]]; + if (curr.isWord) { + res = Math.min(res, dfs(j + 1)); + } + } + + dp[i] = res; + return res; + }; + + return dfs(0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2 + m * k)$ +* Space complexity: $O(n + m * k)$ + +> Where $n$ is the length of the string $s$, $m$ is the number of words in the dictionary, and $k$ is the average length of a word in the dictionary. + +--- + +## 7. Dynamic Programming (Bottom-Up) Using Trie + +::tabs-start + +```python +class TrieNode: + def __init__(self): + self.children = {} + self.isWord = False + +class Trie: + def __init__(self): + self.root = TrieNode() + + def addWord(self, word): + curr = self.root + for c in word: + if c not in curr.children: + curr.children[c] = TrieNode() + curr = curr.children[c] + curr.isWord = True + +class Solution: + def minExtraChar(self, s: str, dictionary: List[str]) -> int: + trie = Trie() + for w in dictionary: + trie.addWord(w) + + n = len(s) + dp = [0] * (n + 1) + + for i in range(n - 1, -1, -1): + dp[i] = 1 + dp[i + 1] + curr = trie.root + for j in range(i, n): + if s[j] not in curr.children: + break + curr = curr.children[s[j]] + if curr.isWord: + dp[i] = min(dp[i], dp[j + 1]) + + return dp[0] +``` + +```java +class TrieNode { + TrieNode[] children; + boolean isWord; + + TrieNode() { + children = new TrieNode[26]; + isWord = false; + } +} + +class Trie { + TrieNode root; + + Trie() { + root = new TrieNode(); + } + + void addWord(String word) { + TrieNode curr = root; + for (char c : word.toCharArray()) { + if (curr.children[c - 'a'] == null) { + curr.children[c - 'a'] = new TrieNode(); + } + curr = curr.children[c - 'a']; + } + curr.isWord = true; + } +} + +public class Solution { + public int minExtraChar(String s, String[] dictionary) { + Trie trie = new Trie(); + for (String word : dictionary) { + trie.addWord(word); + } + + int n = s.length(); + int[] dp = new int[n + 1]; + for (int i = n - 1; i >= 0; i--) { + dp[i] = 1 + dp[i + 1]; + TrieNode curr = trie.root; + + for (int j = i; j < n; j++) { + if (curr.children[s.charAt(j) - 'a'] == null) break; + curr = curr.children[s.charAt(j) - 'a']; + if (curr.isWord) { + dp[i] = Math.min(dp[i], dp[j + 1]); + } + } + } + + return dp[0]; + } +} +``` + +```cpp +class TrieNode { +public: + TrieNode* children[26]; + bool isWord; + + TrieNode() { + for (int i = 0; i < 26; ++i) children[i] = nullptr; + isWord = false; + } +}; + +class Trie { +public: + TrieNode* root; + + Trie() { + root = new TrieNode(); + } + + void addWord(const string& word) { + TrieNode* curr = root; + for (char c : word) { + if (!curr->children[c - 'a']) { + curr->children[c - 'a'] = new TrieNode(); + } + curr = curr->children[c - 'a']; + } + curr->isWord = true; + } +}; + +class Solution { +public: + int minExtraChar(string s, vector& dictionary) { + Trie trie; + for (const string& word : dictionary) { + trie.addWord(word); + } + + int n = s.size(); + vector dp(n + 1); + for (int i = n - 1; i >= 0; --i) { + dp[i] = 1 + dp[i + 1]; + TrieNode* curr = trie.root; + + for (int j = i; j < n; ++j) { + if (!curr->children[s[j] - 'a']) break; + curr = curr->children[s[j] - 'a']; + if (curr->isWord) { + dp[i] = min(dp[i], dp[j + 1]); + } + } + } + + return dp[0]; + } +}; +``` + +```javascript +class TrieNode { + constructor() { + this.children = {}; + this.isWord = false; + } +} + +class Trie { + constructor() { + this.root = new TrieNode(); + } + + /** + * @param {string} word + * @return {void} + */ + addWord(word) { + let curr = this.root; + for (const c of word) { + if (!curr.children[c]) { + curr.children[c] = new TrieNode(); + } + curr = curr.children[c]; + } + curr.isWord = true; + } +} + +class Solution { + /** + * @param {string} s + * @param {string[]} dictionary + * @return {number} + */ + minExtraChar(s, dictionary) { + const trie = new Trie(); + for (const word of dictionary) { + trie.addWord(word); + } + + const n = s.length; + const dp = new Int32Array(n + 1); + for (let i = n - 1; i >= 0; i--) { + dp[i] = 1 + dp[i + 1]; + let curr = trie.root; + + for (let j = i; j < n; j++) { + if (!curr.children[s[j]]) break; + curr = curr.children[s[j]]; + if (curr.isWord) { + dp[i] = Math.min(dp[i], dp[j + 1]); + } + } + } + + return dp[0]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2 + m * k)$ +* Space complexity: $O(n + m * k)$ + +> Where $n$ is the length of the string $s$, $m$ is the number of words in the dictionary, and $k$ is the average length of a word in the dictionary. \ No newline at end of file diff --git a/articles/find-eventual-safe-states.md b/articles/find-eventual-safe-states.md new file mode 100644 index 000000000..df245c8a2 --- /dev/null +++ b/articles/find-eventual-safe-states.md @@ -0,0 +1,308 @@ +## 1. Depth First Search + +::tabs-start + +```python +class Solution: + def eventualSafeNodes(self, graph: List[List[int]]) -> List[int]: + n = len(graph) + safe = {} + + def dfs(node): + if node in safe: + return safe[node] + safe[node] = False + for nei in graph[node]: + if not dfs(nei): + return safe[node] + safe[node] = True + return safe[node] + + res = [] + for node in range(n): + if dfs(node): + res.append(node) + return res +``` + +```java +public class Solution { + private Boolean[] safe; + + public List eventualSafeNodes(int[][] graph) { + int n = graph.length; + safe = new Boolean[n]; + List res = new ArrayList<>(); + for (int node = 0; node < n; node++) { + if (dfs(graph, node)) { + res.add(node); + } + } + return res; + } + + private boolean dfs(int[][] graph, int node) { + if (safe[node] != null) { + return safe[node]; + } + + safe[node] = false; + for (int nei : graph[node]) { + if (!dfs(graph, nei)) { + return false; + } + } + safe[node] = true; + return true; + } +} +``` + +```cpp +class Solution { + vector safe; + +public: + vector eventualSafeNodes(vector>& graph) { + int n = graph.size(); + vector res; + safe.assign(n, -1); + for (int node = 0; node < n; node++) { + if (dfs(graph, node)) { + res.push_back(node); + } + } + return res; + } + +private: + bool dfs(vector>& graph, int node) { + if (safe[node] != -1) { + return safe[node]; + } + safe[node] = 0; + for (int nei : graph[node]) { + if (!dfs(graph, nei)) { + return false; + } + } + safe[node] = 1; + return true; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} graph + * @return {number[]} + */ + eventualSafeNodes(graph) { + const n = graph.length; + const safe = Array(n).fill(undefined); + const res = []; + + const dfs = (node) => { + if (safe[node] !== undefined) { + return safe[node]; + } + safe[node] = false; + for (let nei of graph[node]) { + if (!dfs(nei)) { + return false; + } + } + safe[node] = true; + return true; + }; + + for (let node = 0; node < n; node++) { + if (dfs(node)) { + res.push(node); + } + } + 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 in the given graph. + +--- + +## 2. Topological Sort (Kahn's Algorithm) + +::tabs-start + +```python +class Solution: + def eventualSafeNodes(self, graph: List[List[int]]) -> List[int]: + n = len(graph) + outdegree = [0] * n + parents = [[] for _ in range(n)] + queue = deque() + + for node in range(n): + outdegree[node] = len(graph[node]) + if outdegree[node] == 0: + queue.append(node) + for nei in graph[node]: + parents[nei].append(node) + + while queue: + node = queue.popleft() + for parent in parents[node]: + outdegree[parent] -= 1 + if outdegree[parent] == 0: + queue.append(parent) + + res = [] + for node in range(n): + if outdegree[node] <= 0: + res.append(node) + return res +``` + +```java +public class Solution { + public List eventualSafeNodes(int[][] graph) { + int n = graph.length; + int[] outdegree = new int[n]; + List[] parents = new ArrayList[n]; + Queue queue = new LinkedList<>(); + + for (int i = 0; i < n; i++) { + parents[i] = new ArrayList<>(); + } + + for (int node = 0; node < n; node++) { + outdegree[node] = graph[node].length; + if (outdegree[node] == 0) { + queue.add(node); + } + for (int nei : graph[node]) { + parents[nei].add(node); + } + } + + while (!queue.isEmpty()) { + int node = queue.poll(); + for (int parent : parents[node]) { + outdegree[parent]--; + if (outdegree[parent] == 0) { + queue.add(parent); + } + } + } + + List res = new ArrayList<>(); + for (int node = 0; node < n; node++) { + if (outdegree[node] <= 0) { + res.add(node); + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + vector eventualSafeNodes(vector>& graph) { + int n = graph.size(); + vector outdegree(n, 0); + vector> parents(n); + queue q; + + for (int node = 0; node < n; node++) { + outdegree[node] = graph[node].size(); + if (outdegree[node] == 0) { + q.push(node); + } + for (int nei : graph[node]) { + parents[nei].push_back(node); + } + } + + while (!q.empty()) { + int node = q.front(); + q.pop(); + for (int parent : parents[node]) { + outdegree[parent]--; + if (outdegree[parent] == 0) { + q.push(parent); + } + } + } + + vector res; + for (int node = 0; node < n; node++) { + if (outdegree[node] <= 0) { + res.push_back(node); + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} graph + * @return {number[]} + */ + eventualSafeNodes(graph) { + const n = graph.length; + const outdegree = Array(n).fill(0); + const parents = Array.from({ length: n }, () => []); + const queue = new Queue(); + + for (let node = 0; node < n; node++) { + outdegree[node] = graph[node].length; + if (outdegree[node] === 0) { + queue.push(node); + } + for (let nei of graph[node]) { + parents[nei].push(node); + } + } + + while (!queue.isEmpty()) { + const node = queue.pop(); + for (let parent of parents[node]) { + outdegree[parent]--; + if (outdegree[parent] === 0) { + queue.push(parent); + } + } + } + + const res = []; + for (let node = 0; node < n; node++) { + if (outdegree[node] <= 0) { + res.push(node); + } + } + 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 in the given graph. \ No newline at end of file diff --git a/articles/find-the-town-judge.md b/articles/find-the-town-judge.md new file mode 100644 index 000000000..393448cd8 --- /dev/null +++ b/articles/find-the-town-judge.md @@ -0,0 +1,199 @@ +## 1. Indegree & Outdegree + +::tabs-start + +```python +class Solution: + def findJudge(self, n: int, trust: List[List[int]]) -> int: + incoming = defaultdict(int) + outgoing = defaultdict(int) + + for src, dst in trust: + outgoing[src] += 1 + incoming[dst] += 1 + + for i in range(1, n + 1): + if outgoing[i] == 0 and incoming[i] == n - 1: + return i + + return -1 +``` + +```java +public class Solution { + public int findJudge(int n, int[][] trust) { + int[] incoming = new int[n + 1]; + int[] outgoing = new int[n + 1]; + + for (int[] t : trust) { + outgoing[t[0]]++; + incoming[t[1]]++; + } + + for (int i = 1; i <= n; i++) { + if (outgoing[i] == 0 && incoming[i] == n - 1) { + return i; + } + } + + return -1; + } +} +``` + +```cpp +class Solution { +public: + int findJudge(int n, vector>& trust) { + vector incoming(n + 1, 0), outgoing(n + 1, 0); + + for (auto& t : trust) { + outgoing[t[0]]++; + incoming[t[1]]++; + } + + for (int i = 1; i <= n; i++) { + if (outgoing[i] == 0 && incoming[i] == n - 1) + return i; + } + + return -1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number[][]} trust + * @return {number} + */ + findJudge(n, trust) { + let incoming = new Array(n + 1).fill(0); + let outgoing = new Array(n + 1).fill(0); + + for (let [src, dst] of trust) { + outgoing[src]++; + incoming[dst]++; + } + + for (let i = 1; i <= n; i++) { + if (outgoing[i] === 0 && incoming[i] === n - 1) { + return i; + } + } + + return -1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(V + E)$ +* Space complexity: $O(V)$ + +> Where $V$ is the number of vertices and $E$ is the number of edges. + +--- + +## 2. Indegree & Outdegree (Optimal) + +::tabs-start + +```python +class Solution: + def findJudge(self, n: int, trust: List[List[int]]) -> int: + delta = defaultdict(int) + + for src, dst in trust: + delta[src] -= 1 + delta[dst] += 1 + + for i in range(1, n + 1): + if delta[i] == n - 1: + return i + + return -1 +``` + +```java +public class Solution { + public int findJudge(int n, int[][] trust) { + int[] delta = new int[n + 1]; + + for (int[] t : trust) { + delta[t[0]] -= 1; + delta[t[1]] += 1; + } + + for (int i = 1; i <= n; i++) { + if (delta[i] == n - 1) { + return i; + } + } + + return -1; + } +} +``` + +```cpp +class Solution { +public: + int findJudge(int n, vector>& trust) { + vector delta(n + 1, 0); + + for (auto& t : trust) { + delta[t[0]]--; + delta[t[1]]++; + } + + for (int i = 1; i <= n; i++) { + if (delta[i] == n - 1) { + return i; + } + } + + return -1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number[][]} trust + * @return {number} + */ + findJudge(n, trust) { + let delta = new Array(n + 1).fill(0); + + for (let [src, dst] of trust) { + delta[src]--; + delta[dst]++; + } + + for (let i = 1; i <= n; i++) { + if (delta[i] === n - 1) { + return i; + } + } + + return -1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(V + E)$ +* Space complexity: $O(V)$ + +> Where $V$ is the number of vertices and $E$ is the number of edges. \ No newline at end of file diff --git a/articles/intersection-of-two-linked-lists.md b/articles/intersection-of-two-linked-lists.md new file mode 100644 index 000000000..855f2a43f --- /dev/null +++ b/articles/intersection-of-two-linked-lists.md @@ -0,0 +1,554 @@ +## 1. Brute Force + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, x): +# self.val = x +# self.next = None +class Solution: + def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> Optional[ListNode]: + while headA: + cur = headB + while cur: + if headA == cur: + return headA + cur = cur.next + headA = headA.next + return None +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { + * val = x; + * next = null; + * } + * } + */ +public class Solution { + public ListNode getIntersectionNode(ListNode headA, ListNode headB) { + while (headA != null) { + ListNode cur = headB; + while (cur != null) { + if (headA == cur) { + return headA; + } + cur = cur.next; + } + headA = headA.next; + } + return null; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + ListNode* getIntersectionNode(ListNode* headA, ListNode* headB) { + while (headA) { + ListNode* cur = headB; + while (cur) { + if (headA == cur) { + return headA; + } + cur = cur->next; + } + headA = headA->next; + } + return nullptr; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} headA + * @param {ListNode} headB + * @return {ListNode} + */ + getIntersectionNode(headA, headB) { + while (headA) { + let cur = headB; + while (cur) { + if (headA === cur) { + return headA; + } + cur = cur.next; + } + headA = headA.next; + } + return null; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * n)$ +* Space complexity: $O(1)$ extra space. + +> Where $m$ is the length of the first list and $n$ is the length of the second list. + +--- + +## 2. Hash Set + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, x): +# self.val = x +# self.next = None +class Solution: + def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> Optional[ListNode]: + nodeSet = set() + cur = headA + while cur: + nodeSet.add(cur) + cur = cur.next + + cur = headB + while cur: + if cur in nodeSet: + return cur + cur = cur.next + + return None +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { + * val = x; + * next = null; + * } + * } + */ +public class Solution { + public ListNode getIntersectionNode(ListNode headA, ListNode headB) { + HashSet nodeSet = new HashSet<>(); + + ListNode cur = headA; + while (cur != null) { + nodeSet.add(cur); + cur = cur.next; + } + + cur = headB; + while (cur != null) { + if (nodeSet.contains(cur)) { + return cur; + } + cur = cur.next; + } + + return null; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + ListNode* getIntersectionNode(ListNode* headA, ListNode* headB) { + unordered_set nodeSet; + + ListNode* cur = headA; + while (cur) { + nodeSet.insert(cur); + cur = cur->next; + } + + cur = headB; + while (cur) { + if (nodeSet.find(cur) != nodeSet.end()) { + return cur; + } + cur = cur->next; + } + + return nullptr; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} headA + * @param {ListNode} headB + * @return {ListNode} + */ + getIntersectionNode(headA, headB) { + const nodeSet = new Set(); + + let cur = headA; + while (cur) { + nodeSet.add(cur); + cur = cur.next; + } + + cur = headB; + while (cur) { + if (nodeSet.has(cur)) { + return cur; + } + cur = cur.next; + } + + return null; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m + n)$ +* Space complexity: $O(m)$ + +> Where $m$ is the length of the first list and $n$ is the length of the second list. + +--- + +## 3. Two Pointers - I + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, x): +# self.val = x +# self.next = None +class Solution: + def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> Optional[ListNode]: + def getLength(head): + length, cur = 0, head + while cur: + length += 1 + cur = cur.next + return length + + m = getLength(headA) + n = getLength(headB) + l1, l2 = headA, headB + + if m < n: + m, n = n, m + l1, l2 = headB, headA + + while m - n: + m -= 1 + l1 = l1.next + + while l1 != l2: + l1 = l1.next + l2 = l2.next + + return l1 +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { + * val = x; + * next = null; + * } + * } + */ +public class Solution { + private int getLength(ListNode head) { + int length = 0; + while (head != null) { + length++; + head = head.next; + } + return length; + } + + public ListNode getIntersectionNode(ListNode headA, ListNode headB) { + int m = getLength(headA); + int n = getLength(headB); + ListNode l1 = headA, l2 = headB; + + if (m < n) { + int temp = m; m = n; n = temp; + ListNode tempNode = l1; l1 = l2; l2 = tempNode; + } + + while (m > n) { + l1 = l1.next; + m--; + } + + while (l1 != null && l1 != l2) { + l1 = l1.next; + l2 = l2.next; + } + + return l1; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { + int getLength(ListNode* head) { + int length = 0; + while (head) { + length++; + head = head->next; + } + return length; + } + +public: + ListNode* getIntersectionNode(ListNode* headA, ListNode* headB) { + int m = getLength(headA), n = getLength(headB); + ListNode* l1 = headA, *l2 = headB; + + if (m < n) { + swap(m, n); + swap(l1, l2); + } + + while (m-- > n) { + l1 = l1->next; + } + + while (l1 && l1 != l2) { + l1 = l1->next; + l2 = l2->next; + } + + return l1; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} headA + * @param {ListNode} headB + * @return {ListNode} + */ + getIntersectionNode(headA, headB) { + const getLength = (head) => { + let length = 0, cur = head; + while (cur) { + length++; + cur = cur.next; + } + return length; + }; + + let m = getLength(headA); + let n = getLength(headB); + let l1 = headA, l2 = headB; + + if (m < n) { + [m, n] = [n, m]; + [l1, l2] = [l2, l1]; + } + + while (m-- > n) { + l1 = l1.next; + } + + while (l1 && l1 !== l2) { + l1 = l1.next; + l2 = l2.next; + } + + return l1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m + n)$ +* Space complexity: $O(1)$ extra space. + +> Where $m$ is the length of the first list and $n$ is the length of the second list. + +--- + +## 4. Two Pointers - II + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, x): +# self.val = x +# self.next = None +class Solution: + def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> Optional[ListNode]: + l1, l2 = headA, headB + while l1 != l2: + l1 = l1.next if l1 else headB + l2 = l2.next if l2 else headA + return l1 +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { + * val = x; + * next = null; + * } + * } + */ +public class Solution { + public ListNode getIntersectionNode(ListNode headA, ListNode headB) { + ListNode l1 = headA, l2 = headB; + while (l1 != l2) { + l1 = (l1 != null) ? l1.next : headB; + l2 = (l2 != null) ? l2.next : headA; + } + return l1; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + ListNode* getIntersectionNode(ListNode* headA, ListNode* headB) { + ListNode* l1 = headA; + ListNode* l2 = headB; + while (l1 != l2) { + l1 = l1 ? l1->next : headB; + l2 = l2 ? l2->next : headA; + } + return l1; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} headA + * @param {ListNode} headB + * @return {ListNode} + */ + getIntersectionNode(headA, headB) { + let l1 = headA, l2 = headB; + while (l1 !== l2) { + l1 = l1 ? l1.next : headB; + l2 = l2 ? l2.next : headA; + } + return l1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m + n)$ +* Space complexity: $O(1)$ extra space. + +> Where $m$ is the length of the first list and $n$ is the length of the second list. \ No newline at end of file diff --git a/articles/island-perimeter.md b/articles/island-perimeter.md new file mode 100644 index 000000000..c4bb78ca5 --- /dev/null +++ b/articles/island-perimeter.md @@ -0,0 +1,516 @@ +## 1. Depth First Search + +::tabs-start + +```python +class Solution: + def islandPerimeter(self, grid: List[List[int]]) -> int: + rows, cols = len(grid), len(grid[0]) + visit = set() + + def dfs(i, j): + if i < 0 or j < 0 or i >= rows or j >= cols or grid[i][j] == 0: + return 1 + if (i, j) in visit: + return 0 + + visit.add((i, j)) + perim = dfs(i, j + 1) + dfs(i + 1, j) + dfs(i, j - 1) + dfs(i - 1, j) + return perim + + for i in range(rows): + for j in range(cols): + if grid[i][j]: + return dfs(i, j) + return 0 +``` + +```java +public class Solution { + private int[][] grid; + private boolean[][] visited; + private int rows, cols; + + public int islandPerimeter(int[][] grid) { + this.grid = grid; + this.rows = grid.length; + this.cols = grid[0].length; + this.visited = new boolean[rows][cols]; + + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + if (grid[i][j] == 1) { + return dfs(i, j); + } + } + } + return 0; + } + + private int dfs(int i, int j) { + if (i < 0 || j < 0 || i >= rows || + j >= cols || grid[i][j] == 0) { + return 1; + } + if (visited[i][j]) { + return 0; + } + + visited[i][j] = true; + return dfs(i, j + 1) + dfs(i + 1, j) + + dfs(i, j - 1) + dfs(i - 1, j); + } +} +``` + +```cpp +class Solution { +private: + vector> grid; + vector> visited; + int rows, cols; + + int dfs(int i, int j) { + if (i < 0 || j < 0 || i >= rows || + j >= cols || grid[i][j] == 0) { + return 1; + } + if (visited[i][j]) { + return 0; + } + + visited[i][j] = true; + return dfs(i, j + 1) + dfs(i + 1, j) + + dfs(i, j - 1) + dfs(i - 1, j); + } + +public: + int islandPerimeter(vector>& grid) { + this->grid = grid; + rows = grid.size(); + cols = grid[0].size(); + visited = vector>(rows, vector(cols, false)); + + for (int i = 0; i < rows; ++i) { + for (int j = 0; j < cols; ++j) { + if (grid[i][j] == 1) { + return dfs(i, j); + } + } + } + return 0; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + islandPerimeter(grid) { + const rows = grid.length, cols = grid[0].length; + const visited = Array.from({ length: rows }, () => Array(cols).fill(false)); + + const dfs = (i, j) => { + if (i < 0 || j < 0 || i >= rows || j >= cols || grid[i][j] === 0) { + return 1; + } + if (visited[i][j]) { + return 0; + } + + visited[i][j] = true; + return dfs(i, j + 1) + dfs(i + 1, j) + + dfs(i, j - 1) + dfs(i - 1, j); + }; + + for (let i = 0; i < rows; i++) { + for (let j = 0; j < cols; j++) { + if (grid[i][j] === 1) { + return dfs(i, j); + } + } + } + return 0; + } +} +``` + +::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 grid. + +--- + +## 2. Breadth First Search + +::tabs-start + +```python +class Solution: + def islandPerimeter(self, grid: List[List[int]]) -> int: + rows, cols = len(grid), len(grid[0]) + visited = set() + directions = [(0, 1), (1, 0), (0, -1), (-1, 0)] + + def bfs(r, c): + queue = deque([(r, c)]) + visited.add((r, c)) + perimeter = 0 + + while queue: + x, y = queue.popleft() + for dx, dy in directions: + nx, ny = x + dx, y + dy + if (nx < 0 or ny < 0 or nx >= rows or + ny >= cols or grid[nx][ny] == 0 + ): + perimeter += 1 + elif (nx, ny) not in visited: + visited.add((nx, ny)) + queue.append((nx, ny)) + return perimeter + + for i in range(rows): + for j in range(cols): + if grid[i][j] == 1: + return bfs(i, j) + return 0 +``` + +```java +public class Solution { + public int islandPerimeter(int[][] grid) { + int rows = grid.length, cols = grid[0].length; + boolean[][] visited = new boolean[rows][cols]; + int[][] directions = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; + + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + if (grid[i][j] == 1) { + Queue queue = new LinkedList<>(); + queue.offer(new int[]{i, j}); + visited[i][j] = true; + int perimeter = 0; + + while (!queue.isEmpty()) { + int[] cell = queue.poll(); + int x = cell[0], y = cell[1]; + + for (int[] dir : directions) { + int nx = x + dir[0], ny = y + dir[1]; + if (nx < 0 || ny < 0 || nx >= rows || + ny >= cols || grid[nx][ny] == 0) { + perimeter++; + } else if (!visited[nx][ny]) { + visited[nx][ny] = true; + queue.offer(new int[]{nx, ny}); + } + } + } + return perimeter; + } + } + } + return 0; + } +} +``` + +```cpp +class Solution { +public: + int islandPerimeter(vector>& grid) { + int rows = grid.size(), cols = grid[0].size(); + vector> visited(rows, vector(cols, false)); + int directions[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; + + for (int i = 0; i < rows; ++i) { + for (int j = 0; j < cols; ++j) { + if (grid[i][j] == 1) { + queue> q; + q.push({i, j}); + visited[i][j] = true; + int perimeter = 0; + + while (!q.empty()) { + auto [x, y] = q.front(); + q.pop(); + + for (auto& dir : directions) { + int nx = x + dir[0], ny = y + dir[1]; + if (nx < 0 || ny < 0 || nx >= rows || + ny >= cols || grid[nx][ny] == 0) { + perimeter++; + } else if (!visited[nx][ny]) { + visited[nx][ny] = true; + q.push({nx, ny}); + } + } + } + return perimeter; + } + } + } + return 0; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + islandPerimeter(grid) { + const rows = grid.length, cols = grid[0].length; + const visited = Array.from({ length: rows }, () => Array(cols).fill(false)); + const directions = [[0, 1], [1, 0], [0, -1], [-1, 0]]; + + const bfs = (r, c) => { + const queue = new Queue([[r, c]]); + visited[r][c] = true; + let perimeter = 0; + while (!queue.isEmpty()) { + const [x, y] = queue.pop(); + + for (const [dx, dy] of directions) { + const nx = x + dx, ny = y + dy; + + if (nx < 0 || ny < 0 || nx >= rows || + ny >= cols || grid[nx][ny] === 0) { + perimeter++; + } else if (!visited[nx][ny]) { + visited[nx][ny] = true; + queue.push([nx, ny]); + } + } + } + return perimeter; + }; + + for (let i = 0; i < rows; i++) { + for (let j = 0; j < cols; j++) { + if (grid[i][j] === 1) { + return bfs(i, j); + } + } + } + return 0; + } +} +``` + +::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 grid. + +--- + +## 3. Iteration - I + +::tabs-start + +```python +class Solution: + def islandPerimeter(self, grid: List[List[int]]) -> int: + m, n, res = len(grid), len(grid[0]), 0 + for i in range(m): + for j in range(n): + if grid[i][j] == 1: + res += (i + 1 >= m or grid[i + 1][j] == 0) + res += (j + 1 >= n or grid[i][j + 1] == 0) + res += (i - 1 < 0 or grid[i - 1][j] == 0) + res += (j - 1 < 0 or grid[i][j - 1] == 0) + return res +``` + +```java +public class Solution { + public int islandPerimeter(int[][] grid) { + int m = grid.length, n = grid[0].length, res = 0; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (grid[i][j] == 1) { + res += (i + 1 >= m || grid[i + 1][j] == 0) ? 1 : 0; + res += (j + 1 >= n || grid[i][j + 1] == 0) ? 1 : 0; + res += (i - 1 < 0 || grid[i - 1][j] == 0) ? 1 : 0; + res += (j - 1 < 0 || grid[i][j - 1] == 0) ? 1 : 0; + } + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int islandPerimeter(vector>& grid) { + int m = grid.size(), n = grid[0].size(), res = 0; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (grid[i][j] == 1) { + res += (i + 1 >= m || grid[i + 1][j] == 0) ? 1 : 0; + res += (j + 1 >= n || grid[i][j + 1] == 0) ? 1 : 0; + res += (i - 1 < 0 || grid[i - 1][j] == 0) ? 1 : 0; + res += (j - 1 < 0 || grid[i][j - 1] == 0) ? 1 : 0; + } + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + islandPerimeter(grid) { + const m = grid.length, n = grid[0].length; + let res = 0; + for (let i = 0; i < m; i++) { + for (let j = 0; j < n; j++) { + if (grid[i][j] === 1) { + res += (i + 1 >= m || grid[i + 1][j] === 0) ? 1 : 0; + res += (j + 1 >= n || grid[i][j + 1] === 0) ? 1 : 0; + res += (i - 1 < 0 || grid[i - 1][j] === 0) ? 1 : 0; + res += (j - 1 < 0 || grid[i][j - 1] === 0) ? 1 : 0; + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * n)$ +* Space complexity: $O(1)$ extra space. + +> Where $m$ is the number of rows and $n$ is the number of columns in the grid. + +--- + +## 4. Iteration - II + +::tabs-start + +```python +class Solution: + def islandPerimeter(self, grid: List[List[int]]) -> int: + m, n = len(grid), len(grid[0]) + res = 0 + for r in range(m): + for c in range(n): + if grid[r][c] == 1: + res += 4 + if r and grid[r - 1][c]: + res -= 2 + if c and grid[r][c - 1] == 1: + res -= 2 + return res +``` + +```java +public class Solution { + public int islandPerimeter(int[][] grid) { + int m = grid.length, n = grid[0].length; + int res = 0;; + for (int r = 0; r < m; r++) { + for (int c = 0; c < n; c++) { + if (grid[r][c] == 1) { + res += 4; + if (r > 0 && grid[r - 1][c] == 1) { + res -= 2; + } + if (c > 0 && grid[r][c - 1] == 1) { + res -= 2; + } + } + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int islandPerimeter(vector>& grid) { + int m = grid.size(), n = grid[0].size(); + int res = 0; + for (int r = 0; r < m; r++) { + for (int c = 0; c < n; c++) { + if (grid[r][c]) { + res += 4; + if (r && grid[r - 1][c]) { + res -= 2; + } + if (c && grid[r][c - 1]) { + res -= 2; + } + } + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + islandPerimeter(grid) { + const m = grid.length, n = grid[0].length; + let res = 0; + for (let r = 0; r < m; r++) { + for (let c = 0; c < n; c++) { + if (grid[r][c] == 1) { + res += 4; + if (r > 0 && grid[r - 1][c] == 1) { + res -= 2; + } + if (c > 0 && grid[r][c - 1] == 1) { + res -= 2; + } + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * n)$ +* Space complexity: $O(1)$ extra space. + +> Where $m$ is the number of rows and $n$ is the number of columns in the grid. \ No newline at end of file diff --git a/articles/maximum-odd-binary-number.md b/articles/maximum-odd-binary-number.md new file mode 100644 index 000000000..41846d673 --- /dev/null +++ b/articles/maximum-odd-binary-number.md @@ -0,0 +1,264 @@ +## 1. Sorting + +::tabs-start + +```python +class Solution: + def maximumOddBinaryNumber(self, s: str) -> str: + s = sorted(s) + s.reverse() + i = len(s) - 1 + while i >= 0 and s[i] == "0": + i -= 1 + + s[i], s[len(s) - 1] = s[len(s) - 1], s[i] + return ''.join(s) +``` + +```java +public class Solution { + public String maximumOddBinaryNumber(String s) { + char[] arr = s.toCharArray(); + Arrays.sort(arr); + reverse(arr); + + int n = arr.length; + int i = n - 1; + + while (i >= 0 && arr[i] == '0') { + i--; + } + + char temp = arr[i]; + arr[i] = arr[n - 1]; + arr[n - 1] = temp; + + return new String(arr); + } + + private void reverse(char[] arr) { + int left = 0, right = arr.length - 1; + while (left < right) { + char temp = arr[left]; + arr[left++] = arr[right]; + arr[right--] = temp; + } + } +} +``` + +```cpp +class Solution { +public: + string maximumOddBinaryNumber(string s) { + sort(s.begin(), s.end(), greater()); + + int n = s.size(), i = n - 1; + while (i >= 0 && s[i] == '0') { + i--; + } + + swap(s[i], s[n - 1]); + return s; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {string} + */ + maximumOddBinaryNumber(s) { + let arr = s.split(''); + arr.sort().reverse(); + + let i = arr.length - 1; + while (i >= 0 && arr[i] === '0') { + i--; + } + + [arr[i], arr[arr.length - 1]] = [arr[arr.length - 1], arr[i]]; + return arr.join(''); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(n)$ + +--- + +## 2. Greedy + +::tabs-start + +```python +class Solution: + def maximumOddBinaryNumber(self, s: str) -> str: + count = 0 + for c in s: + if c == "1": + count += 1 + + return (count - 1) * "1" + (len(s) - count) * "0" + "1" +``` + +```java +public class Solution { + public String maximumOddBinaryNumber(String s) { + int count = 0; + for (char c : s.toCharArray()) { + if (c == '1') count++; + } + + StringBuilder result = new StringBuilder(); + for (int i = 0; i < count - 1; i++) result.append('1'); + for (int i = 0; i < s.length() - count; i++) result.append('0'); + result.append('1'); + + return result.toString(); + } +} +``` + +```cpp +class Solution { +public: + string maximumOddBinaryNumber(string s) { + int count = 0; + for (char c : s) { + if (c == '1') count++; + } + + string result((count - 1), '1'); + result += string(s.length() - count, '0'); + result += '1'; + + return result; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {string} + */ + maximumOddBinaryNumber(s) { + let count = 0; + for (const c of s) { + if (c === '1') count++; + } + + return '1'.repeat(count - 1) + '0'.repeat(s.length - count) + '1'; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 3. Two Pointers + +::tabs-start + +```python +class Solution: + def maximumOddBinaryNumber(self, s: str) -> str: + s = [c for c in s] + left = 0 + + for i in range(len(s)): + if s[i] == "1": + s[i], s[left] = s[left], s[i] + left += 1 + s[left - 1], s[len(s) - 1] = s[len(s) - 1], s[left - 1] + return "".join(s) +``` + +```java +public class Solution { + public String maximumOddBinaryNumber(String s) { + char[] arr = s.toCharArray(); + int left = 0; + + for (int i = 0; i < arr.length; i++) { + if (arr[i] == '1') { + char temp = arr[left]; + arr[left] = arr[i]; + arr[i] = temp; + left++; + } + } + + char temp = arr[left - 1]; + arr[left - 1] = arr[arr.length - 1]; + arr[arr.length - 1] = temp; + + return new String(arr); + } +} +``` + +```cpp +class Solution { +public: + string maximumOddBinaryNumber(string s) { + vector arr(s.begin(), s.end()); + int left = 0; + + for (int i = 0; i < arr.size(); i++) { + if (arr[i] == '1') { + swap(arr[left], arr[i]); + left++; + } + } + + swap(arr[left - 1], arr[arr.size() - 1]); + return string(arr.begin(), arr.end()); + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {string} + */ + maximumOddBinaryNumber(s) { + let arr = s.split(''); + let left = 0; + + for (let i = 0; i < arr.length; i++) { + if (arr[i] === '1') { + [arr[left], arr[i]] = [arr[i], arr[left]]; + left++; + } + } + + [arr[left - 1], arr[arr.length - 1]] = [arr[arr.length - 1], arr[left - 1]]; + return arr.join(''); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ \ No newline at end of file diff --git a/articles/merge-in-between-linked-lists.md b/articles/merge-in-between-linked-lists.md new file mode 100644 index 000000000..2d8a1774f --- /dev/null +++ b/articles/merge-in-between-linked-lists.md @@ -0,0 +1,460 @@ +## 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 mergeInBetween(self, list1: ListNode, a: int, b: int, list2: ListNode) -> ListNode: + cur = list1 + arr = [] + while cur: + arr.append(cur) + cur = cur.next + arr[a - 1].next = list2 + + cur = list2 + while cur.next: + cur = cur.next + + cur.next = arr[b + 1] + return list1 +``` + +```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 mergeInBetween(ListNode list1, int a, int b, ListNode list2) { + ListNode cur = list1; + List arr = new ArrayList<>(); + + while (cur != null) { + arr.add(cur); + cur = cur.next; + } + + arr.get(a - 1).next = list2; + cur = list2; + + while (cur.next != null) { + cur = cur.next; + } + + cur.next = arr.get(b + 1); + return list1; + } +} +``` + +```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* mergeInBetween(ListNode* list1, int a, int b, ListNode* list2) { + ListNode* cur = list1; + vector arr; + + while (cur) { + arr.push_back(cur); + cur = cur->next; + } + + arr[a - 1]->next = list2; + cur = list2; + + while (cur->next) { + cur = cur->next; + } + + cur->next = arr[b + 1]; + return list1; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} list1 + * @param {number} a + * @param {number} b + * @param {ListNode} list2 + * @return {ListNode} + */ + mergeInBetween(list1, a, b, list2) { + let cur = list1; + let arr = []; + + while (cur) { + arr.push(cur); + cur = cur.next; + } + + arr[a - 1].next = list2; + cur = list2; + + while (cur.next) { + cur = cur.next; + } + + cur.next = arr[b + 1]; + return list1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n + m)$ +* Space complexity: $O(n)$ + +> Where $n$ is the length of the first list and $m$ is the length of the second list. + +--- + +## 2. Two Pointers + +::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 mergeInBetween(self, list1: ListNode, a: int, b: int, list2: ListNode) -> ListNode: + curr = list1 + i = 0 + + while i < a - 1: + curr = curr.next + i += 1 + head = curr + + while i <= b: + curr = curr.next + i += 1 + + head.next = list2 + + while list2.next: + list2 = list2.next + list2.next = curr + + return list1 +``` + +```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 mergeInBetween(ListNode list1, int a, int b, ListNode list2) { + ListNode curr = list1; + int i = 0; + + while (i < a - 1) { + curr = curr.next; + i++; + } + ListNode head = curr; + + while (i <= b) { + curr = curr.next; + i++; + } + + head.next = list2; + + while (list2.next != null) { + list2 = list2.next; + } + list2.next = curr; + + return list1; + } +} +``` + +```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* mergeInBetween(ListNode* list1, int a, int b, ListNode* list2) { + ListNode* curr = list1; + int i = 0; + + while (i < a - 1) { + curr = curr->next; + i++; + } + ListNode* head = curr; + + while (i <= b) { + curr = curr->next; + i++; + } + head->next = list2; + + while (list2->next) { + list2 = list2->next; + } + list2->next = curr; + + return list1; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} list1 + * @param {number} a + * @param {number} b + * @param {ListNode} list2 + * @return {ListNode} + */ + mergeInBetween(list1, a, b, list2) { + let curr = list1, i = 0; + + while (i < a - 1) { + curr = curr.next; + i++; + } + let head = curr; + + while (i <= b) { + curr = curr.next; + i++; + } + head.next = list2; + + while (list2.next) { + list2 = list2.next; + } + list2.next = curr; + + return list1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n + m)$ +* Space complexity: $O(1)$ extra space. + +> Where $n$ is the length of the first list and $m$ is the length of the second list. + +--- + +## 3. Recursion + +::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 mergeInBetween(self, list1: ListNode, a: int, b: int, list2: ListNode) -> ListNode: + if a == 1 : + nxt = list1.next + list1.next = list2 + while list2.next: + list2 = list2.next + self.mergeInBetween(nxt, 0, b - 1, list2) + return list1 + + if b == 0: + list2.next = list1.next + return list1 + + self.mergeInBetween(list1.next, a - 1, b - 1, list2) + return list1 +``` + +```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 mergeInBetween(ListNode list1, int a, int b, ListNode list2) { + if (a == 1) { + ListNode nxt = list1.next; + list1.next = list2; + + while (list2.next != null) { + list2 = list2.next; + } + mergeInBetween(nxt, 0, b - 1, list2); + return list1; + } + + if (b == 0) { + list2.next = list1.next; + return list1; + } + + mergeInBetween(list1.next, a - 1, b - 1, list2); + return list1; + } +} +``` + +```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* mergeInBetween(ListNode* list1, int a, int b, ListNode* list2) { + if (a == 1) { + ListNode* nxt = list1->next; + list1->next = list2; + + while (list2->next) { + list2 = list2->next; + } + mergeInBetween(nxt, 0, b - 1, list2); + return list1; + } + + if (b == 0) { + list2->next = list1->next; + return list1; + } + + mergeInBetween(list1->next, a - 1, b - 1, list2); + return list1; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} list1 + * @param {number} a + * @param {number} b + * @param {ListNode} list2 + * @return {ListNode} + */ + mergeInBetween(list1, a, b, list2) { + if (a === 1) { + let nxt = list1.next; + list1.next = list2; + + while (list2.next) { + list2 = list2.next; + } + this.mergeInBetween(nxt, 0, b - 1, list2); + return list1; + } + + if (b === 0) { + list2.next = list1.next; + return list1; + } + + this.mergeInBetween(list1.next, a - 1, b - 1, list2); + return list1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n + m)$ +* Space complexity: $O(n)$ for recursion stack. + +> Where $n$ is the length of the first list and $m$ is the length of the second list. \ No newline at end of file diff --git a/articles/middle-of-the-linked-list.md b/articles/middle-of-the-linked-list.md new file mode 100644 index 000000000..935efc3d4 --- /dev/null +++ b/articles/middle-of-the-linked-list.md @@ -0,0 +1,339 @@ +## 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 middleNode(self, head: Optional[ListNode]) -> Optional[ListNode]: + cur = head + arr = [] + while cur: + arr.append(cur) + cur = cur.next + return arr[len(arr) // 2] +``` + +```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 middleNode(ListNode head) { + ArrayList arr = new ArrayList<>(); + ListNode cur = head; + while (cur != null) { + arr.add(cur); + cur = cur.next; + } + return arr.get(arr.size() / 2); + } +} +``` + +```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* middleNode(ListNode* head) { + vector arr; + ListNode* cur = head; + while (cur) { + arr.push_back(cur); + cur = cur->next; + } + return arr[arr.size() / 2]; + } +}; +``` + +```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} + */ + middleNode(head) { + let arr = []; + let cur = head; + while (cur) { + arr.push(cur); + cur = cur.next; + } + return arr[Math.floor(arr.length / 2)]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 2. Find Length of the List + +::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 middleNode(self, head: Optional[ListNode]) -> Optional[ListNode]: + n, cur = 0, head + while cur: + cur = cur.next + n += 1 + + n //= 2 + cur = head + while n: + n -= 1 + cur = cur.next + return cur +``` + +```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 middleNode(ListNode head) { + int n = 0; + ListNode cur = head; + while (cur != null) { + cur = cur.next; + n++; + } + + n /= 2; + cur = head; + while (n != 0) { + n--; + cur = cur.next; + } + return cur; + } +} +``` + +```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* middleNode(ListNode* head) { + int n = 0; + ListNode* cur = head; + while (cur) { + cur = cur->next; + n++; + } + + n /= 2; + cur = head; + while (n) { + n--; + cur = cur->next; + } + return cur; + } +}; +``` + +```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} + */ + middleNode(head) { + let n = 0; + let cur = head; + while (cur) { + cur = cur.next; + n++; + } + + n = Math.floor(n / 2); + cur = head; + while (n) { + n--; + cur = cur.next; + } + return cur; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ extra space. + +--- + +## 3. Fast & Slow Pointers + +::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 middleNode(self, head: Optional[ListNode]) -> Optional[ListNode]: + slow, fast = head, head + + while fast and fast.next: + slow = slow.next + fast = fast.next.next + return slow +``` + +```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 middleNode(ListNode head) { + ListNode slow = head, fast = head; + + while (fast != null && fast.next != null) { + slow = slow.next; + fast = fast.next.next; + } + return slow; + } +} +``` + +```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* middleNode(ListNode* head) { + ListNode* slow = head; + ListNode* fast = head; + + while (fast && fast->next) { + slow = slow->next; + fast = fast->next->next; + } + return slow; + } +}; +``` + +```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} + */ + middleNode(head) { + let slow = head, fast = head; + + while (fast && fast.next) { + slow = slow.next; + fast = fast.next.next; + } + return slow; + } +} +``` + +::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/open-the-lock.md b/articles/open-the-lock.md new file mode 100644 index 000000000..6ded4c7ee --- /dev/null +++ b/articles/open-the-lock.md @@ -0,0 +1,501 @@ +## 1. Breadth First Search - I + +::tabs-start + +```python +class Solution: + def openLock(self, deadends: List[str], target: str) -> int: + if "0000" in deadends: + return -1 + + def children(lock): + res = [] + for i in range(4): + digit = str((int(lock[i]) + 1) % 10) + res.append(lock[:i] + digit + lock[i+1:]) + digit = str((int(lock[i]) - 1 + 10) % 10) + res.append(lock[:i] + digit + lock[i+1:]) + return res + + q = deque([("0000", 0)]) + visit = set(deadends) + + while q: + lock, turns = q.popleft() + if lock == target: + return turns + for child in children(lock): + if child not in visit: + visit.add(child) + q.append((child, turns + 1)) + return -1 +``` + +```java +public class Solution { + public int openLock(String[] deadends, String target) { + Set visit = new HashSet<>(Arrays.asList(deadends)); + if (visit.contains("0000")) return -1; + + Queue queue = new LinkedList<>(); + queue.offer("0000"); + visit.add("0000"); + + int turns = 0; + while (!queue.isEmpty()) { + int size = queue.size(); + for (int i = 0; i < size; i++) { + String lock = queue.poll(); + if (lock.equals(target)) return turns; + + for (String next : children(lock)) { + if (!visit.contains(next)) { + queue.offer(next); + visit.add(next); + } + } + } + turns++; + } + return -1; + } + + private List children(String lock) { + List res = new ArrayList<>(); + for (int i = 0; i < 4; i++) { + char[] arr = lock.toCharArray(); + arr[i] = (char) (((arr[i] - '0' + 1) % 10) + '0'); + res.add(new String(arr)); + + arr = lock.toCharArray(); + arr[i] = (char) (((arr[i] - '0' - 1 + 10) % 10) + '0'); + res.add(new String(arr)); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int openLock(vector& deadends, string target) { + unordered_set visit(deadends.begin(), deadends.end()); + if (visit.count("0000")) return -1; + + queue> q; + q.push({"0000", 0}); + visit.insert("0000"); + + while (!q.empty()) { + auto [lock, turns] = q.front(); + q.pop(); + + if (lock == target) return turns; + for (string child : children(lock)) { + if (!visit.count(child)) { + visit.insert(child); + q.push({child, turns + 1}); + } + } + } + return -1; + } + +private: + vector children(string lock) { + vector res; + for (int i = 0; i < 4; ++i) { + string next = lock; + next[i] = (next[i] - '0' + 1) % 10 + '0'; + res.push_back(next); + + next = lock; + next[i] = (next[i] - '0' - 1 + 10) % 10 + '0'; + res.push_back(next); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} deadends + * @param {string} target + * @return {number} + */ + openLock(deadends, target) { + const visit = new Set(deadends); + if (visit.has("0000")) return -1; + + const children = (lock) => { + const res = []; + for (let i = 0; i < 4; i++) { + const up = lock.slice(0, i) + ((+lock[i] + 1) % 10) + lock.slice(i + 1); + const down = lock.slice(0, i) + ((+lock[i] - 1 + 10) % 10) + lock.slice(i + 1); + res.push(up, down); + } + return res; + }; + + const queue = new Queue([["0000", 0]]); + visit.add("0000"); + + while (!queue.isEmpty()) { + const [lock, turns] = queue.pop(); + if (lock === target) return turns; + + for (const child of children(lock)) { + if (!visit.has(child)) { + visit.add(child); + queue.push([child, turns + 1]); + } + } + } + return -1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(d ^ n + m)$ +* Space complexity: $O(d ^ n)$ + +> Where $d$ is the number of digits $(0 - 9)$, $n$ is the number of wheels $(4)$, and $m$ is the number of deadends. + +--- + +## 2. Breadth First Search - II + +::tabs-start + +```python +class Solution: + def openLock(self, deadends: List[str], target: str) -> int: + if target == "0000": + return 0 + + visit = set(deadends) + if "0000" in visit: + return -1 + + q = deque(["0000"]) + visit.add("0000") + steps = 0 + + while q: + steps += 1 + for _ in range(len(q)): + lock = q.popleft() + for i in range(4): + for j in [1, -1]: + digit = str((int(lock[i]) + j + 10) % 10) + nextLock = lock[:i] + digit + lock[i+1:] + if nextLock in visit: + continue + if nextLock == target: + return steps + q.append(nextLock) + visit.add(nextLock) + return -1 +``` + +```java +public class Solution { + public int openLock(String[] deadends, String target) { + if (target.equals("0000")) return 0; + + Set visit = new HashSet<>(Arrays.asList(deadends)); + if (visit.contains("0000")) return -1; + + Queue q = new LinkedList<>(); + q.offer("0000"); + visit.add("0000"); + int steps = 0; + + while (!q.isEmpty()) { + steps++; + for (int i = q.size(); i > 0; i--) { + String lock = q.poll(); + for (int j = 0; j < 4; j++) { + for (int move : new int[]{1, -1}) { + char[] arr = lock.toCharArray(); + arr[j] = (char)((arr[j] - '0' + move + 10) % 10 + '0'); + String nextLock = new String(arr); + if (visit.contains(nextLock)) continue; + if (nextLock.equals(target)) return steps; + q.offer(nextLock); + visit.add(nextLock); + } + } + } + } + return -1; + } +} +``` + +```cpp +class Solution { +public: + int openLock(vector& deadends, string target) { + if (target == "0000") return 0; + + unordered_set visit(deadends.begin(), deadends.end()); + if (visit.count("0000")) return -1; + + queue q; + q.push("0000"); + visit.insert("0000"); + int steps = 0; + + while (!q.empty()) { + steps++; + for (int i = q.size(); i > 0; i--) { + string lock = q.front(); q.pop(); + for (int j = 0; j < 4; j++) { + for (int move : {1, -1}) { + string nextLock = lock; + nextLock[j] = (nextLock[j] - '0' + move + 10) % 10 + '0'; + if (visit.count(nextLock)) continue; + if (nextLock == target) return steps; + q.push(nextLock); + visit.insert(nextLock); + } + } + } + } + return -1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} deadends + * @param {string} target + * @return {number} + */ + openLock(deadends, target) { + if (target === "0000") return 0; + + const visit = new Set(deadends); + if (visit.has("0000")) return -1; + + const q = new Queue(["0000"]); + visit.add("0000"); + let steps = 0; + + while (!q.isEmpty()) { + steps++; + for (let i = q.size(); i > 0; i--) { + const lock = q.pop(); + for (let j = 0; j < 4; j++) { + for (let move of [1, -1]) { + const digit = (parseInt(lock[j]) + move + 10) % 10; + const nextLock = lock.slice(0, j) + digit + lock.slice(j + 1); + if (visit.has(nextLock)) continue; + if (nextLock === target) return steps; + q.push(nextLock); + visit.add(nextLock); + } + } + } + } + return -1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(d ^ n + m)$ +* Space complexity: $O(d ^ n)$ + +> Where $d$ is the number of digits $(0 - 9)$, $n$ is the number of wheels $(4)$, and $m$ is the number of deadends. + +--- + +## 3. Bidirectional Breadth First Search + +::tabs-start + +```python +class Solution: + def openLock(self, deadends: List[str], target: str) -> int: + if target == "0000": + return 0 + + visit = set(deadends) + if "0000" in visit: + return -1 + + begin = {"0000"} + end = {target} + steps = 0 + + while begin and end: + if len(begin) > len(end): + begin, end = end, begin + + steps += 1 + temp = set() + for lock in begin: + for i in range(4): + for j in [-1, 1]: + digit = str((int(lock[i]) + j + 10) % 10) + nextLock = lock[:i] + digit + lock[i+1:] + + if nextLock in end: + return steps + if nextLock in visit: + continue + visit.add(nextLock) + temp.add(nextLock) + begin = temp + return -1 +``` + +```java +public class Solution { + public int openLock(String[] deadends, String target) { + if (target.equals("0000")) return 0; + + Set visit = new HashSet<>(Arrays.asList(deadends)); + if (visit.contains("0000")) return -1; + + Set begin = new HashSet<>(); + begin.add("0000"); + Set end = new HashSet<>(); + end.add(target); + int steps = 0; + + while (!begin.isEmpty() && !end.isEmpty()) { + if (begin.size() > end.size()) { + Set temp = begin; + begin = end; + end = temp; + } + + steps++; + Set temp = new HashSet<>(); + for (String lock : begin) { + for (int i = 0; i < 4; i++) { + for (int j : new int[]{-1, 1}) { + char[] chars = lock.toCharArray(); + chars[i] = (char) ((chars[i] - '0' + j + 10) % 10 + '0'); + String nextLock = new String(chars); + + if (end.contains(nextLock)) return steps; + if (visit.contains(nextLock)) continue; + + visit.add(nextLock); + temp.add(nextLock); + } + } + } + begin = temp; + } + return -1; + } +} +``` + +```cpp +class Solution { +public: + int openLock(vector& deadends, string target) { + if (target == "0000") return 0; + + unordered_set visit(deadends.begin(), deadends.end()); + if (visit.count("0000")) return -1; + + unordered_set begin = {"0000"}, end = {target}; + int steps = 0; + + while (!begin.empty() && !end.empty()) { + if (begin.size() > end.size()) swap(begin, end); + steps++; + unordered_set temp; + + for (const string& lock : begin) { + for (int i = 0; i < 4; ++i) { + for (int j : {-1, 1}) { + string nextLock = lock; + nextLock[i] = (nextLock[i] - '0' + j + 10) % 10 + '0'; + + if (end.count(nextLock)) return steps; + if (visit.count(nextLock)) continue; + + visit.insert(nextLock); + temp.insert(nextLock); + } + } + } + begin = temp; + } + return -1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} deadends + * @param {string} target + * @return {number} + */ + openLock(deadends, target) { + if (target === "0000") return 0; + + const visit = new Set(deadends); + if (visit.has("0000")) return -1; + + let begin = new Set(["0000"]); + let end = new Set([target]); + let steps = 0; + + while (begin.size > 0 && end.size > 0) { + if (begin.size > end.size) [begin, end] = [end, begin]; + + steps++; + const temp = new Set(); + + for (const lock of begin) { + for (let i = 0; i < 4; i++) { + for (const j of [-1, 1]) { + const digit = (parseInt(lock[i]) + j + 10) % 10; + const nextLock = lock.slice(0, i) + digit + lock.slice(i + 1); + + if (end.has(nextLock)) return steps; + if (visit.has(nextLock)) continue; + + visit.add(nextLock); + temp.add(nextLock); + } + } + } + begin = temp; + } + return -1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(d ^ n + m)$ +* Space complexity: $O(d ^ n)$ + +> Where $d$ is the number of digits $(0 - 9)$, $n$ is the number of wheels $(4)$, and $m$ is the number of deadends. \ No newline at end of file diff --git a/articles/palindrome-linked-list.md b/articles/palindrome-linked-list.md new file mode 100644 index 000000000..f4f73b7bc --- /dev/null +++ b/articles/palindrome-linked-list.md @@ -0,0 +1,600 @@ +## 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 isPalindrome(self, head: Optional[ListNode]) -> bool: + arr = [] + cur = head + while cur: + arr.append(cur.val) + cur = cur.next + + l, r = 0, len(arr) - 1 + while l < r: + if arr[l] != arr[r]: + return False + l, r = l + 1, r - 1 + + return True +``` + +```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 boolean isPalindrome(ListNode head) { + List arr = new ArrayList<>(); + ListNode cur = head; + while (cur != null) { + arr.add(cur.val); + cur = cur.next; + } + + int l = 0, r = arr.size() - 1; + while (l < r) { + if (!arr.get(l).equals(arr.get(r))) { + return false; + } + l++; + r--; + } + + return true; + } +} +``` + +```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: + bool isPalindrome(ListNode* head) { + std::vector arr; + ListNode* cur = head; + while (cur) { + arr.push_back(cur->val); + cur = cur->next; + } + + int l = 0, r = arr.size() - 1; + while (l < r) { + if (arr[l] != arr[r]) { + return false; + } + l++; + r--; + } + + return true; + } +}; +``` + +```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 {boolean} + */ + isPalindrome(head) { + const arr = []; + let cur = head; + + while (cur) { + arr.push(cur.val); + cur = cur.next; + } + + let l = 0, r = arr.length - 1; + while (l < r) { + if (arr[l] !== arr[r]) { + return false; + } + l++; + r--; + } + + return true; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 2. Recursion + +::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 isPalindrome(self, head: Optional[ListNode]) -> bool: + self.cur = head + + def rec(node): + if node is not None: + if not rec(node.next): + return False + if self.cur.val != node.val: + return False + self.cur = self.cur.next + return True + + return rec(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 { + private ListNode cur; + + public boolean isPalindrome(ListNode head) { + cur = head; + return rec(head); + } + + private boolean rec(ListNode node) { + if (node != null) { + if (!rec(node.next)) { + return false; + } + if (cur.val != node.val) { + return false; + } + cur = cur.next; + } + return true; + } +} +``` + +```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 { + ListNode* cur; + + bool rec(ListNode* node) { + if (node != nullptr) { + if (!rec(node->next)) { + return false; + } + if (cur->val != node->val) { + return false; + } + cur = cur->next; + } + return true; + } + +public: + bool isPalindrome(ListNode* head) { + cur = head; + return rec(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 {boolean} + */ + isPalindrome(head) { + let cur = head; + + const rec = (node) => { + if (node !== null) { + if (!rec(node.next)) { + return false; + } + if (cur.val !== node.val) { + return false; + } + cur = cur.next; + } + return true; + }; + + return rec(head); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ for recursion stack. + +--- + +## 3. Stack + +::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 isPalindrome(self, head: Optional[ListNode]) -> bool: + stack = [] + cur = head + + while cur: + stack.append(cur.val) + cur = cur.next + + cur = head + while cur and cur.val == stack.pop(): + cur = cur.next + + return not cur +``` + +```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 boolean isPalindrome(ListNode head) { + Stack stack = new Stack<>(); + ListNode cur = head; + + while (cur != null) { + stack.push(cur.val); + cur = cur.next; + } + + cur = head; + while (cur != null && cur.val == stack.pop()) { + cur = cur.next; + } + + return cur == null; + } +} +``` + +```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: + bool isPalindrome(ListNode* head) { + stack stack; + ListNode* cur = head; + + while (cur != nullptr) { + stack.push(cur->val); + cur = cur->next; + } + + cur = head; + while (cur != nullptr && cur->val == stack.top()) { + stack.pop(); + cur = cur->next; + } + + return cur == nullptr; + } +}; +``` + +```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 {boolean} + */ + isPalindrome(head) { + const stack = []; + let cur = head; + + while (cur) { + stack.push(cur.val); + cur = cur.next; + } + + cur = head; + while (cur && cur.val === stack.pop()) { + cur = cur.next; + } + + return cur === null; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 4. Fast & Slow Pointers + +::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 isPalindrome(self, head: ListNode) -> bool: + fast = head + slow = head + + # find middle (slow) + while fast and fast.next: + fast = fast.next.next + slow = slow.next + + # reverse second half + prev = None + while slow: + tmp = slow.next + slow.next = prev + prev = slow + slow = tmp + + # check palindrome + left, right = head, prev + while right: + if left.val != right.val: + return False + left = left.next + right = right.next + + return True +``` + +```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 boolean isPalindrome(ListNode head) { + ListNode fast = head, slow = head; + + // find middle (slow) + while (fast != null && fast.next != null) { + fast = fast.next.next; + slow = slow.next; + } + + // reverse second half + ListNode prev = null; + while (slow != null) { + ListNode tmp = slow.next; + slow.next = prev; + prev = slow; + slow = tmp; + } + + // check palindrome + ListNode left = head, right = prev; + while (right != null) { + if (left.val != right.val) { + return false; + } + left = left.next; + right = right.next; + } + + return true; + } +} +``` + +```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: + bool isPalindrome(ListNode* head) { + ListNode *fast = head, *slow = head; + + // find middle (slow) + while (fast && fast->next) { + fast = fast->next->next; + slow = slow->next; + } + + // reverse second half + ListNode *prev = nullptr; + while (slow) { + ListNode *tmp = slow->next; + slow->next = prev; + prev = slow; + slow = tmp; + } + + // check palindrome + ListNode *left = head, *right = prev; + while (right) { + if (left->val != right->val) { + return false; + } + left = left->next; + right = right->next; + } + + return true; + } +}; +``` + +```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 {boolean} + */ + isPalindrome(head) { + let fast = head, slow = head; + + // find middle (slow) + while (fast && fast.next) { + fast = fast.next.next; + slow = slow.next; + } + + // reverse second half + let prev = null; + while (slow) { + let tmp = slow.next; + slow.next = prev; + prev = slow; + slow = tmp; + } + + // check palindrome + let left = head, right = prev; + while (right) { + if (left.val !== right.val) { + return false; + } + left = left.next; + right = right.next; + } + + return true; + } +} +``` + +::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/permutations-ii.md b/articles/permutations-ii.md new file mode 100644 index 000000000..d4c0edd41 --- /dev/null +++ b/articles/permutations-ii.md @@ -0,0 +1,712 @@ +## 1. Backtracking (Hash Set) + +::tabs-start + +```python +class Solution: + def permuteUnique(self, nums: List[int]) -> List[List[int]]: + res = set() + + def backtrack(perm): + if len(perm) == len(nums): + res.add(tuple(perm)) + return + + for i in range(len(nums)): + if nums[i] != float("-inf"): + perm.append(nums[i]) + nums[i] = float("-inf") + backtrack(perm) + nums[i] = perm[-1] + perm.pop() + + backtrack([]) + return list(res) +``` + +```java +public class Solution { + private Set> res; + + public List> permuteUnique(int[] nums) { + res = new HashSet<>(); + List perm = new ArrayList<>(); + backtrack(nums, perm); + return new ArrayList<>(res); + } + + private void backtrack(int[] nums, List perm) { + if (perm.size() == nums.length) { + res.add(new ArrayList<>(perm)); + return; + } + + for (int i = 0; i < nums.length; i++) { + if (nums[i] != Integer.MIN_VALUE) { + int temp = nums[i]; + perm.add(nums[i]); + nums[i] = Integer.MIN_VALUE; + backtrack(nums, perm); + nums[i] = temp; + perm.remove(perm.size() - 1); + } + } + } +} +``` + +```cpp +class Solution { + set> res; +public: + vector> permuteUnique(vector& nums) { + vector perm; + backtrack(nums, perm); + return vector>(res.begin(), res.end()); + } + +private: + void backtrack(vector& nums, vector& perm) { + if (perm.size() == nums.size()) { + res.insert(perm); + return; + } + + for (int i = 0; i < nums.size(); ++i) { + if (nums[i] != INT_MIN) { + int temp = nums[i]; + perm.push_back(temp); + nums[i] = INT_MIN; + backtrack(nums, perm); + nums[i] = temp; + perm.pop_back(); + } + } + + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number[][]} + */ + permuteUnique(nums) { + const res = new Set(); + const perm = []; + + const backtrack = () => { + if (perm.length === nums.length) { + res.add(JSON.stringify(perm)); + return; + } + + for (let i = 0; i < nums.length; i++) { + if (nums[i] !== -Infinity) { + let temp = nums[i]; + perm.push(nums[i]); + nums[i] = -Infinity; + backtrack(); + nums[i] = temp; + perm.pop(); + } + } + }; + + backtrack(); + return Array.from(res).map(JSON.parse); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n! * n)$ +* Space complexity: $O(n! * n)$ for the hash set. + +--- + +## 2. Backtracking (Hash Map) + +::tabs-start + +```python +class Solution: + def permuteUnique(self, nums: List[int]) -> List[List[int]]: + res = [] + perm = [] + count = {n: 0 for n in nums} + for num in nums: + count[num] += 1 + + def dfs(): + if len(perm) == len(nums): + res.append(perm.copy()) + return + + for num in count: + if count[num] > 0: + perm.append(num) + count[num] -= 1 + dfs() + count[num] += 1 + perm.pop() + + dfs() + return res +``` + +```java +public class Solution { + private Map count; + private List> res; + + public List> permuteUnique(int[] nums) { + res = new ArrayList<>(); + count = new HashMap<>(); + List perm = new ArrayList<>(); + + for (int num : nums) { + count.put(num, count.getOrDefault(num, 0) + 1); + } + + dfs(nums, perm); + return res; + } + + private void dfs(int[] nums, List perm) { + if (perm.size() == nums.length) { + res.add(new ArrayList<>(perm)); + return; + } + + for (int num : count.keySet()) { + if (count.get(num) > 0) { + perm.add(num); + count.put(num, count.get(num) - 1); + dfs(nums, perm); + count.put(num, count.get(num) + 1); + perm.remove(perm.size() - 1); + } + } + } +} +``` + +```cpp +class Solution { + vector> res; + unordered_map count; + +public: + vector> permuteUnique(vector& nums) { + for (int& num : nums) { + count[num]++; + } + vector perm; + dfs(nums, perm); + return res; + } + + void dfs(vector& nums, vector& perm) { + if (perm.size() == nums.size()) { + res.push_back(perm); + return; + } + for (auto& [num, cnt] : count) { + if (cnt > 0) { + perm.push_back(num); + cnt--; + dfs(nums, perm); + cnt++; + perm.pop_back(); + } + } + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number[][]} + */ + permuteUnique(nums) { + const res = []; + const perm = []; + const count = {}; + + for (const num of nums) { + count[num] = (count[num] || 0) + 1; + } + + const dfs = () => { + if (perm.length === nums.length) { + res.push([...perm]); + return; + } + + for (const num in count) { + if (count[num] > 0) { + perm.push(+num); + count[num]--; + dfs(); + count[num]++; + perm.pop(); + } + } + }; + + dfs(); + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n! * n)$ +* Space complexity: $O(n! * n)$ for the output list. + +--- + +## 3. Backtracking (Boolean Array) + +::tabs-start + +```python +class Solution: + def permuteUnique(self, nums: List[int]) -> List[List[int]]: + res, n = [], len(nums) + visit = [False] * n + perm = [] + + def dfs(): + if len(perm) == n: + res.append(perm.copy()) + return + + for i in range(n): + if visit[i]: + continue + + if i and nums[i] == nums[i - 1] and not visit[i - 1]: + continue + visit[i] = True + perm.append(nums[i]) + dfs() + visit[i] = False + perm.pop() + + nums.sort() + dfs() + return res +``` + +```java +public class Solution { + private boolean[] visit; + private List> res; + + public List> permuteUnique(int[] nums) { + res = new ArrayList<>(); + visit = new boolean[nums.length]; + Arrays.sort(nums); + List perm = new ArrayList<>(); + dfs(nums, perm); + return res; + } + + private void dfs(int[] nums, List perm) { + if (perm.size() == nums.length) { + res.add(new ArrayList<>(perm)); + return; + } + + for (int i = 0; i < nums.length; i++) { + if (visit[i] || (i > 0 && nums[i] == nums[i - 1] && !visit[i - 1])) + continue; + + visit[i] = true; + perm.add(nums[i]); + dfs(nums, perm); + visit[i] = false; + perm.remove(perm.size() - 1); + } + } +} +``` + +```cpp +class Solution { + vector> res; + vector visit; + +public: + vector> permuteUnique(vector& nums) { + visit.assign(nums.size(), false); + vector perm; + sort(nums.begin(), nums.end()); + dfs(nums, perm); + return res; + } + + void dfs(vector& nums, vector& perm) { + if (perm.size() == nums.size()) { + res.push_back(perm); + return; + } + for (int i = 0; i < nums.size(); i++) { + if (visit[i] || (i > 0 && nums[i] == nums[i - 1] && !visit[i - 1])) + continue; + + visit[i] = true; + perm.push_back(nums[i]); + dfs(nums, perm); + visit[i] = false; + perm.pop_back(); + } + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number[][]} + */ + permuteUnique(nums) { + const res = []; + const visit = new Array(nums.length).fill(false); + const perm = []; + nums.sort((a, b) => a - b); + + const dfs = () => { + if (perm.length === nums.length) { + res.push([...perm]); + return; + } + + for (let i = 0; i < nums.length; i++) { + if (visit[i] || (i > 0 && nums[i] === nums[i - 1] && !visit[i - 1])) + continue; + + visit[i] = true; + perm.push(nums[i]); + dfs(); + visit[i] = false; + perm.pop(); + } + }; + + dfs(); + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n! * n)$ +* Space complexity: $O(n! * n)$ for the output list. + +--- + +## 4. Backtracking (Optimal) + +::tabs-start + +```python +class Solution: + def permuteUnique(self, nums: List[int]) -> List[List[int]]: + res = [] + + def dfs(i): + if i == len(nums): + res.append(nums.copy()) + return + + for j in range(i, len(nums)): + if j > i and nums[i] == nums[j]: + continue + + nums[i], nums[j] = nums[j], nums[i] + dfs(i + 1) + + for j in range(len(nums) - 1, i, -1): + nums[j], nums[i] = nums[i], nums[j] + + nums.sort() + dfs(0) + return res +``` + +```java +public class Solution { + private List> res; + + public List> permuteUnique(int[] nums) { + res = new ArrayList<>(); + Arrays.sort(nums); + dfs(0, nums); + return res; + } + + private void dfs(int i, int[] nums) { + if (i == nums.length) { + List temp = new ArrayList<>(); + for (int num : nums) temp.add(num); + res.add(temp); + return; + } + + for (int j = i; j < nums.length; j++) { + if (j > i && nums[j] == nums[i]) continue; + swap(nums, i, j); + dfs(i + 1, nums); + } + + for (int j = nums.length - 1; j > i; j--) { + swap(nums, i, j); + } + } + + private void swap(int[] nums, int i, int j) { + int temp = nums[i]; + nums[i] = nums[j]; + nums[j] = temp; + } +} +``` + +```cpp +class Solution { + vector> res; + +public: + vector> permuteUnique(vector& nums) { + sort(nums.begin(), nums.end()); + dfs(0, nums); + return res; + } + + void dfs(int i, vector& nums) { + if (i == nums.size()) { + res.push_back(nums); + return; + } + + for (int j = i; j < nums.size(); ++j) { + if (j > i && nums[j] == nums[i]) continue; + swap(nums[i], nums[j]); + dfs(i + 1, nums); + } + + for (int j = nums.size() - 1; j > i; --j) { + swap(nums[i], nums[j]); + } + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number[][]} + */ + permuteUnique(nums) { + const res = []; + nums.sort((a, b) => a - b); + + const dfs = (i) => { + if (i === nums.length) { + res.push([...nums]); + return; + } + + for (let j = i; j < nums.length; j++) { + if (j > i && nums[j] === nums[i]) continue; + [nums[i], nums[j]] = [nums[j], nums[i]]; + dfs(i + 1); + } + + for (let j = nums.length - 1; j > i; j--) { + [nums[i], nums[j]] = [nums[j], nums[i]]; + } + }; + + dfs(0); + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n! * n)$ +* Space complexity: $O(n! * n)$ for the output list. + +--- + +## 5. Iteration + +::tabs-start + +```python +class Solution: + def permuteUnique(self, nums: List[int]) -> List[List[int]]: + n = len(nums) + nums.sort() + res = [nums.copy()] + + while True: + i = n - 2 + while i >= 0 and nums[i] >= nums[i + 1]: + i -= 1 + + if i < 0: + break + + j = n - 1 + while nums[j] <= nums[i]: + j -= 1 + nums[i], nums[j] = nums[j], nums[i] + + l, r = i + 1, n - 1 + while l < r: + nums[l], nums[r] = nums[r], nums[l] + l, r = l + 1, r - 1 + + res.append(nums.copy()) + + return res +``` + +```java +public class Solution { + public List> permuteUnique(int[] nums) { + int n = nums.length; + Arrays.sort(nums); + List> res = new ArrayList<>(); + res.add(toList(nums)); + + while (true) { + int i = n - 2; + while (i >= 0 && nums[i] >= nums[i + 1]) i--; + + if (i < 0) break; + + int j = n - 1; + while (nums[j] <= nums[i]) j--; + + swap(nums, i, j); + reverse(nums, i + 1, n - 1); + res.add(toList(nums)); + } + + return res; + } + + private void reverse(int[] nums, int l, int r) { + while (l < r) { + swap(nums, l++, r--); + } + } + + private void swap(int[] nums, int i, int j) { + int temp = nums[i]; + nums[i] = nums[j]; + nums[j] = temp; + } + + private List toList(int[] nums) { + List list = new ArrayList<>(); + for (int num : nums) list.add(num); + return list; + } +} +``` + +```cpp +class Solution { +public: + vector> permuteUnique(vector& nums) { + int n = nums.size(); + sort(nums.begin(), nums.end()); + vector> res = {nums}; + + while (true) { + int i = n - 2; + while (i >= 0 && nums[i] >= nums[i + 1]) i--; + + if (i < 0) break; + + int j = n - 1; + while (nums[j] <= nums[i]) j--; + + swap(nums[i], nums[j]); + reverse(nums.begin() + i + 1, nums.end()); + res.push_back(nums); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number[][]} + */ + permuteUnique(nums) { + const n = nums.length; + nums.sort((a, b) => a - b); + const res = [nums.slice()]; + + while (true) { + let i = n - 2; + while (i >= 0 && nums[i] >= nums[i + 1]) i--; + + if (i < 0) break; + + let j = n - 1; + while (nums[j] <= nums[i]) j--; + + [nums[i], nums[j]] = [nums[j], nums[i]]; + + let l = i + 1, r = n - 1; + while (l < r) { + [nums[l], nums[r]] = [nums[r], nums[l]]; + l++; + r--; + } + + res.push(nums.slice()); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n! * n)$ +* Space complexity: $O(n! * n)$ for the output list. \ No newline at end of file diff --git a/articles/permutations.md b/articles/permutations.md index 3f9811dde..492290c73 100644 --- a/articles/permutations.md +++ b/articles/permutations.md @@ -151,7 +151,7 @@ class Solution { ### Time & Space Complexity * Time complexity: $O(n! * n ^ 2)$ -* Space complexity: $O(n! * n)$ +* Space complexity: $O(n! * n)$ for the output list. --- @@ -308,7 +308,7 @@ class Solution { ### Time & Space Complexity * Time complexity: $O(n! * n ^ 2)$ -* Space complexity: $O(n! * n)$ +* Space complexity: $O(n! * n)$ for the output list. --- @@ -506,7 +506,7 @@ class Solution { ### Time & Space Complexity * Time complexity: $O(n! * n)$ -* Space complexity: $O(n)$ +* Space complexity: $O(n! * n)$ for the output list. --- @@ -696,7 +696,7 @@ class Solution { ### Time & Space Complexity * Time complexity: $O(n! * n)$ -* Space complexity: $O(n)$ +* Space complexity: $O(n! * n)$ for the output list. --- @@ -894,4 +894,4 @@ class Solution { ### Time & Space Complexity * Time complexity: $O(n! * n)$ -* Space complexity: $O(n)$ \ No newline at end of file +* Space complexity: $O(n! * n)$ for the output list. \ No newline at end of file diff --git a/articles/remove-duplicates-from-sorted-list.md b/articles/remove-duplicates-from-sorted-list.md new file mode 100644 index 000000000..b50bbbdcb --- /dev/null +++ b/articles/remove-duplicates-from-sorted-list.md @@ -0,0 +1,312 @@ +## 1. Recursion + +::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 deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]: + if not head or not head.next: + return head + + head.next = self.deleteDuplicates(head.next) + return head if head.val != head.next.val else head.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 deleteDuplicates(ListNode head) { + if (head == null || head.next == null) return head; + + head.next = deleteDuplicates(head.next); + return head.val != head.next.val ? head : head.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* deleteDuplicates(ListNode* head) { + if (!head || !head->next) return head; + + head->next = deleteDuplicates(head->next); + return head->val != head->next->val ? head : head->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} + */ + deleteDuplicates(head) { + if (!head || !head.next) return head; + + head.next = this.deleteDuplicates(head.next); + return head.val !== head.next.val ? head : head.next; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(2 ^ n)$ +* Space complexity: $O(n)$ for recursion stack. + +--- + +## 2. Iteration - I + +::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 deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]: + cur = head + while cur: + while cur.next and cur.next.val == cur.val: + cur.next = cur.next.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 deleteDuplicates(ListNode head) { + ListNode cur = head; + while (cur != null) { + while (cur.next != null && cur.next.val == cur.val) { + cur.next = cur.next.next; + } + 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* deleteDuplicates(ListNode* head) { + ListNode* cur = head; + while (cur) { + while (cur->next && cur->next->val == cur->val) { + cur->next = cur->next->next; + } + 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} + */ + deleteDuplicates(head) { + let cur = head; + while (cur) { + while (cur.next && cur.next.val === cur.val) { + cur.next = cur.next.next; + } + cur = cur.next; + } + return head; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ extra space. + +--- + +## 3. Iteration - II + +::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 deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]: + cur = head + while cur and cur.next: + if cur.val == cur.next.val: + cur.next = cur.next.next + else: + 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 deleteDuplicates(ListNode head) { + ListNode cur = head; + while (cur != null && cur.next != null) { + if (cur.next.val == cur.val) { + cur.next = cur.next.next; + } else { + 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* deleteDuplicates(ListNode* head) { + ListNode* cur = head; + while (cur && cur->next) { + if (cur->next->val == cur->val) { + cur->next = cur->next->next; + } else { + 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} + */ + deleteDuplicates(head) { + let cur = head; + while (cur && cur.next) { + if (cur.next.val === cur.val) { + cur.next = cur.next.next; + } else { + cur = cur.next; + } + } + return head; + } +} +``` + +::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/remove-linked-list-elements.md b/articles/remove-linked-list-elements.md new file mode 100644 index 000000000..30e4a5e94 --- /dev/null +++ b/articles/remove-linked-list-elements.md @@ -0,0 +1,514 @@ +## 1. Brute Force + +::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 removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]: + arr = [] + cur = head + + while cur: + if cur.val != val: + arr.append(cur.val) + cur = cur.next + + if not arr: + return None + + res = ListNode(arr[0]) + cur = res + for i in range(1, len(arr)): + node = ListNode(arr[i]) + cur.next = node + cur = cur.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 removeElements(ListNode head, int val) { + List arr = new ArrayList<>(); + ListNode cur = head; + + while (cur != null) { + if (cur.val != val) { + arr.add(cur.val); + } + cur = cur.next; + } + + if (arr.isEmpty()) { + return null; + } + + ListNode res = new ListNode(arr.get(0)); + cur = res; + for (int i = 1; i < arr.size(); i++) { + ListNode node = new ListNode(arr.get(i)); + cur.next = node; + cur = cur.next; + } + + 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: + ListNode* removeElements(ListNode* head, int val) { + vector arr; + ListNode* cur = head; + + while (cur) { + if (cur->val != val) { + arr.push_back(cur->val); + } + cur = cur->next; + } + + if (arr.empty()) { + return nullptr; + } + + ListNode* res = new ListNode(arr[0]); + cur = res; + for (int i = 1; i < arr.size(); i++) { + ListNode* node = new ListNode(arr[i]); + cur->next = node; + cur = cur->next; + } + + 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} val + * @return {ListNode} + */ + removeElements(head, val) { + const arr = []; + let cur = head; + + while (cur) { + if (cur.val !== val) { + arr.push(cur.val); + } + cur = cur.next; + } + + if (arr.length === 0) { + return null; + } + + const res = new ListNode(arr[0]); + cur = res; + for (let i = 1; i < arr.length; i++) { + const node = new ListNode(arr[i]); + cur.next = node; + cur = cur.next; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 2. Recursion + +::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 removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]: + if not head: + return None + head.next = self.removeElements(head.next, val) + return head if head.val != val else head.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 removeElements(ListNode head, int val) { + if (head == null) return null; + head.next = removeElements(head.next, val); + return head.val != val ? head : head.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* removeElements(ListNode* head, int val) { + if (head == nullptr) return nullptr; + head->next = removeElements(head->next, val); + return head->val != val ? head : head->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 + * @param {number} val + * @return {ListNode} + */ + removeElements(head, val) { + if (head === null) return null; + head.next = this.removeElements(head.next, val); + return head.val !== val ? head : head.next; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ for recursion stack. + +--- + +## 3. 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 removeElements(self, head: ListNode, val: int) -> ListNode: + dummy = ListNode(0, head) + prev, curr = dummy, head + + while curr: + nxt = curr.next + if curr.val == val: + prev.next = nxt + else: + prev = curr + curr = nxt + + 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 removeElements(ListNode head, int val) { + ListNode dummy = new ListNode(0, head); + ListNode prev = dummy, curr = head; + + while (curr != null) { + ListNode nxt = curr.next; + if (curr.val == val) { + prev.next = nxt; + } else { + prev = curr; + } + curr = nxt; + } + + 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* removeElements(ListNode* head, int val) { + ListNode dummy(0, head); + ListNode *prev = &dummy, *curr = head; + + while (curr) { + ListNode* nxt = curr->next; + if (curr->val == val) { + prev->next = nxt; + } else { + prev = curr; + } + curr = nxt; + } + + 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 + * @param {number} val + * @return {ListNode} + */ + removeElements(head, val) { + let dummy = new ListNode(0, head); + let prev = dummy, curr = head; + + while (curr) { + let nxt = curr.next; + if (curr.val === val) { + prev.next = nxt; + } else { + prev = curr; + } + curr = nxt; + } + + return dummy.next; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ extra space. + +--- + +## 4. iteration Without Prev Pointer + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def removeElements(self, head: ListNode, val: int) -> ListNode: + dummy = ListNode(-1, head) + curr = dummy + + while curr.next: + if curr.next.val == val: + curr.next = curr.next.next + else: + curr = curr.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 removeElements(ListNode head, int val) { + ListNode dummy = new ListNode(-1, head); + ListNode curr = dummy; + + while (curr.next != null) { + if (curr.next.val == val) { + curr.next = curr.next.next; + } else { + curr = curr.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* removeElements(ListNode* head, int val) { + ListNode dummy(-1, head); + ListNode *curr = &dummy; + + while (curr->next) { + if (curr->next->val == val) { + curr->next = curr->next->next; + } else { + curr = curr->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 + * @param {number} val + * @return {ListNode} + */ + removeElements(head, val) { + let dummy = new ListNode(-1, head); + let curr = dummy; + + while (curr.next) { + if (curr.next.val === val) { + curr.next = curr.next.next; + } else { + curr = curr.next; + } + } + + return dummy.next; + } +} +``` + +::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/remove-nodes-from-linked-list.md b/articles/remove-nodes-from-linked-list.md new file mode 100644 index 000000000..b629d4760 --- /dev/null +++ b/articles/remove-nodes-from-linked-list.md @@ -0,0 +1,574 @@ +## 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 removeNodes(self, head: Optional[ListNode]) -> Optional[ListNode]: + cur, arr = head, [ListNode(0, head)] + while cur: + arr.append(cur) + cur = cur.next + + rightMaxi = ListNode(0, None) + for i in range(len(arr) - 1, 0, -1): + if rightMaxi.val > arr[i].val: + arr[i - 1].next = rightMaxi + else: + rightMaxi = arr[i] + + return arr[0].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 removeNodes(ListNode head) { + List arr = new ArrayList<>(); + arr.add(new ListNode(0, head)); + ListNode cur = head; + + while (cur != null) { + arr.add(cur); + cur = cur.next; + } + + ListNode rightMaxi = new ListNode(0, null); + for (int i = arr.size() - 1; i > 0; i--) { + if (rightMaxi.val > arr.get(i).val) { + arr.get(i - 1).next = rightMaxi; + } else { + rightMaxi = arr.get(i); + } + } + + return arr.get(0).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* removeNodes(ListNode* head) { + vector arr; + arr.push_back(new ListNode(0, head)); + ListNode* cur = head; + + while (cur) { + arr.push_back(cur); + cur = cur->next; + } + + ListNode* rightMaxi = new ListNode(0, nullptr); + for (int i = arr.size() - 1; i > 0; i--) { + if (rightMaxi->val > arr[i]->val) { + arr[i - 1]->next = rightMaxi; + } else { + rightMaxi = arr[i]; + } + } + + return arr[0]->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} + */ + removeNodes(head) { + let cur = head, arr = [{ val: 0, next: head }]; + while (cur) { + arr.push(cur); + cur = cur.next; + } + + let rightMaxi = { val: 0, next: null }; + for (let i = arr.length - 1; i > 0; i--) { + if (rightMaxi.val > arr[i].val) { + arr[i - 1].next = rightMaxi; + } else { + rightMaxi = arr[i]; + } + } + + return arr[0].next; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 2. Monotonic Decreasing Stack + +::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 removeNodes(self, head: Optional[ListNode]) -> Optional[ListNode]: + stack = [] + cur = head + + while cur: + while stack and cur.val > stack[-1]: + stack.pop() + stack.append(cur.val) + cur = cur.next + + dummy = ListNode() + cur = dummy + + for num in stack: + cur.next = ListNode(num) + cur = cur.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 removeNodes(ListNode head) { + Stack stack = new Stack<>(); + ListNode cur = head; + + while (cur != null) { + while (!stack.isEmpty() && cur.val > stack.peek()) { + stack.pop(); + } + stack.push(cur.val); + cur = cur.next; + } + + ListNode dummy = new ListNode(); + cur = dummy; + + for (int num : stack) { + cur.next = new ListNode(num); + cur = cur.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* removeNodes(ListNode* head) { + vector stack; + ListNode* cur = head; + + while (cur) { + while (!stack.empty() && cur->val > stack.back()) { + stack.pop_back(); + } + stack.push_back(cur->val); + cur = cur->next; + } + + ListNode* dummy = new ListNode(); + cur = dummy; + + for (int num : stack) { + cur->next = new ListNode(num); + cur = cur->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} + */ + removeNodes(head) { + let stack = []; + let cur = head; + + while (cur) { + while (stack.length && cur.val > stack[stack.length - 1]) { + stack.pop(); + } + stack.push(cur.val); + cur = cur.next; + } + + let dummy = new ListNode(); + cur = dummy; + + for (let num of stack) { + cur.next = new ListNode(num); + cur = cur.next; + } + + return dummy.next; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 3. Recursion + +::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 removeNodes(self, head: Optional[ListNode]) -> Optional[ListNode]: + if not head: + return None + + head.next = self.removeNodes(head.next) + if head.next and head.val < head.next.val: + return head.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 removeNodes(ListNode head) { + if (head == null) return null; + + head.next = removeNodes(head.next); + if (head.next != null && head.val < head.next.val) { + return head.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* removeNodes(ListNode* head) { + if (!head) return nullptr; + + head->next = removeNodes(head->next); + if (head->next && head->val < head->next->val) { + return head->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} + */ + removeNodes(head) { + if (!head) return null; + + head.next = this.removeNodes(head.next); + if (head.next && head.val < head.next.val) { + return head.next; + } + return head; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ for recursion stack. + +--- + +## 4. Reverse Twice + +::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 removeNodes(self, head: Optional[ListNode]) -> Optional[ListNode]: + def reverse(head): + prev, cur = None, head + while cur: + tmp = cur.next + cur.next = prev + prev, cur = cur, tmp + return prev + + head = reverse(head) + cur = head + cur_max = head.val + + while cur and cur.next: + if cur.next.val < cur_max: + cur.next = cur.next.next + else: + cur_max = cur.next.val + cur = cur.next + + return reverse(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 removeNodes(ListNode head) { + head = reverse(head); + ListNode cur = head; + int curMax = head.val; + + while (cur != null && cur.next != null) { + if (cur.next.val < curMax) { + cur.next = cur.next.next; + } else { + curMax = cur.next.val; + cur = cur.next; + } + } + return reverse(head); + } + + private ListNode reverse(ListNode head) { + ListNode prev = null, cur = head; + while (cur != null) { + ListNode tmp = cur.next; + cur.next = prev; + prev = cur; + cur = tmp; + } + return prev; + } +} +``` + +```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* reverse(ListNode* head) { + ListNode* prev = nullptr; + ListNode* cur = head; + while (cur) { + ListNode* tmp = cur->next; + cur->next = prev; + prev = cur; + cur = tmp; + } + return prev; + } + + ListNode* removeNodes(ListNode* head) { + head = reverse(head); + ListNode* cur = head; + int cur_max = head->val; + + while (cur && cur->next) { + if (cur->next->val < cur_max) { + cur->next = cur->next->next; + } else { + cur_max = cur->next->val; + cur = cur->next; + } + } + return reverse(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} + */ + removeNodes(head) { + const reverse = (head) => { + let prev = null, cur = head; + while (cur) { + let tmp = cur.next; + cur.next = prev; + prev = cur; + cur = tmp; + } + return prev; + }; + + head = reverse(head); + let cur = head; + let cur_max = head.val; + + while (cur && cur.next) { + if (cur.next.val < cur_max) { + cur.next = cur.next.next; + } else { + cur_max = cur.next.val; + cur = cur.next; + } + } + return reverse(head); + } +} +``` + +::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/reorder-routes-to-make-all-paths-lead-to-the-city-zero.md b/articles/reorder-routes-to-make-all-paths-lead-to-the-city-zero.md new file mode 100644 index 000000000..ae2727f84 --- /dev/null +++ b/articles/reorder-routes-to-make-all-paths-lead-to-the-city-zero.md @@ -0,0 +1,385 @@ +## 1. Depth First Search - I + +::tabs-start + +```python +class Solution: + def minReorder(self, n: int, connections: List[List[int]]) -> int: + edges = {(a, b) for a, b in connections} + neighbors = {city: [] for city in range(n)} + visit = set() + changes = 0 + + for a, b in connections: + neighbors[a].append(b) + neighbors[b].append(a) + + def dfs(city): + nonlocal changes + visit.add(city) + for neighbor in neighbors[city]: + if neighbor in visit: + continue + if (neighbor, city) not in edges: + changes += 1 + dfs(neighbor) + + dfs(0) + return changes +``` + +```java +public class Solution { + private Map> neighbors; + private boolean[] visit; + private Set edges; + + public int minReorder(int n, int[][] connections) { + edges = new HashSet<>(); + neighbors = new HashMap<>(); + visit = new boolean[n]; + int[] changes = {0}; + + for (int[] conn : connections) { + int a = conn[0], b = conn[1]; + edges.add(a + "," + b); + neighbors.computeIfAbsent(a, k -> new ArrayList<>()).add(b); + neighbors.computeIfAbsent(b, k -> new ArrayList<>()).add(a); + } + + dfs(0, changes); + return changes[0]; + } + + private void dfs(int city, int[] changes) { + visit[city] = true; + for (int neighbor : neighbors.get(city)) { + if (visit[neighbor]) continue; + if (!edges.contains(neighbor + "," + city)) { + changes[0]++; + } + dfs(neighbor, changes); + } + } +} +``` + +```cpp +class Solution { +public: + int minReorder(int n, vector>& connections) { + unordered_set edges; + unordered_map> neighbors; + vector visit(n, false); + int changes = 0; + + for (auto& c : connections) { + edges.insert(to_string(c[0]) + "," + to_string(c[1])); + neighbors[c[0]].push_back(c[1]); + neighbors[c[1]].push_back(c[0]); + } + + function dfs = [&](int city) { + visit[city] = true; + for (int neighbor : neighbors[city]) { + if (visit[neighbor]) continue; + if (edges.find(to_string(neighbor) + "," + to_string(city)) == edges.end()) { + changes++; + } + dfs(neighbor); + } + }; + + dfs(0); + return changes; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number[][]} connections + * @return {number} + */ + minReorder(n, connections) { + const edges = new Set(); + const neighbors = Array.from({ length: n }, () => []); + const visit = new Array(n).fill(false); + let changes = 0; + + for (const [a, b] of connections) { + edges.add(`${a},${b}`); + neighbors[a].push(b); + neighbors[b].push(a); + } + + const dfs = (city) => { + visit[city] = true; + for (const neighbor of neighbors[city]) { + if (visit[neighbor]) continue; + if (!edges.has(`${neighbor},${city}`)) changes++; + dfs(neighbor); + } + }; + + dfs(0); + return changes; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 2. Depth First Search - II + +::tabs-start + +```python +class Solution: + def minReorder(self, n: int, connections: List[List[int]]) -> int: + adj = [[] for _ in range(n)] + for u, v in connections: + adj[u].append(v) + adj[v].append(-u) + + def dfs(node, parent): + changes = 0 + for nei in adj[node]: + if abs(nei) == parent: + continue + changes += dfs(abs(nei), node) + (nei > 0) + return changes + + return dfs(0, -1) +``` + +```java +public class Solution { + public int minReorder(int n, int[][] connections) { + List> adj = new ArrayList<>(); + for (int i = 0; i < n; i++) adj.add(new ArrayList<>()); + + for (int[] conn : connections) { + adj.get(conn[0]).add(conn[1]); + adj.get(conn[1]).add(-conn[0]); + } + + return dfs(0, -1, adj); + } + + private int dfs(int node, int parent, List> adj) { + int changes = 0; + for (int nei : adj.get(node)) { + if (Math.abs(nei) == parent) continue; + changes += dfs(Math.abs(nei), node, adj) + (nei > 0 ? 1 : 0); + } + return changes; + } +} +``` + +```cpp +class Solution { +public: + int minReorder(int n, vector>& connections) { + vector> adj(n); + for (auto& conn : connections) { + int u = conn[0], v = conn[1]; + adj[u].push_back(v); + adj[v].push_back(-u); + } + + return dfs(0, -1, adj); + } + +private: + int dfs(int node, int parent, vector>& adj) { + int changes = 0; + for (int nei : adj[node]) { + if (abs(nei) == parent) continue; + changes += dfs(abs(nei), node, adj) + (nei > 0); + } + return changes; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number[][]} connections + * @return {number} + */ + minReorder(n, connections) { + const adj = Array.from({ length: n }, () => []); + for (const [u, v] of connections) { + adj[u].push(v); + adj[v].push(-u); + } + + const dfs = (node, parent) => { + let changes = 0; + for (const nei of adj[node]) { + if (Math.abs(nei) === parent) continue; + changes += dfs(Math.abs(nei), node) + (nei > 0 ? 1 : 0); + } + return changes; + }; + + return dfs(0, -1); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 3. Breadth First Search + +::tabs-start + +```python +class Solution: + def minReorder(self, n: int, connections: List[List[int]]) -> int: + adj = [[] for _ in range(n)] + for u, v in connections: + adj[u].append((v, 1)) + adj[v].append((u, 0)) + + visit = [False] * n + queue = deque([0]) + visit[0] = True + changes = 0 + + while queue: + node = queue.popleft() + for neighbor, isForward in adj[node]: + if not visit[neighbor]: + visit[neighbor] = True + changes += isForward + queue.append(neighbor) + return changes +``` + +```java +public class Solution { + public int minReorder(int n, int[][] connections) { + List[] adj = new ArrayList[n]; + for (int i = 0; i < n; i++) adj[i] = new ArrayList<>(); + + for (int[] conn : connections) { + adj[conn[0]].add(new int[]{conn[1], 1}); + adj[conn[1]].add(new int[]{conn[0], 0}); + } + + boolean[] visited = new boolean[n]; + Queue queue = new LinkedList<>(); + queue.add(0); + visited[0] = true; + int changes = 0; + + while (!queue.isEmpty()) { + int node = queue.poll(); + for (int[] edge : adj[node]) { + int neighbor = edge[0], isForward = edge[1]; + if (!visited[neighbor]) { + visited[neighbor] = true; + changes += isForward; + queue.add(neighbor); + } + } + } + return changes; + } +} +``` + +```cpp +class Solution { +public: + int minReorder(int n, vector>& connections) { + vector>> adj(n); + for (auto& conn : connections) { + adj[conn[0]].push_back({conn[1], 1}); + adj[conn[1]].push_back({conn[0], 0}); + } + + vector visit(n, false); + queue q; + q.push(0); + visit[0] = true; + int changes = 0; + + while (!q.empty()) { + int node = q.front(); + q.pop(); + for (auto& [neighbor, isForward] : adj[node]) { + if (!visit[neighbor]) { + visit[neighbor] = true; + changes += isForward; + q.push(neighbor); + } + } + } + return changes; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number[][]} connections + * @return {number} + */ + minReorder(n, connections) { + const adj = Array.from({ length: n }, () => []); + for (const [u, v] of connections) { + adj[u].push([v, 1]); + adj[v].push([u, 0]); + } + + const visited = Array(n).fill(false); + const queue = new Queue(); + queue.push(0); + visited[0] = true; + let changes = 0; + + while (!queue.isEmpty()) { + const node = queue.pop(); + for (const [neighbor, isForward] of adj[node]) { + if (!visited[neighbor]) { + visited[neighbor] = true; + changes += isForward; + queue.push(neighbor); + } + } + } + return changes; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ \ No newline at end of file diff --git a/articles/restore-ip-addresses.md b/articles/restore-ip-addresses.md new file mode 100644 index 000000000..a0a6fd2b6 --- /dev/null +++ b/articles/restore-ip-addresses.md @@ -0,0 +1,278 @@ +## 1. Backtracking + +::tabs-start + +```python +class Solution: + def restoreIpAddresses(self, s: str) -> List[str]: + res = [] + if len(s) > 12: + return res + + def backtrack(i, dots, curIP): + if dots == 4 and i == len(s): + res.append(curIP[:-1]) + return + if dots > 4: + return + + for j in range(i, min(i + 3, len(s))): + if i != j and s[i] == "0": + continue + if int(s[i: j + 1]) < 256: + backtrack(j + 1, dots + 1, curIP + s[i: j + 1] + ".") + + backtrack(0, 0, "") + return res +``` + +```java +public class Solution { + public List restoreIpAddresses(String s) { + List res = new ArrayList<>(); + if (s.length() > 12) return res; + + backtrack(0, 0, "", s, res); + return res; + } + + private void backtrack(int i, int dots, String curIP, String s, List res) { + if (dots == 4 && i == s.length()) { + res.add(curIP.substring(0, curIP.length() - 1)); + return; + } + if (dots > 4) return; + + for (int j = i; j < Math.min(i + 3, s.length()); j++) { + if (i != j && s.charAt(i) == '0') continue; + if (Integer.parseInt(s.substring(i, j + 1)) < 256) { + backtrack(j + 1, dots + 1, curIP + s.substring(i, j + 1) + ".", s, res); + } + } + } +} +``` + +```cpp +class Solution { + vector res; + +public: + vector restoreIpAddresses(string s) { + if (s.length() > 12) return res; + backtrack(s, 0, 0, ""); + return res; + } + +private: + void backtrack(string& s, int i, int dots, string curIP) { + if (dots == 4 && i == s.size()) { + res.push_back(curIP.substr(0, curIP.size() - 1)); + return; + } + if (dots > 4) return; + + for (int j = i; j < min(i + 3, (int)s.size()); j++) { + if (i != j && s[i] == '0') continue; + if (stoi(s.substr(i, j - i + 1)) < 256) { + backtrack(s, j + 1, dots + 1, curIP + s.substr(i, j - i + 1) + "."); + } + } + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {string[]} + */ + restoreIpAddresses(s) { + const res = []; + if (s.length > 12) return res; + + const backtrack = (i, dots, curIP) => { + if (dots === 4 && i === s.length) { + res.push(curIP.slice(0, -1)); + return; + } + if (dots > 4) return; + + for (let j = i; j < Math.min(i + 3, s.length); j++) { + if (i !== j && s[i] === '0') continue; + if (parseInt(s.slice(i, j + 1)) < 256) { + backtrack(j + 1, dots + 1, curIP + s.slice(i, j + 1) + '.'); + } + } + }; + + backtrack(0, 0, ""); + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m ^ n * n)$ +* Space complexity: $O(m * n)$ + +> Where $m$ is equals to $3$ as there are at most three digits in a valid segment and $n$ is equals to $4$ as there are four segments in a valid IP. + +--- + +## 2. Iteration + +::tabs-start + +```python +class Solution: + def restoreIpAddresses(self, s: str) -> List[str]: + res = [] + if len(s) > 12: + return res + + def valid(num): + return len(num) == 1 or (int(num) < 256 and num[0] != "0") + + def add(s1, s2, s3, s4): + if s1 + s2 + s3 + s4 != len(s): + return + + num1 = s[:s1] + num2 = s[s1:s1+s2] + num3 = s[s1+s2:s1+s2+s3] + num4 = s[s1+s2+s3:] + if valid(num1) and valid(num2) and valid(num3) and valid(num4): + res.append(num1 + "." + num2 + "." + num3 + "." + num4) + + for seg1 in range(1, 4): + for seg2 in range(1, 4): + for seg3 in range(1, 4): + for seg4 in range(1, 4): + add(seg1, seg2, seg3, seg4) + + return res +``` + +```java +public class Solution { + public List restoreIpAddresses(String s) { + List res = new ArrayList<>(); + if (s.length() > 12) return res; + + for (int seg1 = 1; seg1 < 4; seg1++) { + for (int seg2 = 1; seg2 < 4; seg2++) { + for (int seg3 = 1; seg3 < 4; seg3++) { + for (int seg4 = 1; seg4 < 4; seg4++) { + if (seg1 + seg2 + seg3 + seg4 != s.length()) continue; + + String num1 = s.substring(0, seg1); + String num2 = s.substring(seg1, seg1 + seg2); + String num3 = s.substring(seg1 + seg2, seg1 + seg2 + seg3); + String num4 = s.substring(seg1 + seg2 + seg3); + + if (isValid(num1) && isValid(num2) && isValid(num3) && isValid(num4)) { + res.add(num1 + "." + num2 + "." + num3 + "." + num4); + } + } + } + } + } + return res; + } + + private boolean isValid(String num) { + if (num.length() > 1 && num.charAt(0) == '0') return false; + int value = Integer.parseInt(num); + return value <= 255; + } +} +``` + +```cpp +class Solution { +public: + vector restoreIpAddresses(string s) { + vector res; + if (s.size() > 12) return res; + + auto valid = [&](string& num) { + if (num.size() > 1 && num[0] == '0') return false; + int value = stoi(num); + return value <= 255; + }; + + for (int seg1 = 1; seg1 < 4; ++seg1) { + for (int seg2 = 1; seg2 < 4; ++seg2) { + for (int seg3 = 1; seg3 < 4; ++seg3) { + for (int seg4 = 1; seg4 < 4; ++seg4) { + if (seg1 + seg2 + seg3 + seg4 != s.size()) continue; + + string num1 = s.substr(0, seg1); + string num2 = s.substr(seg1, seg2); + string num3 = s.substr(seg1 + seg2, seg3); + string num4 = s.substr(seg1 + seg2 + seg3); + + if (valid(num1) && valid(num2) && valid(num3) && valid(num4)) { + res.push_back(num1 + "." + num2 + "." + num3 + "." + num4); + } + } + } + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {string[]} + */ + restoreIpAddresses(s) { + const res = []; + if (s.length > 12) return res; + + const isValid = (num) => { + if (num.length > 1 && num[0] === '0') return false; + const value = parseInt(num, 10); + return value <= 255; + }; + + for (let seg1 = 1; seg1 < 4; seg1++) { + for (let seg2 = 1; seg2 < 4; seg2++) { + for (let seg3 = 1; seg3 < 4; seg3++) { + for (let seg4 = 1; seg4 < 4; seg4++) { + if (seg1 + seg2 + seg3 + seg4 !== s.length) continue; + + const num1 = s.substring(0, seg1); + const num2 = s.substring(seg1, seg1 + seg2); + const num3 = s.substring(seg1 + seg2, seg1 + seg2 + seg3); + const num4 = s.substring(seg1 + seg2 + seg3); + + if (isValid(num1) && isValid(num2) && isValid(num3) && isValid(num4)) { + res.push(`${num1}.${num2}.${num3}.${num4}`); + } + } + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m ^ n * n)$ +* Space complexity: $O(m * n)$ + +> Where $m$ is equals to $3$ as there are at most three digits in a valid segment and $n$ is equals to $4$ as there are four segments in a valid IP. \ No newline at end of file diff --git a/articles/snakes-and-ladders.md b/articles/snakes-and-ladders.md new file mode 100644 index 000000000..afc71ef47 --- /dev/null +++ b/articles/snakes-and-ladders.md @@ -0,0 +1,572 @@ +## 1. Breadth First Search - I + +::tabs-start + +```python +class Solution: + def snakesAndLadders(self, board: List[List[int]]) -> int: + n = len(board) + + def intToPos(square): + r = (square - 1) // n + c = (square - 1) % n + if r % 2 == 1: + c = n - 1 - c + r = n - 1 - r + return r, c + + q = deque([(1, 0)]) + visit = set() + + while q: + square, moves = q.popleft() + + for i in range(1, 7): + nextSquare = square + i + r, c = intToPos(nextSquare) + if board[r][c] != -1: + nextSquare = board[r][c] + + if nextSquare == n * n: + return moves + 1 + + if nextSquare not in visit: + visit.add(nextSquare) + q.append((nextSquare, moves + 1)) + + return -1 +``` + +```java +public class Solution { + public int snakesAndLadders(int[][] board) { + int n = board.length; + Queue q = new LinkedList<>(); + q.offer(new int[]{1, 0}); + Set visit = new HashSet<>(); + + while (!q.isEmpty()) { + int[] cur = q.poll(); + int square = cur[0], moves = cur[1]; + + for (int i = 1; i <= 6; i++) { + int nextSquare = square + i; + int[] pos = intToPos(nextSquare, n); + int r = pos[0], c = pos[1]; + if (board[r][c] != -1) { + nextSquare = board[r][c]; + } + if (nextSquare == n * n) return moves + 1; + if (!visit.contains(nextSquare)) { + visit.add(nextSquare); + q.offer(new int[]{nextSquare, moves + 1}); + } + } + } + return -1; + } + + private int[] intToPos(int square, int n) { + int r = (square - 1) / n; + int c = (square - 1) % n; + if (r % 2 == 1) c = n - 1 - c; + r = n - 1 - r; + return new int[]{r, c}; + } +} +``` + +```cpp +class Solution { +public: + int snakesAndLadders(vector>& board) { + int n = board.size(); + queue> q; + q.push({1, 0}); + unordered_set visit; + + while (!q.empty()) { + auto [square, moves] = q.front(); q.pop(); + + for (int i = 1; i <= 6; i++) { + int nextSquare = square + i; + auto [r, c] = intToPos(nextSquare, n); + if (board[r][c] != -1) { + nextSquare = board[r][c]; + } + if (nextSquare == n * n) return moves + 1; + if (!visit.count(nextSquare)) { + visit.insert(nextSquare); + q.push({nextSquare, moves + 1}); + } + } + } + return -1; + } + +private: + pair intToPos(int square, int n) { + int r = (square - 1) / n; + int c = (square - 1) % n; + if (r % 2 == 1) c = n - 1 - c; + r = n - 1 - r; + return {r, c}; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} board + * @return {number} + */ + snakesAndLadders(board) { + const n = board.length; + const queue = new Queue([[1, 0]]); + const visit = new Set(); + + const intToPos = (square) => { + let r = Math.floor((square - 1) / n); + let c = (square - 1) % n; + if (r % 2 === 1) c = n - 1 - c; + r = n - 1 - r; + return [r, c]; + }; + + while (!queue.isEmpty()) { + const [square, moves] = queue.pop(); + + for (let i = 1; i <= 6; i++) { + let nextSquare = square + i; + const [r, c] = intToPos(nextSquare); + if (board[r][c] !== -1) { + nextSquare = board[r][c]; + } + if (nextSquare === n * n) return moves + 1; + if (!visit.has(nextSquare)) { + visit.add(nextSquare); + queue.push([nextSquare, moves + 1]); + } + } + } + return -1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n ^ 2)$ + +--- + +## 2. Breadth First Search - II + +::tabs-start + +```python +class Solution: + def snakesAndLadders(self, board: List[List[int]]) -> int: + n = len(board) + + def intToPos(square): + r = (square - 1) // n + c = (square - 1) % n + if r % 2 == 1: + c = n - 1 - c + r = n - 1 - r + return r, c + + dist = [-1] * (n * n + 1) + q = deque([1]) + dist[1] = 0 + + while q: + square = q.popleft() + + for i in range(1, 7): + nextSquare = square + i + if nextSquare > n * n: + break + + r, c = intToPos(nextSquare) + if board[r][c] != -1: + nextSquare = board[r][c] + + if dist[nextSquare] == -1: + dist[nextSquare] = dist[square] + 1 + if nextSquare == n * n: + return dist[nextSquare] + q.append(nextSquare) + + return -1 +``` + +```java +public class Solution { + public int snakesAndLadders(int[][] board) { + int n = board.length; + int[] dist = new int[n * n + 1]; + Arrays.fill(dist, -1); + Queue q = new LinkedList<>(); + q.add(1); + dist[1] = 0; + + while (!q.isEmpty()) { + int square = q.poll(); + + for (int i = 1; i <= 6; i++) { + int nextSquare = square + i; + if (nextSquare > n * n) { + break; + } + + int[] pos = intToPos(nextSquare, n); + int r = pos[0], c = pos[1]; + + if (board[r][c] != -1) { + nextSquare = board[r][c]; + } + + if (dist[nextSquare] == -1) { + dist[nextSquare] = dist[square] + 1; + if (nextSquare == n * n) { + return dist[nextSquare]; + } + q.add(nextSquare); + } + } + } + + return -1; + } + + private int[] intToPos(int square, int n) { + int r = (square - 1) / n; + int c = (square - 1) % n; + if (r % 2 == 1) { + c = n - 1 - c; + } + r = n - 1 - r; + return new int[]{r, c}; + } +} +``` + +```cpp +class Solution { +public: + int snakesAndLadders(vector>& board) { + int n = board.size(); + vector dist(n * n + 1, -1); + queue q; + q.push(1); + dist[1] = 0; + + while (!q.empty()) { + int square = q.front(); + q.pop(); + + for (int i = 1; i <= 6; i++) { + int nextSquare = square + i; + if (nextSquare > n * n) { + break; + } + + auto [r, c] = intToPos(nextSquare, n); + if (board[r][c] != -1) { + nextSquare = board[r][c]; + } + + if (dist[nextSquare] == -1) { + dist[nextSquare] = dist[square] + 1; + if (nextSquare == n * n) { + return dist[nextSquare]; + } + q.push(nextSquare); + } + } + } + + return -1; + } + +private: + pair intToPos(int square, int n) { + int r = (square - 1) / n; + int c = (square - 1) % n; + if (r % 2 == 1) { + c = n - 1 - c; + } + r = n - 1 - r; + return {r, c}; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} board + * @return {number} + */ + snakesAndLadders(board) { + const n = board.length; + const dist = new Array(n * n + 1).fill(-1); + const queue = new Queue([1]); + dist[1] = 0; + + const intToPos = (square) => { + let r = Math.floor((square - 1) / n); + let c = (square - 1) % n; + if (r % 2 === 1) c = n - 1 - c; + r = n - 1 - r; + return [r, c]; + }; + + while (!queue.isEmpty()) { + const square = queue.pop(); + + for (let i = 1; i <= 6; i++) { + let nextSquare = square + i; + if (nextSquare > n * n) break; + + const [r, c] = intToPos(nextSquare, n); + if (board[r][c] !== -1) { + nextSquare = board[r][c]; + } + + if (dist[nextSquare] === -1) { + dist[nextSquare] = dist[square] + 1; + if (nextSquare === n * n) { + return dist[nextSquare]; + } + queue.push(nextSquare); + } + } + } + + return -1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n ^ 2)$ + +--- + +## 3. Breadth First Search - III + +::tabs-start + +```python +class Solution: + def snakesAndLadders(self, board: List[List[int]]) -> int: + n = len(board) + + def intToPos(square): + r = (square - 1) // n + c = (square - 1) % n + if r % 2 == 1: + c = n - 1 - c + r = n - 1 - r + return r, c + + q = deque([1]) + board[n - 1][0] = 0 + moves = 0 + + while q: + for _ in range(len(q)): + square = q.popleft() + + for i in range(1, 7): + nextSquare = square + i + if nextSquare > n * n: + break + + r, c = intToPos(nextSquare) + if board[r][c] != -1: + nextSquare = board[r][c] + + if board[r][c] != 0: + if nextSquare == n * n: + return moves + 1 + q.append(nextSquare) + board[r][c] = 0 + moves += 1 + + return -1 +``` + +```java +public class Solution { + public int snakesAndLadders(int[][] board) { + int n = board.length; + Queue q = new LinkedList<>(); + q.add(1); + board[n - 1][0] = 0; + int moves = 0; + + while (!q.isEmpty()) { + for (int it = q.size(); it > 0; it--) { + int square = q.poll(); + for (int i = 1; i <= 6; i++) { + int nextSquare = square + i; + if (nextSquare > n * n) { + break; + } + + int[] pos = intToPos(nextSquare, n); + int r = pos[0], c = pos[1]; + + if (board[r][c] != -1) { + nextSquare = board[r][c]; + } + + if (board[r][c] != 0) { + if (nextSquare == n * n) { + return moves + 1; + } + + board[r][c] = 0; + q.add(nextSquare); + } + } + } + moves++; + } + + return -1; + } + + private int[] intToPos(int square, int n) { + int r = (square - 1) / n; + int c = (square - 1) % n; + if (r % 2 == 1) { + c = n - 1 - c; + } + r = n - 1 - r; + return new int[]{r, c}; + } +} +``` + +```cpp +class Solution { +public: + int snakesAndLadders(vector>& board) { + int n = board.size(); + queue q; + q.push(1); + board[n - 1][0] = 0; + int moves = 0; + + while (!q.empty()) { + for (int it = q.size(); it > 0; it--) { + int square = q.front(); q.pop(); + for (int i = 1; i <= 6; i++) { + int nextSquare = square + i; + if (nextSquare > n * n) { + break; + } + + auto [r, c] = intToPos(nextSquare, n); + if (board[r][c] != -1) { + nextSquare = board[r][c]; + } + + if (board[r][c] != 0) { + if (nextSquare == n * n) { + return moves + 1; + } + + board[r][c] = 0; + q.push(nextSquare); + } + } + } + moves++; + } + + return -1; + } + +private: + pair intToPos(int square, int n) { + int r = (square - 1) / n; + int c = (square - 1) % n; + if (r % 2 == 1) { + c = n - 1 - c; + } + r = n - 1 - r; + return {r, c}; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} board + * @return {number} + */ + snakesAndLadders(board) { + const n = board.length; + const queue = new Queue([1]); + board[n - 1][0] = 0; + + const intToPos = (square) => { + let r = Math.floor((square - 1) / n); + let c = (square - 1) % n; + if (r % 2 === 1) c = n - 1 - c; + r = n - 1 - r; + return [r, c]; + }; + + let moves = 0; + while (!queue.isEmpty()) { + for (let it = queue.size(); it > 0; it--) { + const square = queue.pop(); + for (let i = 1; i <= 6; i++) { + let nextSquare = square + i; + if (nextSquare > n * n) break; + + const [r, c] = intToPos(nextSquare, n); + if (board[r][c] !== -1) { + nextSquare = board[r][c]; + } + + if (board[r][c] !== 0) { + if (nextSquare === n * n) { + return moves + 1; + } + + board[r][c] = 0; + queue.push(nextSquare); + } + } + } + moves++; + } + + return -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/sum-of-all-subset-xor-totals.md b/articles/sum-of-all-subset-xor-totals.md new file mode 100644 index 000000000..b1f8dc9ae --- /dev/null +++ b/articles/sum-of-all-subset-xor-totals.md @@ -0,0 +1,341 @@ +## 1. Backtracking + +::tabs-start + +```python +class Solution: + def subsetXORSum(self, nums: List[int]) -> int: + res = 0 + + def backtrack(i, subset): + nonlocal res + xorr = 0 + for num in subset: + xorr ^= num + res += xorr + + for j in range(i, len(nums)): + subset.append(nums[j]) + backtrack(j + 1, subset) + subset.pop() + + backtrack(0, []) + return res +``` + +```java +public class Solution { + int res = 0; + + public int subsetXORSum(int[] nums) { + backtrack(0, nums, new ArrayList<>()); + return res; + } + + private void backtrack(int i, int[] nums, List subset) { + int xorr = 0; + for (int num : subset) xorr ^= num; + res += xorr; + + for (int j = i; j < nums.length; j++) { + subset.add(nums[j]); + backtrack(j + 1, nums, subset); + subset.remove(subset.size() - 1); + } + } +} +``` + +```cpp +class Solution { +public: + int subsetXORSum(vector& nums) { + int res = 0; + vector subset; + + function backtrack = [&](int i) { + int xorr = 0; + for (int num : subset) xorr ^= num; + res += xorr; + + for (int j = i; j < nums.size(); ++j) { + subset.push_back(nums[j]); + backtrack(j + 1); + subset.pop_back(); + } + }; + + backtrack(0); + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + subsetXORSum(nums) { + let res = 0; + + const backtrack = (i, subset) => { + let xorr = 0; + for (let num of subset) xorr ^= num; + res += xorr; + + for (let j = i; j < nums.length; j++) { + subset.push(nums[j]); + backtrack(j + 1, subset); + subset.pop(); + } + }; + + backtrack(0, []); + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * 2 ^ n)$ +* Space complexity: $O(n)$ + +--- + +## 2. Recursion + +::tabs-start + +```python +class Solution: + def subsetXORSum(self, nums: List[int]) -> int: + def dfs(i, total): + if i == len(nums): + return total + return dfs(i + 1, total ^ nums[i]) + dfs(i + 1, total) + + return dfs(0, 0) +``` + +```java +public class Solution { + public int subsetXORSum(int[] nums) { + return dfs(nums, 0, 0); + } + + private int dfs(int[] nums, int i, int total) { + if (i == nums.length) { + return total; + } + return dfs(nums, i + 1, total ^ nums[i]) + dfs(nums, i + 1, total); + } +} +``` + +```cpp +class Solution { +public: + int subsetXORSum(vector& nums) { + return dfs(nums, 0, 0); + } + +private: + int dfs(vector& nums, int i, int total) { + if (i == nums.size()) { + return total; + } + return dfs(nums, i + 1, total ^ nums[i]) + dfs(nums, i + 1, total); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + subsetXORSum(nums) { + const dfs = (i, total) => { + if (i === nums.length) { + return total; + } + return dfs(i + 1, total ^ nums[i]) + dfs(i + 1, total); + }; + + return dfs(0, 0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(2 ^ n)$ +* Space complexity: $O(n)$ for recursion stack. + +--- + +## 3. Bit Manipulation + +::tabs-start + +```python +class Solution: + def subsetXORSum(self, nums: List[int]) -> int: + n = len(nums) + res = 0 + + for mask in range(1 << n): + xorr = 0 + for i in range(n): + if mask & (1 << i): + xorr ^= nums[i] + res += xorr + + return res +``` + +```java +public class Solution { + public int subsetXORSum(int[] nums) { + int n = nums.length; + int res = 0; + + for (int mask = 0; mask < (1 << n); mask++) { + int xorr = 0; + for (int i = 0; i < n; i++) { + if ((mask & ( 1 << i)) != 0) { + xorr ^= nums[i]; + } + } + res += xorr; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int subsetXORSum(vector& nums) { + int n = nums.size(); + int res = 0; + + for (int mask = 0; mask < (1 << n); mask++) { + int xorr = 0; + for (int i = 0; i < n; i++) { + if ((mask & ( 1 << i)) != 0) { + xorr ^= nums[i]; + } + } + res += xorr; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + subsetXORSum(nums) { + const n = nums.length; + let res = 0; + + for (let mask = 0; mask < (1 << n); mask++) { + let xorr = 0; + for (let i = 0; i < n; i++) { + if ((mask & ( 1 << i)) !== 0) { + xorr ^= nums[i]; + } + } + res += xorr; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * 2 ^ n)$ +* Space complexity: $O(1)$ extra space. + +--- + +## 4. Bit Manipulation (Optimal) + +::tabs-start + +```python +class Solution: + def subsetXORSum(self, nums: List[int]) -> int: + res = 0 + for num in nums: + res |= num + return res << (len(nums) - 1) +``` + +```java +public class Solution { + public int subsetXORSum(int[] nums) { + int res = 0; + for (int num : nums) { + res |= num; + } + return res << (nums.length - 1); + } +} +``` + +```cpp +class Solution { +public: + int subsetXORSum(vector& nums) { + int res = 0; + for (int& num : nums) { + res |= num; + } + return res << (nums.size() - 1); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + subsetXORSum(nums) { + let res = 0; + for (let num of nums) { + res |= num; + } + return res << (nums.length - 1); + } +} +``` + +::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/verifying-an-alien-dictionary.md b/articles/verifying-an-alien-dictionary.md new file mode 100644 index 000000000..7ab6ac58d --- /dev/null +++ b/articles/verifying-an-alien-dictionary.md @@ -0,0 +1,211 @@ +## 1. Sorting + +::tabs-start + +```python +class Solution: + def isAlienSorted(self, words: List[str], order: str) -> bool: + order_index = {c: i for i, c in enumerate(order)} + + def compare(word): + return [order_index[c] for c in word] + + return words == sorted(words, key=compare) +``` + +```java +public class Solution { + public boolean isAlienSorted(String[] words, String order) { + int[] orderIndex = new int[26]; + for (int i = 0; i < order.length(); i++) + orderIndex[order.charAt(i) - 'a'] = i; + + Comparator compare = (w1, w2) -> { + for (int i = 0; i < Math.min(w1.length(), w2.length()); i++) { + if (w1.charAt(i) != w2.charAt(i)) + return orderIndex[w1.charAt(i) - 'a'] - orderIndex[w2.charAt(i) - 'a']; + } + return w1.length() - w2.length(); + }; + + String[] sortedWords = words.clone(); + Arrays.sort(sortedWords, compare); + return Arrays.equals(words, sortedWords); + } +} +``` + +```cpp +class Solution { +public: + bool isAlienSorted(vector& words, string order) { + int orderIndex[26]; + for (int i = 0; i < order.size(); ++i) + orderIndex[order[i] - 'a'] = i; + + auto compare = [&](const string &a, const string &b) { + for (int i = 0; i < min(a.size(), b.size()); ++i) { + if (a[i] != b[i]) + return orderIndex[a[i] - 'a'] < orderIndex[b[i] - 'a']; + } + return a.size() < b.size(); + }; + + return is_sorted(words.begin(), words.end(), compare); + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} words + * @param {string} order + * @return {boolean} + */ + isAlienSorted(words, order) { + let orderIndex = new Array(26).fill(0); + for (let i = 0; i < order.length; i++) { + orderIndex[order.charCodeAt(i) - 97] = i; + } + + const compare = (w1, w2) => { + for (let i = 0; i < Math.min(w1.length, w2.length); i++) { + if (w1[i] !== w2[i]) { + return orderIndex[w1.charCodeAt(i) - 97] - orderIndex[w2.charCodeAt(i) - 97]; + } + } + return w1.length - w2.length; + }; + + let sortedWords = [...words].sort(compare); + return words.join() === sortedWords.join(); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * m\log n)$ +* Space complexity: $O(n * m)$ + +> Where $n$ is the number of words and $m$ is the average length of a word. + +--- + +## 2. Comparing adjacent words + +::tabs-start + +```python +class Solution: + def isAlienSorted(self, words: List[str], order: str) -> bool: + order_index = {c: i for i, c in enumerate(order)} + + for i in range(len(words) - 1): + w1, w2 = words[i], words[i + 1] + + for j in range(len(w1)): + if j == len(w2): + return False + + if w1[j] != w2[j]: + if order_index[w1[j]] > order_index[w2[j]]: + return False + break + return True +``` + +```java +public class Solution { + public boolean isAlienSorted(String[] words, String order) { + int[] orderIndex = new int[26]; + for (int i = 0; i < order.length(); i++) + orderIndex[order.charAt(i) - 'a'] = i; + + for (int i = 0; i < words.length - 1; i++) { + String w1 = words[i], w2 = words[i + 1]; + int j = 0; + + for (; j < w1.length(); j++) { + if (j == w2.length()) return false; + if (w1.charAt(j) != w2.charAt(j)) { + if (orderIndex[w1.charAt(j) - 'a'] > orderIndex[w2.charAt(j) - 'a']) { + return false; + } + break; + } + } + } + return true; + } +} +``` + +```cpp +class Solution { +public: + bool isAlienSorted(vector& words, string order) { + int orderIndex[26] = {0}; + for (int i = 0; i < order.size(); ++i) + orderIndex[order[i] - 'a'] = i; + + for (int i = 0; i < words.size() - 1; ++i) { + string w1 = words[i], w2 = words[i + 1]; + int j = 0; + + for (; j < w1.size(); ++j) { + if (j == w2.size()) return false; + if (w1[j] != w2[j]) { + if (orderIndex[w1[j] - 'a'] > orderIndex[w2[j] - 'a']) + return false; + break; + } + } + } + return true; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} words + * @param {string} order + * @return {boolean} + */ + isAlienSorted(words, order) { + let orderIndex = new Array(26).fill(0); + for (let i = 0; i < order.length; i++) { + orderIndex[order.charCodeAt(i) - 97] = i; + } + + for (let i = 0; i < words.length - 1; i++) { + let w1 = words[i], w2 = words[i + 1]; + + for (let j = 0; j < w1.length; j++) { + if (j === w2.length) return false; + + if (w1[j] !== w2[j]) { + if (orderIndex[w1.charCodeAt(j) - 97] > orderIndex[w2.charCodeAt(j) - 97]) + return false; + break; + } + } + } + return true; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * m)$ +* Space complexity: $O(1)$ since we have $26$ different characters. + +> Where $n$ is the number of words and $m$ is the average length of a word. \ No newline at end of file