From b0e7b545b75f7fe0904b3447c49291fa97775f4d Mon Sep 17 00:00:00 2001 From: Sri Hari <94112314+Srihari2222@users.noreply.github.com> Date: Fri, 14 Feb 2025 19:04:57 +0530 Subject: [PATCH 01/12] Sri Hari: Batch-5/Neetcode-ALL/Added-articles (#3841) * Batch-5/Neetcode-ALL/Added-articles * Batch-5/Neetcode-ALL/Added-articles * Batch-5/Neetcode-ALL/Added-articles * Batch-5/Neetcode-ALL/Added-articles * Batch-5/Neetcode-ALL/Added-articles * Batch-5/Neetcode-ALL/Added-articles * Batch-5/Neetcode-ALL/Added-articles * Batch-5/Neetcode-ALL/Added-articles * Batch-5/Neetcode-ALL/Added-articles * Batch-5/Neetcode-ALL/Added-articles * Batch-5/Neetcode-ALL/Added-articles * Batch-5/Neetcode-ALL/Added-articles * Batch-5/Neetcode-ALL/Added-articles --- articles/all-possible-full-binary-trees.md | 693 +++++++++++ articles/binary-search-tree-iterator.md | 699 +++++++++++ articles/concatenated-words.md | 587 +++++++++ ...t-all-valid-pickup-and-delivery-options.md | 668 +++++++++++ articles/data-stream-as-disjoint-intervals.md | 450 +++++++ articles/design-browser-history.md | 640 ++++++++++ articles/detonate-the-maximum-bombs.md | 522 ++++++++ articles/distribute-coins-in-binary-tree.md | 723 +++++++++++ .../eliminate-maximum-number-of-monsters.md | 298 +++++ articles/find-all-people-with-secret.md | 834 +++++++++++++ .../find-the-maximum-sum-of-node-values.md | 637 ++++++++++ articles/find-the-safest-path-in-a-grid.md | 1054 +++++++++++++++++ articles/find-unique-binary-string.md | 685 +++++++++++ articles/furthest-building-you-can-reach.md | 723 +++++++++++ articles/integer-to-roman.md | 195 +++ articles/is-graph-bipartite.md | 611 ++++++++++ articles/knight-dialer.md | 946 +++++++++++++++ ...largest-color-value-in-a-directed-graph.md | 589 +++++++++ articles/largest-divisible-subset.md | 738 ++++++++++++ .../largest-submatrix-with-rearrangements.md | 522 ++++++++ articles/maximize-score-after-n-operations.md | 629 ++++++++++ ...lement-after-decreasing-and-rearranging.md | 158 +++ ...catenated-string-with-unique-characters.md | 857 ++++++++++++++ articles/maximum-length-of-pair-chain.md | 556 +++++++++ ...aximum-nesting-depth-of-the-parentheses.md | 305 +++++ ...aximum-points-you-can-obtain-from-cards.md | 462 ++++++++ articles/maximum-score-of-a-good-subarray.md | 729 ++++++++++++ .../maximum-score-words-formed-by-letters.md | 676 +++++++++++ articles/minimize-maximum-of-array.md | 210 ++++ ...ns-to-make-character-frequencies-unique.md | 348 ++++++ ...imum-number-of-arrows-to-burst-balloons.md | 183 +++ ...minimum-number-of-days-to-eat-n-oranges.md | 354 ++++++ ...m-number-of-vertices-to-reach-all-nodes.md | 465 ++++++++ ...ne-bit-operations-to-make-integers-zero.md | 313 +++++ articles/number-of-good-paths.md | 861 ++++++++++++++ articles/number-of-laser-beams-in-a-bank.md | 110 ++ ...umber-of-ways-to-divide-a-long-corridor.md | 608 ++++++++++ articles/operations-on-tree.md | 806 +++++++++++++ articles/parallel-courses-iii.md | 481 ++++++++ articles/partition-array-for-maximum-sum.md | 446 +++++++ articles/path-with-maximum-gold.md | 508 ++++++++ articles/path-with-maximum-probability.md | 632 ++++++++++ ...es-if-both-neighbors-are-the-same-color.md | 322 +++++ articles/remove-covered-intervals.md | 275 +++++ ...f-edges-to-keep-graph-fully-traversable.md | 274 +++++ articles/reveal-cards-in-increasing-order.md | 406 +++++++ articles/rotate-list.md | 486 ++++++++ articles/score-after-flipping-matrix.md | 253 ++++ ...ring-into-descending-consecutive-values.md | 570 +++++++++ articles/the-number-of-beautiful-subsets.md | 739 ++++++++++++ articles/two-city-scheduling.md | 683 +++++++++++ ...between-two-points-containing-no-points.md | 212 ++++ 52 files changed, 27731 insertions(+) create mode 100644 articles/all-possible-full-binary-trees.md create mode 100644 articles/binary-search-tree-iterator.md create mode 100644 articles/concatenated-words.md create mode 100644 articles/count-all-valid-pickup-and-delivery-options.md create mode 100644 articles/data-stream-as-disjoint-intervals.md create mode 100644 articles/design-browser-history.md create mode 100644 articles/detonate-the-maximum-bombs.md create mode 100644 articles/distribute-coins-in-binary-tree.md create mode 100644 articles/eliminate-maximum-number-of-monsters.md create mode 100644 articles/find-all-people-with-secret.md create mode 100644 articles/find-the-maximum-sum-of-node-values.md create mode 100644 articles/find-the-safest-path-in-a-grid.md create mode 100644 articles/find-unique-binary-string.md create mode 100644 articles/furthest-building-you-can-reach.md create mode 100644 articles/integer-to-roman.md create mode 100644 articles/is-graph-bipartite.md create mode 100644 articles/knight-dialer.md create mode 100644 articles/largest-color-value-in-a-directed-graph.md create mode 100644 articles/largest-divisible-subset.md create mode 100644 articles/largest-submatrix-with-rearrangements.md create mode 100644 articles/maximize-score-after-n-operations.md create mode 100644 articles/maximum-element-after-decreasing-and-rearranging.md create mode 100644 articles/maximum-length-of-a-concatenated-string-with-unique-characters.md create mode 100644 articles/maximum-length-of-pair-chain.md create mode 100644 articles/maximum-nesting-depth-of-the-parentheses.md create mode 100644 articles/maximum-points-you-can-obtain-from-cards.md create mode 100644 articles/maximum-score-of-a-good-subarray.md create mode 100644 articles/maximum-score-words-formed-by-letters.md create mode 100644 articles/minimize-maximum-of-array.md create mode 100644 articles/minimum-deletions-to-make-character-frequencies-unique.md create mode 100644 articles/minimum-number-of-arrows-to-burst-balloons.md create mode 100644 articles/minimum-number-of-days-to-eat-n-oranges.md create mode 100644 articles/minimum-number-of-vertices-to-reach-all-nodes.md create mode 100644 articles/minimum-one-bit-operations-to-make-integers-zero.md create mode 100644 articles/number-of-good-paths.md create mode 100644 articles/number-of-laser-beams-in-a-bank.md create mode 100644 articles/number-of-ways-to-divide-a-long-corridor.md create mode 100644 articles/operations-on-tree.md create mode 100644 articles/parallel-courses-iii.md create mode 100644 articles/partition-array-for-maximum-sum.md create mode 100644 articles/path-with-maximum-gold.md create mode 100644 articles/path-with-maximum-probability.md create mode 100644 articles/remove-colored-pieces-if-both-neighbors-are-the-same-color.md create mode 100644 articles/remove-covered-intervals.md create mode 100644 articles/remove-max-number-of-edges-to-keep-graph-fully-traversable.md create mode 100644 articles/reveal-cards-in-increasing-order.md create mode 100644 articles/rotate-list.md create mode 100644 articles/score-after-flipping-matrix.md create mode 100644 articles/splitting-a-string-into-descending-consecutive-values.md create mode 100644 articles/the-number-of-beautiful-subsets.md create mode 100644 articles/two-city-scheduling.md create mode 100644 articles/widest-vertical-area-between-two-points-containing-no-points.md diff --git a/articles/all-possible-full-binary-trees.md b/articles/all-possible-full-binary-trees.md new file mode 100644 index 000000000..1e75b0293 --- /dev/null +++ b/articles/all-possible-full-binary-trees.md @@ -0,0 +1,693 @@ +## 1. Recursion + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def allPossibleFBT(self, n: int) -> List[Optional[TreeNode]]: + def backtrack(n): + if n == 0: + return [] + if n == 1: + return [TreeNode(0)] + + res = [] + for l in range(n): + r = n - 1 - l + leftTrees, rightTrees = backtrack(l), backtrack(r) + + for t1 in leftTrees: + for t2 in rightTrees: + res.append(TreeNode(0, t1, t2)) + return res + + return backtrack(n) +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public List allPossibleFBT(int n) { + return backtrack(n); + } + + private List backtrack(int n) { + if (n == 0) { + return new ArrayList<>(); + } + if (n == 1) { + return Arrays.asList(new TreeNode(0)); + } + + List res = new ArrayList<>(); + for (int l = 0; l < n; l++) { + int r = n - 1 - l; + List leftTrees = backtrack(l); + List rightTrees = backtrack(r); + + for (TreeNode t1 : leftTrees) { + for (TreeNode t2 : rightTrees) { + res.add(new TreeNode(0, t1, t2)); + } + } + } + return res; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + vector allPossibleFBT(int n) { + return backtrack(n); + } + +private: + vector backtrack(int n) { + if (n == 0) { + return {}; + } + if (n == 1) { + return {new TreeNode(0)}; + } + + vector res; + for (int l = 0; l < n; l++) { + int r = n - 1 - l; + vector leftTrees = backtrack(l); + vector rightTrees = backtrack(r); + + for (auto& t1 : leftTrees) { + for (auto& t2 : rightTrees) { + res.push_back(new TreeNode(0, t1, t2)); + } + } + } + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {number} n + * @return {TreeNode[]} + */ + allPossibleFBT(n) { + const backtrack = (n) => { + if (n === 0) { + return []; + } + if (n === 1) { + return [new TreeNode(0)]; + } + + let res = []; + for (let l = 0; l < n; l++) { + let r = n - 1 - l; + let leftTrees = backtrack(l); + let rightTrees = backtrack(r); + + for (let t1 of leftTrees) { + for (let t2 of rightTrees) { + res.push(new TreeNode(0, t1, t2)); + } + } + } + return res; + }; + + return backtrack(n); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(2 ^ n)$ +* Space complexity: $O(n * 2 ^ n)$ + +--- + +## 2. Recursion (Optimal) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def allPossibleFBT(self, n: int) -> List[Optional[TreeNode]]: + if n % 2 == 0: + return [] + if n == 1: + return [TreeNode(0)] + + res = [] + for left in range(1, n, 2): + leftSubTree = self.allPossibleFBT(left) + rightSubTree = self.allPossibleFBT(n - 1 - left) + for l in leftSubTree: + for r in rightSubTree: + root = TreeNode(0, l, r) + res.append(root) + return res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public List allPossibleFBT(int n) { + if (n % 2 == 0) { + return new ArrayList<>(); + } + if (n == 1) { + return Arrays.asList(new TreeNode(0)); + } + + List res = new ArrayList<>(); + for (int left = 1; left < n; left += 2) { + List leftSubTree = allPossibleFBT(left); + List rightSubTree = allPossibleFBT(n - 1 - left); + for (TreeNode l : leftSubTree) { + for (TreeNode r : rightSubTree) { + TreeNode root = new TreeNode(0, l, r); + res.add(root); + } + } + } + return res; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + vector allPossibleFBT(int n) { + if (n % 2 == 0) { + return {}; + } + if (n == 1) { + return {new TreeNode(0)}; + } + + vector res; + for (int left = 1; left < n; left += 2) { + vector leftSubTree = allPossibleFBT(left); + vector rightSubTree = allPossibleFBT(n - 1 - left); + for (auto& l : leftSubTree) { + for (auto& r : rightSubTree) { + TreeNode* root = new TreeNode(0, l, r); + res.push_back(root); + } + } + } + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {number} n + * @return {TreeNode[]} + */ + allPossibleFBT(n) { + if (n % 2 === 0) { + return []; + } + if (n === 1) { + return [new TreeNode(0)]; + } + + let res = []; + for (let left = 1; left < n; left += 2) { + let leftSubTree = this.allPossibleFBT(left); + let rightSubTree = this.allPossibleFBT(n - 1 - left); + for (let l of leftSubTree) { + for (let r of rightSubTree) { + let root = new TreeNode(0, l, r); + res.push(root); + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(2 ^ n)$ +* Space complexity: $O(n * 2 ^ n)$ + +--- + +## 3. Dynamic Programming (Top-Down) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def allPossibleFBT(self, n: int) -> List[Optional[TreeNode]]: + dp = {} + + def dfs(n): + if n % 2 == 0: + return [] + if n == 1: + return [TreeNode(0)] + if n in dp: + return dp[n] + + res = [] + for left in range(1, n, 2): + leftSubTree = dfs(left) + rightSubTree = dfs(n - 1 - left) + for l in leftSubTree: + for r in rightSubTree: + res.append(TreeNode(0, l, r)) + + dp[n] = res + return res + + return dfs(n) +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + private List[] dp; + + public List allPossibleFBT(int n) { + dp = new ArrayList[n + 1]; + return dfs(n); + } + + private List dfs(int n) { + if (n % 2 == 0) { + return new ArrayList<>(); + } + if (n == 1) { + return Arrays.asList(new TreeNode(0)); + } + if (dp[n] != null) { + return dp[n]; + } + + List res = new ArrayList<>(); + for (int left = 1; left < n; left += 2) { + List leftSubTree = dfs(left); + List rightSubTree = dfs(n - 1 - left); + for (TreeNode l : leftSubTree) { + for (TreeNode r : rightSubTree) { + res.add(new TreeNode(0, l, r)); + } + } + } + + return dp[n] = res; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +private: + vector> dp; + +public: + vector allPossibleFBT(int n) { + dp.resize(n + 1); + return dfs(n); + } + + vector dfs(int n) { + if (n % 2 == 0) { + return {}; + } + if (n == 1) { + return {new TreeNode(0)}; + } + if (!dp[n].empty()) { + return dp[n]; + } + + vector res; + for (int left = 1; left < n; left += 2) { + vector leftSubTree = dfs(left); + vector rightSubTree = dfs(n - 1 - left); + for (auto& l : leftSubTree) { + for (auto& r : rightSubTree) { + res.push_back(new TreeNode(0, l, r)); + } + } + } + + return dp[n] = res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {number} n + * @return {TreeNode[]} + */ + allPossibleFBT(n) { + let dp = new Array(n + 1); + + const dfs = (n) => { + if (n % 2 === 0) { + return []; + } + if (n === 1) { + return [new TreeNode(0)]; + } + if (dp[n]) { + return dp[n]; + } + + let res = []; + for (let left = 1; left < n; left += 2) { + let leftSubTree = dfs(left); + let rightSubTree = dfs(n - 1 - left); + for (let t1 of leftSubTree) { + for (let t2 of rightSubTree) { + res.push(new TreeNode(0, t1, t2)); + } + } + } + + return (dp[n] = res); + }; + + return dfs(n); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(2 ^ n)$ +* Space complexity: $O(n * 2 ^ n)$ + +--- + +## 4. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def allPossibleFBT(self, n: int) -> List[Optional[TreeNode]]: + if n % 2 == 0: + return [] + + dp = [[] for _ in range(n + 1)] + dp[1] = [TreeNode(0)] + + for nodes in range(3, n + 1, 2): + res = [] + for left in range(1, nodes, 2): + right = nodes - 1 - left + for t1 in dp[left]: + for t2 in dp[right]: + res.append(TreeNode(0, t1, t2)) + dp[nodes] = res + + return dp[n] +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public List allPossibleFBT(int n) { + if (n % 2 == 0) { + return new ArrayList<>(); + } + + List[] dp = new ArrayList[n + 1]; + for (int i = 0; i <= n; i++) { + dp[i] = new ArrayList<>(); + } + dp[1].add(new TreeNode(0)); + + for (int nodes = 3; nodes <= n; nodes += 2) { + List res = new ArrayList<>(); + for (int left = 1; left < nodes; left += 2) { + int right = nodes - 1 - left; + for (TreeNode t1 : dp[left]) { + for (TreeNode t2 : dp[right]) { + res.add(new TreeNode(0, t1, t2)); + } + } + } + dp[nodes] = res; + } + + return dp[n]; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + vector allPossibleFBT(int n) { + if (n % 2 == 0) { + return {}; + } + + vector> dp(n + 1); + dp[1].push_back(new TreeNode(0)); + + for (int nodes = 3; nodes <= n; nodes += 2) { + vector res; + for (int left = 1; left < nodes; left += 2) { + int right = nodes - 1 - left; + for (auto& t1 : dp[left]) { + for (auto& t2 : dp[right]) { + res.push_back(new TreeNode(0, t1, t2)); + } + } + } + dp[nodes] = res; + } + + return dp[n]; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {number} n + * @return {TreeNode[]} + */ + allPossibleFBT(n) { + if (n % 2 === 0) { + return []; + } + + let dp = Array.from({ length: n + 1 }, () => []); + dp[1] = [new TreeNode(0)]; + + for (let nodes = 3; nodes <= n; nodes += 2) { + let res = []; + for (let left = 1; left < nodes; left += 2) { + let right = nodes - 1 - left; + for (let t1 of dp[left]) { + for (let t2 of dp[right]) { + res.push(new TreeNode(0, t1, t2)); + } + } + } + dp[nodes] = res; + } + + return dp[n]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(2 ^ n)$ +* Space complexity: $O(n * 2 ^ n)$ \ No newline at end of file diff --git a/articles/binary-search-tree-iterator.md b/articles/binary-search-tree-iterator.md new file mode 100644 index 000000000..873698c70 --- /dev/null +++ b/articles/binary-search-tree-iterator.md @@ -0,0 +1,699 @@ +## 1. Flattening the BST (DFS) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class BSTIterator: + + def __init__(self, root: Optional[TreeNode]): + self.arr = [] + self.itr = 0 + + def dfs(node): + if not node: + return + dfs(node.left) + self.arr.append(node.val) + dfs(node.right) + + dfs(root) + + def next(self) -> int: + val = self.arr[self.itr] + self.itr += 1 + return val + + def hasNext(self) -> bool: + return self.itr < len(self.arr) +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class BSTIterator { + private List arr; + private int itr; + + public BSTIterator(TreeNode root) { + arr = new ArrayList<>(); + itr = 0; + dfs(root); + } + + private void dfs(TreeNode node) { + if (node == null) { + return; + } + dfs(node.left); + arr.add(node.val); + dfs(node.right); + } + + public int next() { + return arr.get(itr++); + } + + public boolean hasNext() { + return itr < arr.size(); + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class BSTIterator { +private: + vector arr; + int itr; + + void dfs(TreeNode* node) { + if (!node) { + return; + } + dfs(node->left); + arr.push_back(node->val); + dfs(node->right); + } + +public: + BSTIterator(TreeNode* root) { + itr = 0; + dfs(root); + } + + int next() { + return arr[itr++]; + } + + bool hasNext() { + return itr < arr.size(); + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class BSTIterator { + /** + * @constructor + * @param {TreeNode} root + */ + constructor(root) { + this.arr = []; + this.itr = 0; + + const dfs = (node) => { + if (!node) { + return; + } + dfs(node.left); + this.arr.push(node.val); + dfs(node.right); + }; + + dfs(root); + } + + /** + * @return {number} + */ + next() { + return this.arr[this.itr++]; + } + + /** + * @return {boolean} + */ + hasNext() { + return this.itr < this.arr.length; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: + * $O(n)$ time for initialization. + * $O(n)$ time for each $next()$ and $hasNext()$ function calls. +* Space complexity: $O(n)$ + +--- + +## 2. Flatten the BST (Iterative DFS) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class BSTIterator: + + def __init__(self, root: Optional[TreeNode]): + self.arr = [] + self.itr = 0 + + stack = [] + while root or stack: + while root: + stack.append(root) + root = root.left + root = stack.pop() + self.arr.append(root.val) + root = root.right + + def next(self) -> int: + val = self.arr[self.itr] + self.itr += 1 + return val + + def hasNext(self) -> bool: + return self.itr < len(self.arr) +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class BSTIterator { + private List arr; + private int itr; + + public BSTIterator(TreeNode root) { + arr = new ArrayList<>(); + itr = 0; + Stack stack = new Stack<>(); + while (root != null || !stack.isEmpty()) { + while (root != null) { + stack.push(root); + root = root.left; + } + root = stack.pop(); + arr.add(root.val); + root = root.right; + } + } + + public int next() { + return arr.get(itr++); + } + + public boolean hasNext() { + return itr < arr.size(); + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class BSTIterator { +private: + vector arr; + int itr; + +public: + BSTIterator(TreeNode* root) { + itr = 0; + stack stack; + while (root || !stack.empty()) { + while (root) { + stack.push(root); + root = root->left; + } + root = stack.top(); + stack.pop(); + arr.push_back(root->val); + root = root->right; + } + } + + int next() { + return arr[itr++]; + } + + bool hasNext() { + return itr < arr.size(); + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class BSTIterator { + /** + * @constructor + * @param {TreeNode} root + */ + constructor(root) { + this.arr = []; + this.itr = 0; + + let stack = []; + while (root || stack.length) { + while (root) { + stack.push(root); + root = root.left; + } + root = stack.pop(); + this.arr.push(root.val); + root = root.right; + } + } + + /** + * @return {number} + */ + next() { + return this.arr[this.itr++]; + } + + /** + * @return {boolean} + */ + hasNext() { + return this.itr < this.arr.length; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: + * $O(n)$ time for initialization. + * $O(n)$ time for each $next()$ and $hasNext()$ function calls. +* Space complexity: $O(n)$ + +--- + +## 3. Iterative DFS - I + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class BSTIterator: + + def __init__(self, root: Optional[TreeNode]): + self.stack = [] + while root: + self.stack.append(root) + root = root.left + + def next(self) -> int: + res = self.stack.pop() + cur = res.right + while cur: + self.stack.append(cur) + cur = cur.left + return res.val + + def hasNext(self) -> bool: + return bool(self.stack) +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class BSTIterator { + private Stack stack; + + public BSTIterator(TreeNode root) { + stack = new Stack<>(); + while (root != null) { + stack.push(root); + root = root.left; + } + } + + public int next() { + TreeNode res = stack.pop(); + TreeNode cur = res.right; + while (cur != null) { + stack.push(cur); + cur = cur.left; + } + return res.val; + } + + public boolean hasNext() { + return !stack.isEmpty(); + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class BSTIterator { +private: + stack stack; + +public: + BSTIterator(TreeNode* root) { + while (root) { + stack.push(root); + root = root->left; + } + } + + int next() { + TreeNode* res = stack.top(); + stack.pop(); + TreeNode* cur = res->right; + while (cur) { + stack.push(cur); + cur = cur->left; + } + return res->val; + } + + bool hasNext() { + return !stack.empty(); + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class BSTIterator { + /** + * @constructor + * @param {TreeNode} root + */ + constructor(root) { + this.stack = []; + while (root) { + this.stack.push(root); + root = root.left; + } + } + + /** + * @return {number} + */ + next() { + let res = this.stack.pop(); + let cur = res.right; + while (cur) { + this.stack.push(cur); + cur = cur.left; + } + return res.val; + } + + /** + * @return {boolean} + */ + hasNext() { + return this.stack.length > 0; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(1)$ in average for each function call. +* Space complexity: $O(h)$ + +> Where $n$ is the number of nodes and $h$ is the height of the given tree. + +--- + +## 4. Iterative DFS - II + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class BSTIterator: + + def __init__(self, root: Optional[TreeNode]): + self.cur = root + self.stack = [] + + def next(self) -> int: + while self.cur: + self.stack.append(self.cur) + self.cur = self.cur.left + + node = self.stack.pop() + self.cur = node.right + return node.val + + def hasNext(self) -> bool: + return bool(self.cur) or bool(self.stack) +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class BSTIterator { + private TreeNode cur; + private Stack stack; + + public BSTIterator(TreeNode root) { + cur = root; + stack = new Stack<>(); + } + + public int next() { + while (cur != null) { + stack.push(cur); + cur = cur.left; + } + + TreeNode node = stack.pop(); + cur = node.right; + return node.val; + } + + public boolean hasNext() { + return cur != null || !stack.isEmpty(); + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class BSTIterator { +private: + TreeNode* cur; + stack stack; + +public: + BSTIterator(TreeNode* root) { + cur = root; + } + + int next() { + while (cur) { + stack.push(cur); + cur = cur->left; + } + + TreeNode* node = stack.top(); + stack.pop(); + cur = node->right; + return node->val; + } + + bool hasNext() { + return cur || !stack.empty(); + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class BSTIterator { + /** + * @constructor + * @param {TreeNode} root + */ + constructor(root) { + this.cur = root; + this.stack = []; + } + + /** + * @return {number} + */ + next() { + while (this.cur) { + this.stack.push(this.cur); + this.cur = this.cur.left; + } + + let node = this.stack.pop(); + this.cur = node.right; + return node.val; + } + + /** + * @return {boolean} + */ + hasNext() { + return this.cur !== null || this.stack.length > 0; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(1)$ in average for each function call. +* Space complexity: $O(h)$ + +> Where $n$ is the number of nodes and $h$ is the height of the given tree. \ No newline at end of file diff --git a/articles/concatenated-words.md b/articles/concatenated-words.md new file mode 100644 index 000000000..0d7eaf0d4 --- /dev/null +++ b/articles/concatenated-words.md @@ -0,0 +1,587 @@ +## 1. Brute Force (Backtracking) + +::tabs-start + +```python +class Solution: + def findAllConcatenatedWordsInADict(self, words: List[str]) -> List[str]: + n = len(words) + res = [] + wordSet = set(words) + maxLen = 0 + for w in words: + maxLen = max(maxLen, len(w)) + + def dfs(concatWord, totLen): + if len(concatWord) > 1: + word = "".join(concatWord) + if word in wordSet: + res.append(word) + wordSet.remove(word) + + for i in range(len(words)): + if totLen + len(words[i]) > maxLen: + continue + concatWord.append(words[i]) + dfs(concatWord, totLen + len(words[i])) + concatWord.pop() + + dfs([], 0) + return res +``` + +```java +public class Solution { + private Set wordSet; + private int maxLen; + private List res; + private String[] words; + + public List findAllConcatenatedWordsInADict(String[] words) { + this.words = words; + this.wordSet = new HashSet<>(Arrays.asList(words)); + this.maxLen = 0; + this.res = new ArrayList<>(); + + for (String w : words) { + maxLen = Math.max(maxLen, w.length()); + } + + dfs(new ArrayList<>(), 0); + return res; + } + + private void dfs(List concatWord, int totLen) { + if (concatWord.size() > 1) { + String word = String.join("", concatWord); + if (wordSet.contains(word)) { + res.add(word); + wordSet.remove(word); + } + } + + for (String word : words) { + if (totLen + word.length() > maxLen) continue; + concatWord.add(word); + dfs(concatWord, totLen + word.length()); + concatWord.remove(concatWord.size() - 1); + } + } +} +``` + +```cpp +class Solution { +private: + unordered_set wordSet; + int maxLen; + vector res; + vector words; + +public: + vector findAllConcatenatedWordsInADict(vector& words) { + this->words = words; + wordSet = unordered_set(words.begin(), words.end()); + maxLen = 0; + res.clear(); + + for (const string& w : words) { + maxLen = max(maxLen, (int)w.length()); + } + + vector concatWord; + dfs(concatWord, 0); + return res; + } + +private: + void dfs(vector& concatWord, int totLen) { + if (concatWord.size() > 1) { + string word = accumulate(concatWord.begin(), concatWord.end(), string("")); + if (wordSet.count(word)) { + res.push_back(word); + wordSet.erase(word); + } + } + + for (const string& word : words) { + if (totLen + word.size() > maxLen) continue; + concatWord.push_back(word); + dfs(concatWord, totLen + word.length()); + concatWord.pop_back(); + } + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} words + * @return {string[]} + */ + findAllConcatenatedWordsInADict(words) { + let n = words.length; + let res = []; + let wordSet = new Set(words); + let maxLen = 0; + + for (let w of words) { + maxLen = Math.max(maxLen, w.length); + } + + const dfs = (concatWord, totLen) => { + if (concatWord.length > 1) { + let word = concatWord.join(""); + if (wordSet.has(word)) { + res.push(word); + wordSet.delete(word); + } + } + + for (let i = 0; i < words.length; i++) { + if (totLen + words[i].length > maxLen) continue; + concatWord.push(words[i]); + dfs(concatWord, totLen + words[i].length); + concatWord.pop(); + } + }; + + dfs([], 0); + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * n ^ n)$ +* Space complexity: $O(m * n)$ + +> Where $n$ is the size of the string array $words$ and $m$ is the length of the longest word in the array. + +--- + +## 2. Recursion + +::tabs-start + +```python +class Solution: + def findAllConcatenatedWordsInADict(self, words: List[str]) -> List[str]: + wordSet = set(words) + + def dfs(word): + for i in range(1, len(word)): + prefix, suffix = word[:i], word[i:] + if ((prefix in wordSet and suffix in wordSet) or + (prefix in wordSet and dfs(suffix)) + ): + return True + return False + + res = [] + for w in words: + if dfs(w): + res.append(w) + return res +``` + +```java +public class Solution { + public List findAllConcatenatedWordsInADict(String[] words) { + Set wordSet = new HashSet<>(Arrays.asList(words)); + List res = new ArrayList<>(); + + for (String w : words) { + if (dfs(w, wordSet)) { + res.add(w); + } + } + return res; + } + + private boolean dfs(String word, Set wordSet) { + for (int i = 1; i < word.length(); i++) { + String prefix = word.substring(0, i); + String suffix = word.substring(i); + + if ((wordSet.contains(prefix) && wordSet.contains(suffix)) || + (wordSet.contains(prefix) && dfs(suffix, wordSet))) { + return true; + } + } + return false; + } +} +``` + +```cpp +class Solution { +public: + vector findAllConcatenatedWordsInADict(vector& words) { + unordered_set wordSet(words.begin(), words.end()); + vector res; + + for (const string& w : words) { + if (dfs(w, wordSet)) { + res.push_back(w); + } + } + return res; + } + +private: + bool dfs(const string& word, unordered_set& wordSet) { + for (int i = 1; i < word.size(); i++) { + string prefix = word.substr(0, i); + string suffix = word.substr(i); + + if ((wordSet.count(prefix) && wordSet.count(suffix)) || + (wordSet.count(prefix) && dfs(suffix, wordSet))) { + return true; + } + } + return false; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} words + * @return {string[]} + */ + findAllConcatenatedWordsInADict(words) { + const wordSet = new Set(words); + + const dfs = (word) => { + for (let i = 1; i < word.length; i++) { + const prefix = word.substring(0, i); + const suffix = word.substring(i); + + if ((wordSet.has(prefix) && wordSet.has(suffix)) || + (wordSet.has(prefix) && dfs(suffix))) { + return true; + } + } + return false; + }; + + const res = []; + for (let w of words) { + if (dfs(w)) { + res.push(w); + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * m ^ 4)$ +* Space complexity: $O(n * m)$ + +> Where $n$ is the size of the string array $words$ and $m$ is the length of the longest word in the array. + +--- + +## 3. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def findAllConcatenatedWordsInADict(self, words: List[str]) -> List[str]: + wordSet = set(words) + dp = {} + + def dfs(word): + if word in dp: + return dp[word] + + for i in range(1, len(word)): + prefix, suffix = word[:i], word[i:] + if ((prefix in wordSet and suffix in wordSet) or + (prefix in wordSet and dfs(suffix)) + ): + dp[word] = True + return True + dp[word] = False + return False + + res = [] + for w in words: + if dfs(w): + res.append(w) + return res +``` + +```java +public class Solution { + private Map dp; + + public List findAllConcatenatedWordsInADict(String[] words) { + Set wordSet = new HashSet<>(Arrays.asList(words)); + List res = new ArrayList<>(); + dp = new HashMap<>(); + + for (String w : words) { + if (dfs(w, wordSet)) { + res.add(w); + } + } + return res; + } + + private boolean dfs(String word, Set wordSet) { + if (dp.containsKey(word)) { + return dp.get(word); + } + + for (int i = 1; i < word.length(); i++) { + String prefix = word.substring(0, i); + String suffix = word.substring(i); + + if ((wordSet.contains(prefix) && wordSet.contains(suffix)) || + (wordSet.contains(prefix) && dfs(suffix, wordSet))) { + dp.put(word, true); + return true; + } + } + dp.put(word, false); + return false; + } +} +``` + +```cpp +class Solution { + unordered_map dp; + +public: + vector findAllConcatenatedWordsInADict(vector& words) { + unordered_set wordSet(words.begin(), words.end()); + vector res; + + for (const string& w : words) { + if (dfs(w, wordSet)) { + res.push_back(w); + } + } + return res; + } + +private: + bool dfs(const string& word, unordered_set& wordSet) { + if (dp.count(word)) { + return dp[word]; + } + + for (int i = 1; i < word.size(); i++) { + string prefix = word.substr(0, i); + string suffix = word.substr(i); + + if ((wordSet.count(prefix) && wordSet.count(suffix)) || + (wordSet.count(prefix) && dfs(suffix, wordSet))) { + dp[word] = true; + return true; + } + } + dp[word] = false; + return false; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} words + * @return {string[]} + */ + findAllConcatenatedWordsInADict(words) { + const wordSet = new Set(words); + const dp = new Map(); + + const dfs = (word) => { + if (dp.has(word)) { + return dp.get(word); + } + + for (let i = 1; i < word.length; i++) { + const prefix = word.substring(0, i); + const suffix = word.substring(i); + + if ((wordSet.has(prefix) && wordSet.has(suffix)) || + (wordSet.has(prefix) && dfs(suffix))) { + dp.set(word, true); + return true; + } + } + dp.set(word, false); + return false; + }; + + const res = []; + for (let w of words) { + if (dfs(w)) { + res.push(w); + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * m ^ 3)$ +* Space complexity: $O(n * m)$ + +> Where $n$ is the size of the string array $words$ and $m$ is the length of the longest word in the array. + +--- + +## 4. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def findAllConcatenatedWordsInADict(self, words: List[str]) -> List[str]: + wordSet = set(words) + res = [] + + for word in words: + m = len(word) + + dp = [False] * (m + 1) + dp[0] = True + + for i in range(1, m + 1): + for j in range(i): + if j == 0 and i == m: + continue + if dp[j] and word[j:i] in wordSet: + dp[i] = True + break + + if dp[m]: + res.append(word) + + return res +``` + +```java +public class Solution { + public List findAllConcatenatedWordsInADict(String[] words) { + Set wordSet = new HashSet<>(Arrays.asList(words)); + List res = new ArrayList<>(); + + for (String word : words) { + int m = word.length(); + boolean[] dp = new boolean[m + 1]; + dp[0] = true; + + for (int i = 1; i <= m; i++) { + for (int j = 0; j < i; j++) { + if (j == 0 && i == m) continue; + if (dp[j] && wordSet.contains(word.substring(j, i))) { + dp[i] = true; + break; + } + } + } + + if (dp[m]) { + res.add(word); + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + vector findAllConcatenatedWordsInADict(vector& words) { + unordered_set wordSet(words.begin(), words.end()); + vector res; + + for (string& word : words) { + int m = word.length(); + vector dp(m + 1, false); + dp[0] = true; + + for (int i = 1; i <= m; i++) { + for (int j = 0; j < i; j++) { + if (j == 0 && i == m) continue; + if (dp[j] && wordSet.count(word.substr(j, i - j))) { + dp[i] = true; + break; + } + } + } + + if (dp[m]) { + res.push_back(word); + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} words + * @return {string[]} + */ + findAllConcatenatedWordsInADict(words) { + const wordSet = new Set(words); + const res = []; + + for (const word of words) { + const m = word.length; + const dp = new Array(m + 1).fill(false); + dp[0] = true; + + for (let i = 1; i <= m; i++) { + for (let j = 0; j < i; j++) { + if (j === 0 && i === m) continue; + if (dp[j] && wordSet.has(word.substring(j, i))) { + dp[i] = true; + break; + } + } + } + + if (dp[m]) { + res.push(word); + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * m ^ 3)$ +* Space complexity: $O(n * m)$ + +> Where $n$ is the size of the string array $words$ and $m$ is the length of the longest word in the array. \ No newline at end of file diff --git a/articles/count-all-valid-pickup-and-delivery-options.md b/articles/count-all-valid-pickup-and-delivery-options.md new file mode 100644 index 000000000..78b58d069 --- /dev/null +++ b/articles/count-all-valid-pickup-and-delivery-options.md @@ -0,0 +1,668 @@ +## 1. Recursion + +::tabs-start + +```python +class Solution: + def countOrders(self, n: int) -> int: + MOD = 1000000007 + + def dfs(picked, delivered): + if picked == n and delivered == n: + return 1 + + res = 0 + if picked < n: + res = (res + (n - picked) * dfs(picked + 1, delivered)) % MOD + if delivered < picked: + res = (res + (picked - delivered) * dfs(picked, delivered + 1)) % MOD + + return res + + return dfs(0, 0) +``` + +```java +public class Solution { + private static final int MOD = 1_000_000_007; + + public int countOrders(int n) { + return dfs(0, 0, n); + } + + private int dfs(int picked, int delivered, int n) { + if (picked == n && delivered == n) { + return 1; + } + + long res = 0; + if (picked < n) { + res = ((res + (n - picked) * 1L * dfs(picked + 1, delivered, n)) % MOD); + } + if (delivered < picked) { + res = ((res + (picked - delivered) * 1L * dfs(picked, delivered + 1, n)) % MOD); + } + + return (int) res; + } +} +``` + +```cpp +class Solution { +public: + static const int MOD = 1'000'000'007; + + int countOrders(int n) { + return dfs(0, 0, n); + } + +private: + int dfs(int picked, int delivered, int n) { + if (picked == n && delivered == n) { + return 1; + } + + int res = 0; + if (picked < n) { + res = (res + (n - picked) * 1LL * dfs(picked + 1, delivered, n)) % MOD; + } + if (delivered < picked) { + res = (res + (picked - delivered) * 1LL * dfs(picked, delivered + 1, n)) % MOD; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + countOrders(n) { + const MOD = 1_000_000_007; + + const dfs = (picked, delivered) => { + if (picked === n && delivered === n) { + return 1; + } + + let res = 0; + if (picked < n) { + res = (res + (n - picked) * dfs(picked + 1, delivered)) % MOD; + } + if (delivered < picked) { + res = (res + (picked - delivered) * dfs(picked, delivered + 1)) % MOD; + } + + return res; + }; + + return dfs(0, 0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(2 ^ n)$ +* Space complexity: $O(n)$ for recursion stack. + +--- + +## 2. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def countOrders(self, n: int) -> int: + MOD = 1000000007 + dp = [[-1] * (n + 1) for _ in range(n + 1)] + dp[n][n] = 1 + + def dfs(picked, delivered): + if dp[picked][delivered] != -1: + return dp[picked][delivered] + + res = 0 + if picked < n: + res = (res + (n - picked) * dfs(picked + 1, delivered)) % MOD + if delivered < picked: + res = (res + (picked - delivered) * dfs(picked, delivered + 1)) % MOD + + dp[picked][delivered] = res + return res + + return dfs(0, 0) +``` + +```java +public class Solution { + private static final int MOD = 1_000_000_007; + private int[][] dp; + + public int countOrders(int n) { + dp = new int[n + 1][n + 1]; + for (int i = 0; i <= n; i++) { + for (int j = 0; j <= n; j++) { + dp[i][j] = -1; + } + } + dp[n][n] = 1; + return dfs(0, 0, n); + } + + private int dfs(int picked, int delivered, int n) { + if (dp[picked][delivered] != -1) { + return dp[picked][delivered]; + } + + long res = 0; + if (picked < n) { + res = ((res + (n - picked) * 1L * dfs(picked + 1, delivered, n)) % MOD); + } + if (delivered < picked) { + res = ((res + (picked - delivered) * 1L * dfs(picked, delivered + 1, n)) % MOD); + } + + return dp[picked][delivered] = (int)res; + } +} +``` + +```cpp +class Solution { +public: + static const int MOD = 1'000'000'007; + vector> dp; + + int countOrders(int n) { + dp.assign(n + 1, vector(n + 1, -1)); + dp[n][n] = 1; + return dfs(0, 0, n); + } + +private: + int dfs(int picked, int delivered, int n) { + if (dp[picked][delivered] != -1) { + return dp[picked][delivered]; + } + + int res = 0; + if (picked < n) { + res = (res + (n - picked) * 1LL * dfs(picked + 1, delivered, n)) % MOD; + } + if (delivered < picked) { + res = (res + (picked - delivered) * 1LL * dfs(picked, delivered + 1, n)) % MOD; + } + + return dp[picked][delivered] = res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + countOrders(n) { + const MOD = 1_000_000_007; + const dp = Array.from({ length: n + 1 }, () => Array(n + 1).fill(-1)); + + const dfs = (picked, delivered) => { + if (picked === n && delivered === n) { + return 1; + } + if (dp[picked][delivered] !== -1) { + return dp[picked][delivered]; + } + + let res = 0; + if (picked < n) { + res = (res + (n - picked) * dfs(picked + 1, delivered)) % MOD; + } + if (delivered < picked) { + res = (res + (picked - delivered) * dfs(picked, delivered + 1)) % MOD; + } + + dp[picked][delivered] = res; + return res; + }; + + return dfs(0, 0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n ^ 2)$ + +--- + +## 3. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def countOrders(self, n: int) -> int: + MOD = 1000000007 + dp = [[0] * (n + 1) for _ in range(n + 1)] + dp[0][0] = 1 + + for picked in range(n + 1): + for delivered in range(n + 1): + if picked < n: + dp[picked + 1][delivered] = ( + (dp[picked + 1][delivered] + + (n - picked) * dp[picked][delivered]) % MOD + ) + + if delivered < picked: + dp[picked][delivered + 1] = ( + (dp[picked][delivered + 1] + + (picked - delivered) * dp[picked][delivered]) % MOD + ) + + return dp[n][n] +``` + +```java +public class Solution { + public int countOrders(int n) { + final int MOD = 1_000_000_007; + int[][] dp = new int[n + 1][n + 1]; + dp[0][0] = 1; + + for (int picked = 0; picked <= n; picked++) { + for (int delivered = 0; delivered <= n; delivered++) { + if (picked < n) { + dp[picked + 1][delivered] = (int) ((dp[picked + 1][delivered] + + (n - picked) * 1L * dp[picked][delivered]) % MOD); + } + if (delivered < picked) { + dp[picked][delivered + 1] = (int) ((dp[picked][delivered + 1] + + (picked - delivered) * 1L * dp[picked][delivered]) % MOD); + } + } + } + + return dp[n][n]; + } +} +``` + +```cpp +class Solution { +public: + int countOrders(int n) { + const int MOD = 1'000'000'007; + vector> dp(n + 1, vector(n + 1, 0)); + dp[0][0] = 1; + + for (int picked = 0; picked <= n; picked++) { + for (int delivered = 0; delivered <= n; delivered++) { + if (picked < n) { + dp[picked + 1][delivered] = (dp[picked + 1][delivered] + + (n - picked) * 1LL * dp[picked][delivered]) % MOD; + } + if (delivered < picked) { + dp[picked][delivered + 1] = (dp[picked][delivered + 1] + + (picked - delivered) * 1LL * dp[picked][delivered]) % MOD; + } + } + } + + return dp[n][n]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + countOrders(n) { + const MOD = 1_000_000_007; + const dp = Array.from({ length: n + 1 }, () => Array(n + 1).fill(0)); + dp[0][0] = 1; + + for (let picked = 0; picked <= n; picked++) { + for (let delivered = 0; delivered <= n; delivered++) { + if (picked < n) { + dp[picked + 1][delivered] = ( + (dp[picked + 1][delivered] + + (n - picked) * dp[picked][delivered]) % MOD + ); + } + + if (delivered < picked) { + dp[picked][delivered + 1] = ( + (dp[picked][delivered + 1] + + (picked - delivered) * dp[picked][delivered]) % MOD + ); + } + } + } + + return dp[n][n]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n ^ 2)$ + +--- + +## 4. Dynamic Programming (Space Optimized) + +::tabs-start + +```python +class Solution: + def countOrders(self, n: int) -> int: + MOD = 1000000007 + dp = [0] * (n + 1) + dp[0] = 1 + + for picked in range(n + 1): + for delivered in range(picked): + dp[delivered + 1] = ( + (dp[delivered + 1] + + (picked - delivered) * dp[delivered]) % MOD + ) + + if picked < n: + next_dp = [0] * (n + 1) + for delivered in range(picked + 1): + next_dp[delivered] = ( + (next_dp[delivered] + + (n - picked) * dp[delivered]) % MOD + ) + dp = next_dp + + return dp[n] +``` + +```java +public class Solution { + public int countOrders(int n) { + int MOD = 1000000007; + int[] dp = new int[n + 1]; + dp[0] = 1; + + for (int picked = 0; picked <= n; picked++) { + for (int delivered = 0; delivered < picked; delivered++) { + dp[delivered + 1] = (int)((dp[delivered + 1] + + (picked - delivered) * 1L * dp[delivered]) % MOD); + } + + if (picked < n) { + int[] next_dp = new int[n + 1]; + for (int delivered = 0; delivered <= picked; delivered++) { + next_dp[delivered] = (int)((next_dp[delivered] + + (n - picked) * 1L *dp[delivered]) % MOD); + } + dp = next_dp; + } + } + + return dp[n]; + } +} +``` + +```cpp +class Solution { +public: + int countOrders(int n) { + const int MOD = 1000000007; + vector dp(n + 1); + dp[0] = 1; + + for (int picked = 0; picked <= n; picked++) { + for (int delivered = 0; delivered < picked; delivered++) { + dp[delivered + 1] = (int)((dp[delivered + 1] + + (picked - delivered) * 1LL * dp[delivered]) % MOD); + } + if (picked < n) { + vector next_dp(n + 1); + for (int delivered = 0; delivered <= picked; delivered++) { + next_dp[delivered] = (int)((next_dp[delivered] + + (n - picked) * 1LL * dp[delivered]) % MOD); + } + dp = next_dp; + } + } + + return dp[n]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + countOrders(n) { + const MOD = 1000000007; + let dp = new Array(n + 1).fill(0); + dp[0] = 1; + + for (let picked = 0; picked <= n; picked++) { + for (let delivered = 0; delivered < picked; delivered++) { + dp[delivered + 1] = ( + (dp[delivered + 1] + + (picked - delivered) * dp[delivered]) % MOD + ); + } + + if (picked < n) { + let next_dp = new Array(n + 1).fill(0); + for (let delivered = 0; delivered <= picked; delivered++) { + next_dp[delivered] = ( + (next_dp[delivered] + + (n - picked) * dp[delivered]) % MOD + ); + } + dp = next_dp; + } + } + + return dp[n]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n)$ + +--- + +## 5. Combinatorics + +::tabs-start + +```python +class Solution: + def countOrders(self, n: int) -> int: + MOD = 1000000007 + slots, res = 2 * n, 1 + while slots > 0: + valid_choices = slots * (slots - 1) // 2 + res = (res * valid_choices) % MOD + slots -= 2 + return res +``` + +```java +public class Solution { + public int countOrders(int n) { + int MOD = 1000000007; + long slots = 2 * n, res = 1; + + while (slots > 0) { + long validChoices = slots * (slots - 1) / 2; + res = (res * validChoices) % MOD; + slots -= 2; + } + return (int) res; + } +} +``` + +```cpp +class Solution { +public: + int countOrders(int n) { + const int MOD = 1000000007; + long long slots = 2 * n, res = 1; + + while (slots > 0) { + long long validChoices = slots * (slots - 1) / 2; + res = (res * validChoices) % MOD; + slots -= 2; + } + return (int) res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + countOrders(n) { + const MOD = 1000000007; + let slots = 2 * n, res = 1; + + while (slots > 0) { + let validChoices = (slots * (slots - 1)) / 2; + res = (res * validChoices) % MOD; + slots -= 2; + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ + +--- + +## 6. Probability + +::tabs-start + +```python +class Solution: + def countOrders(self, n: int) -> int: + MOD = 1000000007 + res = 1 + + for slot in range(1, 2 * n + 1): + res *= slot + if slot % 2 == 0: + res >>= 1 + res %= MOD + + return res +``` + +```java +public class Solution { + public int countOrders(int n) { + int MOD = 1000000007; + long res = 1; + + for (int slot = 1; slot <= 2 * n; slot++) { + res *= slot; + if (slot % 2 == 0) { + res >>= 1; + } + res %= MOD; + } + return (int) res; + } +} +``` + +```cpp +class Solution { +public: + int countOrders(int n) { + const int MOD = 1000000007; + long long res = 1; + + for (int slot = 1; slot <= 2 * n; slot++) { + res *= slot; + if (slot % 2 == 0) { + res >>= 1; + } + res %= MOD; + } + return (int) res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + countOrders(n) { + const MOD = BigInt(1000000007); + let res = BigInt(1); + + for (let slot = 1; slot <= 2 * n; slot++) { + res *= BigInt(slot); + if (slot % 2 === 0) { + res /= BigInt(2); + } + res %= MOD; + } + return Number(res); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ \ No newline at end of file diff --git a/articles/data-stream-as-disjoint-intervals.md b/articles/data-stream-as-disjoint-intervals.md new file mode 100644 index 000000000..a39dc70f3 --- /dev/null +++ b/articles/data-stream-as-disjoint-intervals.md @@ -0,0 +1,450 @@ +## 1. Brute Force (Sorting) + +::tabs-start + +```python +class SummaryRanges: + + def __init__(self): + self.arr = [] + + def addNum(self, value: int) -> None: + self.arr.append(value) + + def getIntervals(self) -> List[List[int]]: + if not self.arr: + return [] + + self.arr.sort() + n = len(self.arr) + start = self.arr[0] + res = [] + for i in range(1, n): + if self.arr[i] - self.arr[i - 1] > 1: + res.append([start, self.arr[i - 1]]) + start = self.arr[i] + + res.append([start, self.arr[n - 1]]) + return res +``` + +```java +public class SummaryRanges { + private List arr; + + public SummaryRanges() { + arr = new ArrayList<>(); + } + + public void addNum(int value) { + arr.add(value); + } + + public List getIntervals() { + List res = new ArrayList<>(); + if (arr.isEmpty()) return res; + + Collections.sort(arr); + int start = arr.get(0); + for (int i = 1; i < arr.size(); i++) { + if (arr.get(i) - arr.get(i - 1) > 1) { + res.add(new int[]{start, arr.get(i - 1)}); + start = arr.get(i); + } + } + res.add(new int[]{start, arr.get(arr.size() - 1)}); + return res; + } +} +``` + +```cpp +class SummaryRanges { +private: + vector arr; + +public: + SummaryRanges() {} + + void addNum(int value) { + arr.push_back(value); + } + + vector> getIntervals() { + vector> res; + if (arr.empty()) return res; + + sort(arr.begin(), arr.end()); + int start = arr[0]; + for (int i = 1; i < arr.size(); i++) { + if (arr[i] - arr[i - 1] > 1) { + res.push_back({start, arr[i - 1]}); + start = arr[i]; + } + } + res.push_back({start, arr.back()}); + return res; + } +}; +``` + +```javascript +class SummaryRanges { + constructor() { + this.arr = []; + } + + /** + * @param {number} value + * @return {void} + */ + addNum(value) { + this.arr.push(value); + } + + /** + * @return {number[][]} + */ + getIntervals() { + if (this.arr.length === 0) return []; + + this.arr.sort((a, b) => a - b); + let start = this.arr[0]; + let res = []; + + for (let i = 1; i < this.arr.length; i++) { + if (this.arr[i] - this.arr[i - 1] > 1) { + res.push([start, this.arr[i - 1]]); + start = this.arr[i]; + } + } + res.push([start, this.arr[this.arr.length - 1]]); + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: + * $O(1)$ time for initialization. + * $O(1)$ time for each $addNum()$ function call. + * $O(n \log n)$ time for each $getIntervals()$ function call. +* Space complexity: $O(n)$ + +--- + +## 2. Hash Set + Sorting + +::tabs-start + +```python +class SummaryRanges: + + def __init__(self): + self.arr = set() + + def addNum(self, value: int) -> None: + self.arr.add(value) + + def getIntervals(self) -> List[List[int]]: + if not self.arr: + return [] + + lst = sorted(list(self.arr)) + n = len(lst) + start = lst[0] + res = [] + for i in range(1, n): + if lst[i] - lst[i - 1] > 1: + res.append([start, lst[i - 1]]) + start = lst[i] + + res.append([start, lst[n - 1]]) + return res +``` + +```java +public class SummaryRanges { + private Set arr; + + public SummaryRanges() { + arr = new TreeSet<>(); + } + + public void addNum(int value) { + arr.add(value); + } + + public List getIntervals() { + List res = new ArrayList<>(); + if (arr.isEmpty()) return res; + + List lst = new ArrayList<>(arr); + int start = lst.get(0); + for (int i = 1; i < lst.size(); i++) { + if (lst.get(i) - lst.get(i - 1) > 1) { + res.add(new int[]{start, lst.get(i - 1)}); + start = lst.get(i); + } + } + res.add(new int[]{start, lst.get(lst.size() - 1)}); + return res; + } +} +``` + +```cpp +class SummaryRanges { +private: + set arr; + +public: + SummaryRanges() {} + + void addNum(int value) { + arr.insert(value); + } + + vector> getIntervals() { + vector> res; + if (arr.empty()) return res; + + vector lst(arr.begin(), arr.end()); + int start = lst[0]; + + for (int i = 1; i < lst.size(); i++) { + if (lst[i] - lst[i - 1] > 1) { + res.push_back({start, lst[i - 1]}); + start = lst[i]; + } + } + res.push_back({start, lst.back()}); + return res; + } +}; +``` + +```javascript +class SummaryRanges { + constructor() { + this.arr = new Set(); + } + + /** + * @param {number} value + * @return {number[][]} + */ + addNum(value) { + this.arr.add(value); + } + + /** + * @return {number[][]} + */ + getIntervals() { + if (this.arr.size === 0) return []; + + let lst = Array.from(this.arr).sort((a, b) => a - b); + let start = lst[0]; + let res = []; + + for (let i = 1; i < lst.length; i++) { + if (lst[i] - lst[i - 1] > 1) { + res.push([start, lst[i - 1]]); + start = lst[i]; + } + } + res.push([start, lst[lst.length - 1]]); + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: + * $O(1)$ time for initialization. + * $O(1)$ time for each $addNum()$ function call. + * $O(n \log n)$ time for each $getIntervals()$ function call. +* Space complexity: $O(n)$ + +--- + +## 3. Ordered Map + +::tabs-start + +```python +from sortedcontainers import SortedDict + +class SummaryRanges: + def __init__(self): + self.treeMap = SortedDict() + + def addNum(self, value: int) -> None: + self.treeMap[value] = True + + def getIntervals(self) -> List[List[int]]: + res = [] + for n in self.treeMap: + if res and res[-1][1] + 1 == n: + res[-1][1] = n + else: + res.append([n, n]) + return res +``` + +```java +public class SummaryRanges { + private TreeMap treeMap; + + public SummaryRanges() { + treeMap = new TreeMap<>(); + } + + public void addNum(int value) { + treeMap.put(value, true); + } + + public List getIntervals() { + List res = new ArrayList<>(); + for (int n : treeMap.keySet()) { + if (!res.isEmpty() && res.get(res.size() - 1)[1] + 1 == n) { + res.get(res.size() - 1)[1] = n; + } else { + res.add(new int[]{n, n}); + } + } + return res; + } +} +``` + +```cpp +class SummaryRanges { +private: + map treeMap; + +public: + SummaryRanges() {} + + void addNum(int value) { + treeMap[value] = true; + } + + vector> getIntervals() { + vector> res; + for (auto& [n, _] : treeMap) { + if (!res.empty() && res.back()[1] + 1 == n) { + res.back()[1] = n; + } else { + res.push_back({n, n}); + } + } + return res; + } +}; +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: + * $O(1)$ time for initialization. + * $O(\log n)$ time for each $addNum()$ function call. + * $O(n)$ time for each $getIntervals()$ function call. +* Space complexity: $O(n)$ + +--- + +## 4. Ordered Set + +::tabs-start + +```python +from sortedcontainers import SortedSet + +class SummaryRanges: + def __init__(self): + self.orderedSet = SortedSet() + + def addNum(self, value: int) -> None: + self.orderedSet.add(value) + + def getIntervals(self) -> List[List[int]]: + res = [] + for n in self.orderedSet: + if res and res[-1][1] + 1 == n: + res[-1][1] = n + else: + res.append([n, n]) + return res +``` + +```java +public class SummaryRanges { + private TreeSet orderedSet; + + public SummaryRanges() { + orderedSet = new TreeSet<>(); + } + + public void addNum(int value) { + orderedSet.add(value); + } + + public List getIntervals() { + List res = new ArrayList<>(); + for (int n : orderedSet) { + if (!res.isEmpty() && res.get(res.size() - 1)[1] + 1 == n) { + res.get(res.size() - 1)[1] = n; + } else { + res.add(new int[]{n, n}); + } + } + return res; + } +} +``` + +```cpp +class SummaryRanges { +private: + set orderedSet; + +public: + SummaryRanges() {} + + void addNum(int value) { + orderedSet.insert(value); + } + + vector> getIntervals() { + vector> res; + for (int n : orderedSet) { + if (!res.empty() && res.back()[1] + 1 == n) { + res.back()[1] = n; + } else { + res.push_back({n, n}); + } + } + return res; + } +}; +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: + * $O(1)$ time for initialization. + * $O(\log n)$ time for each $addNum()$ function call. + * $O(n)$ time for each $getIntervals()$ function call. +* Space complexity: $O(n)$ \ No newline at end of file diff --git a/articles/design-browser-history.md b/articles/design-browser-history.md new file mode 100644 index 000000000..a557f9151 --- /dev/null +++ b/articles/design-browser-history.md @@ -0,0 +1,640 @@ +## 1. Two Stacks + +::tabs-start + +```python +class BrowserHistory: + + def __init__(self, homepage: str): + self.back_history = [homepage] + self.front_history = [] + + def visit(self, url: str) -> None: + self.back_history.append(url) + self.front_history = [] + + def back(self, steps: int) -> str: + while steps and len(self.back_history) > 1: + self.front_history.append(self.back_history.pop()) + steps -= 1 + return self.back_history[-1] + + def forward(self, steps: int) -> str: + while steps and self.front_history: + self.back_history.append(self.front_history.pop()) + steps -= 1 + return self.back_history[-1] +``` + +```java +public class BrowserHistory { + private Stack backHistory; + private Stack frontHistory; + + public BrowserHistory(String homepage) { + backHistory = new Stack<>(); + frontHistory = new Stack<>(); + backHistory.push(homepage); + } + + public void visit(String url) { + backHistory.push(url); + frontHistory = new Stack<>(); + } + + public String back(int steps) { + while (steps > 0 && backHistory.size() > 1) { + frontHistory.push(backHistory.pop()); + steps--; + } + return backHistory.peek(); + } + + public String forward(int steps) { + while (steps > 0 && !frontHistory.isEmpty()) { + backHistory.push(frontHistory.pop()); + steps--; + } + return backHistory.peek(); + } +} +``` + +```cpp +class BrowserHistory { +private: + stack backHistory, frontHistory; + +public: + BrowserHistory(string homepage) { + backHistory.push(homepage); + } + + void visit(string url) { + backHistory.push(url); + frontHistory = stack(); + } + + string back(int steps) { + while (steps-- && backHistory.size() > 1) { + frontHistory.push(backHistory.top()); + backHistory.pop(); + } + return backHistory.top(); + } + + string forward(int steps) { + while (steps-- && !frontHistory.empty()) { + backHistory.push(frontHistory.top()); + frontHistory.pop(); + } + return backHistory.top(); + } +}; +``` + +```javascript +class BrowserHistory { + /** + * @constructor + * @param {string} homepage + */ + constructor(homepage) { + this.backHistory = [homepage]; + this.frontHistory = []; + } + + /** + * @param {string} url + * @return {void} + */ + visit(url) { + this.backHistory.push(url); + this.frontHistory = []; + } + + /** + * @param {number} steps + * @return {string} + */ + back(steps) { + while (steps-- > 0 && this.backHistory.length > 1) { + this.frontHistory.push(this.backHistory.pop()); + } + return this.backHistory[this.backHistory.length - 1]; + } + + /** + * @param {number} steps + * @return {string} + */ + forward(steps) { + while (steps-- > 0 && this.frontHistory.length > 0) { + this.backHistory.push(this.frontHistory.pop()); + } + return this.backHistory[this.backHistory.length - 1]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: + * $O(1)$ time for initialization. + * $O(1)$ time for each $visit()$ function call. + * $O(min(n, steps))$ time for each $back()$ and $forward()$ function calls. +* Space complexity: $O(m * n)$ + +> Where $n$ is the number of visited urls, $m$ is the average length of each url, and $steps$ is the number of steps we go forward or back. + +--- + +## 2. Dynamic Array + +::tabs-start + +```python +class BrowserHistory: + + def __init__(self, homepage: str): + self.history = [homepage] + self.cur = 0 + + def visit(self, url: str) -> None: + self.cur += 1 + self.history = self.history[:self.cur] + self.history.append(url) + + def back(self, steps: int) -> str: + self.cur = max(0, self.cur - steps) + return self.history[self.cur] + + def forward(self, steps: int) -> str: + self.cur = min(len(self.history) - 1, self.cur + steps) + return self.history[self.cur] +``` + +```java +public class BrowserHistory { + private List history; + private int cur; + + public BrowserHistory(String homepage) { + history = new ArrayList<>(); + history.add(homepage); + cur = 0; + } + + public void visit(String url) { + cur++; + history = history.subList(0, cur); + history.add(url); + } + + public String back(int steps) { + cur = Math.max(0, cur - steps); + return history.get(cur); + } + + public String forward(int steps) { + cur = Math.min(history.size() - 1, cur + steps); + return history.get(cur); + } +} +``` + +```cpp +class BrowserHistory { +private: + vector history; + int cur; + +public: + BrowserHistory(string homepage) { + history.push_back(homepage); + cur = 0; + } + + void visit(string url) { + cur++; + history.resize(cur); + history.push_back(url); + } + + string back(int steps) { + cur = max(0, cur - steps); + return history[cur]; + } + + string forward(int steps) { + cur = min((int)history.size() - 1, cur + steps); + return history[cur]; + } +}; +``` + +```javascript +class BrowserHistory { + /** + * @constructor + * @param {string} homepage + */ + constructor(homepage) { + this.history = [homepage]; + this.cur = 0; + } + + /** + * @param {string} url + * @return {void} + */ + visit(url) { + this.cur++; + this.history = this.history.slice(0, this.cur); + this.history.push(url); + } + + /** + * @param {number} steps + * @return {string} + */ + back(steps) { + this.cur = Math.max(0, this.cur - steps); + return this.history[this.cur]; + } + + /** + * @param {number} steps + * @return {string} + */ + forward(steps) { + this.cur = Math.min(this.history.length - 1, this.cur + steps); + return this.history[this.cur]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: + * $O(1)$ time for initialization. + * $O(n)$ time for each $visit()$ function call. + * $O(1)$ time for each $back()$ and $forward()$ function calls. +* Space complexity: $O(m * n)$ + +> Where $n$ is the number of visited urls and $m$ is the average length of each url. + +--- + +## 3. Dynamic Array (Optimal) + +::tabs-start + +```python +class BrowserHistory: + + def __init__(self, homepage: str): + self.history = [homepage] + self.cur = 0 + self.n = 1 + + def visit(self, url: str) -> None: + self.cur += 1 + if self.cur == len(self.history): + self.history.append(url) + self.n += 1 + else: + self.history[self.cur] = url + self.n = self.cur + 1 + + def back(self, steps: int) -> str: + self.cur = max(0, self.cur - steps) + return self.history[self.cur] + + def forward(self, steps: int) -> str: + self.cur = min(self.n - 1, self.cur + steps) + return self.history[self.cur] +``` + +```java +public class BrowserHistory { + private List history; + private int cur; + private int n; + + public BrowserHistory(String homepage) { + history = new ArrayList<>(); + history.add(homepage); + cur = 0; + n = 1; + } + + public void visit(String url) { + cur++; + if (cur == history.size()) { + history.add(url); + n++; + } else { + history.set(cur, url); + n = cur + 1; + } + } + + public String back(int steps) { + cur = Math.max(0, cur - steps); + return history.get(cur); + } + + public String forward(int steps) { + cur = Math.min(n - 1, cur + steps); + return history.get(cur); + } +} +``` + +```cpp +class BrowserHistory { +private: + vector history; + int cur, n; + +public: + BrowserHistory(string homepage) { + history.push_back(homepage); + cur = 0; + n = 1; + } + + void visit(string url) { + cur++; + if (cur == history.size()) { + history.push_back(url); + n++; + } else { + history[cur] = url; + n = cur + 1; + } + } + + string back(int steps) { + cur = max(0, cur - steps); + return history[cur]; + } + + string forward(int steps) { + cur = min(n - 1, cur + steps); + return history[cur]; + } +}; +``` + +```javascript +class BrowserHistory { + /** + * @constructor + * @param {string} homepage + */ + constructor(homepage) { + this.history = [homepage]; + this.cur = 0; + this.n = 1; + } + + /** + * @param {string} url + * @return {void} + */ + visit(url) { + this.cur++; + if (this.cur === this.history.length) { + this.history.push(url); + this.n++; + } else { + this.history[this.cur] = url; + this.n = this.cur + 1; + } + } + + /** + * @param {number} steps + * @return {string} + */ + back(steps) { + this.cur = Math.max(0, this.cur - steps); + return this.history[this.cur]; + } + + /** + * @param {number} steps + * @return {string} + */ + forward(steps) { + this.cur = Math.min(this.n - 1, this.cur + steps); + return this.history[this.cur]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: + * $O(1)$ time for initialization. + * $O(1)$ time for each $visit()$ function call. + * $O(1)$ time for each $back()$ and $forward()$ function calls. +* Space complexity: $O(m * n)$ + +> Where $n$ is the number of visited urls and $m$ is the average length of each url. + +--- + +## 4. Doubly Linked List + +::tabs-start + +```python +class ListNode: + def __init__(self, val, prev=None, next=None): + self.val = val + self.prev = prev + self.next = next + +class BrowserHistory: + + def __init__(self, homepage: str): + self.cur = ListNode(homepage) + + def visit(self, url: str) -> None: + self.cur.next = ListNode(url, self.cur) + self.cur = self.cur.next + + def back(self, steps: int) -> str: + while self.cur.prev and steps > 0: + self.cur = self.cur.prev + steps -= 1 + return self.cur.val + + def forward(self, steps: int) -> str: + while self.cur.next and steps > 0: + self.cur = self.cur.next + steps -= 1 + return self.cur.val +``` + +```java +class ListNode { + String val; + ListNode prev, next; + + public ListNode(String val, ListNode prev, ListNode next) { + this.val = val; + this.prev = prev; + this.next = next; + } + + public ListNode(String val) { + this(val, null, null); + } +} + +public class BrowserHistory { + private ListNode cur; + + public BrowserHistory(String homepage) { + cur = new ListNode(homepage); + } + + public void visit(String url) { + cur.next = new ListNode(url, cur, null); + cur = cur.next; + } + + public String back(int steps) { + while (cur.prev != null && steps > 0) { + cur = cur.prev; + steps--; + } + return cur.val; + } + + public String forward(int steps) { + while (cur.next != null && steps > 0) { + cur = cur.next; + steps--; + } + return cur.val; + } +} +``` + +```cpp +class BrowserHistory { + struct ListNode { + public: + string val; + ListNode* prev; + ListNode* next; + + ListNode(string val, ListNode* prev = nullptr, ListNode* next = nullptr) + : val(val), prev(prev), next(next) {} + }; + + ListNode* cur; + +public: + BrowserHistory(string homepage) { + cur = new ListNode(homepage); + } + + void visit(string url) { + cur->next = new ListNode(url, cur, nullptr); + cur = cur->next; + } + + string back(int steps) { + while (cur->prev != nullptr && steps > 0) { + cur = cur->prev; + steps--; + } + return cur->val; + } + + string forward(int steps) { + while (cur->next != nullptr && steps > 0) { + cur = cur->next; + steps--; + } + return cur->val; + } +}; +``` + +```javascript +class ListNode { + constructor(val, prev = null, next = null) { + this.val = val; + this.prev = prev; + this.next = next; + } +} + +class BrowserHistory { + /** + * @constructor + * @param {string} homepage + */ + constructor(homepage) { + this.cur = new ListNode(homepage); + } + + /** + * @param {string} url + * @return {void} + */ + visit(url) { + this.cur.next = new ListNode(url, this.cur, null); + this.cur = this.cur.next; + } + + /** + * @param {number} steps + * @return {string} + */ + back(steps) { + while (this.cur.prev !== null && steps > 0) { + this.cur = this.cur.prev; + steps--; + } + return this.cur.val; + } + + /** + * @param {number} steps + * @return {string} + */ + forward(steps) { + while (this.cur.next !== null && steps > 0) { + this.cur = this.cur.next; + steps--; + } + return this.cur.val; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: + * $O(1)$ time for initialization. + * $O(1)$ time for each $visit()$ function call. + * $O(min(n, steps))$ time for each $back()$ and $forward()$ function calls. +* Space complexity: $O(m * n)$ + +> Where $n$ is the number of visited urls, $m$ is the average length of each url, and $steps$ is the number of steps we go forward or back. \ No newline at end of file diff --git a/articles/detonate-the-maximum-bombs.md b/articles/detonate-the-maximum-bombs.md new file mode 100644 index 000000000..bc1a75fc9 --- /dev/null +++ b/articles/detonate-the-maximum-bombs.md @@ -0,0 +1,522 @@ +## 1. Depth First Search + +::tabs-start + +```python +class Solution: + def maximumDetonation(self, bombs: list[list[int]]) -> int: + adj = [[] for _ in range(len(bombs))] + + for i in range(len(bombs)): + x1, y1, r1 = bombs[i] + for j in range(i + 1, len(bombs)): + x2, y2, r2 = bombs[j] + d = (x1 - x2) ** 2 + (y1 - y2) ** 2 + + if d <= r1 ** 2: + adj[i].append(j) + if d <= r2 ** 2: + adj[j].append(i) + + def dfs(i, visit): + if i in visit: + return 0 + visit.add(i) + for nei in adj[i]: + dfs(nei, visit) + return len(visit) + + res = 0 + for i in range(len(bombs)): + res = max(res, dfs(i, set())) + return res +``` + +```java +public class Solution { + public int maximumDetonation(int[][] bombs) { + int n = bombs.length; + List[] adj = new ArrayList[n]; + for (int i = 0; i < n; i++) { + adj[i] = new ArrayList<>(); + } + + for (int i = 0; i < n; i++) { + for (int j = i + 1; j < n; j++) { + int x1 = bombs[i][0], y1 = bombs[i][1], r1 = bombs[i][2]; + int x2 = bombs[j][0], y2 = bombs[j][1], r2 = bombs[j][2]; + long d = (long) (x1 - x2) * (x1 - x2) + (long) (y1 - y2) * (y1 - y2); + + if (d <= (long) r1 * r1) { + adj[i].add(j); + } + if (d <= (long) r2 * r2) { + adj[j].add(i); + } + } + } + + int res = 0; + for (int i = 0; i < n; i++) { + res = Math.max(res, dfs(i, new HashSet<>(), adj)); + } + return res; + } + + private int dfs(int i, Set visit, List[] adj) { + if (!visit.add(i)) return 0; + for (int nei : adj[i]) { + dfs(nei, visit, adj); + } + return visit.size(); + } +} +``` + +```cpp +class Solution { +public: + int maximumDetonation(vector>& bombs) { + int n = bombs.size(); + vector> adj(n); + + for (int i = 0; i < n; i++) { + for (int j = i + 1; j < n; j++) { + long long x1 = bombs[i][0], y1 = bombs[i][1], r1 = bombs[i][2]; + long long x2 = bombs[j][0], y2 = bombs[j][1], r2 = bombs[j][2]; + long long d = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2); + + if (d <= r1 * r1) { + adj[i].push_back(j); + } + if (d <= r2 * r2) { + adj[j].push_back(i); + } + } + } + + int res = 0; + for (int i = 0; i < n; i++) { + unordered_set visit; + res = max(res, dfs(i, visit, adj)); + } + return res; + } + +private: + int dfs(int i, unordered_set& visit, vector>& adj) { + if (!visit.insert(i).second) return 0; + for (int nei : adj[i]) { + dfs(nei, visit, adj); + } + return visit.size(); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} bombs + * @return {number} + */ + maximumDetonation(bombs) { + let n = bombs.length; + let adj = Array.from({ length: n }, () => []); + + for (let i = 0; i < n; i++) { + for (let j = i + 1; j < n; j++) { + let [x1, y1, r1] = bombs[i]; + let [x2, y2, r2] = bombs[j]; + let d = (x1 - x2) ** 2 + (y1 - y2) ** 2; + + if (d <= r1 ** 2) adj[i].push(j); + if (d <= r2 ** 2) adj[j].push(i); + } + } + + const dfs = (i, visit) => { + if (visit.has(i)) return 0; + visit.add(i); + for (let nei of adj[i]) { + dfs(nei, visit); + } + return visit.size; + }; + + let res = 0; + for (let i = 0; i < n; i++) { + res = Math.max(res, dfs(i, new Set())); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 3)$ +* Space complexity: $O(n ^ 2)$ + +--- + +## 2. Breadth First Search + +::tabs-start + +```python +class Solution: + def maximumDetonation(self, bombs: list[list[int]]) -> int: + n = len(bombs) + adj = [[] for _ in range(n)] + + for i in range(n): + x1, y1, r1 = bombs[i] + for j in range(i + 1, n): + x2, y2, r2 = bombs[j] + d = (x1 - x2) ** 2 + (y1 - y2) ** 2 + + if d <= r1 ** 2: + adj[i].append(j) + if d <= r2 ** 2: + adj[j].append(i) + + res = 0 + for i in range(n): + q = deque([i]) + visit = [False] * n + visit[i] = True + count = 1 + while q: + node = q.popleft() + for nei in adj[node]: + if not visit[nei]: + visit[nei] = True + count += 1 + q.append(nei) + res = max(res, count) + return res +``` + +```java +public class Solution { + public int maximumDetonation(int[][] bombs) { + int n = bombs.length; + List[] adj = new ArrayList[n]; + for (int i = 0; i < n; i++) { + adj[i] = new ArrayList<>(); + } + + for (int i = 0; i < n; i++) { + int x1 = bombs[i][0], y1 = bombs[i][1], r1 = bombs[i][2]; + for (int j = i + 1; j < n; j++) { + int x2 = bombs[j][0], y2 = bombs[j][1], r2 = bombs[j][2]; + long d = (long) (x1 - x2) * (x1 - x2) + (long) (y1 - y2) * (y1 - y2); + + if (d <= (long) r1 * r1) adj[i].add(j); + if (d <= (long) r2 * r2) adj[j].add(i); + } + } + + int res = 0; + for (int i = 0; i < n; i++) { + Queue q = new LinkedList<>(); + boolean[] visit = new boolean[n]; + q.offer(i); + visit[i] = true; + int count = 1; + + while (!q.isEmpty()) { + int node = q.poll(); + for (int nei : adj[node]) { + if (!visit[nei]) { + visit[nei] = true; + count++; + q.offer(nei); + } + } + } + res = Math.max(res, count); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int maximumDetonation(vector>& bombs) { + int n = bombs.size(); + vector> adj(n); + + for (int i = 0; i < n; i++) { + int x1 = bombs[i][0], y1 = bombs[i][1], r1 = bombs[i][2]; + for (int j = i + 1; j < n; j++) { + int x2 = bombs[j][0], y2 = bombs[j][1], r2 = bombs[j][2]; + long long d = (x1 - x2) * 1LL * (x1 - x2) + (y1 - y2) * 1LL * (y1 - y2); + + if (d <= (long long) r1 * r1) adj[i].push_back(j); + if (d <= (long long) r2 * r2) adj[j].push_back(i); + } + } + + int res = 0; + for (int i = 0; i < n; i++) { + queue q; + vector visit(n, false); + q.push(i); + visit[i] = true; + int count = 1; + + while (!q.empty()) { + int node = q.front();q.pop(); + for (int& nei : adj[node]) { + if (!visit[nei]) { + visit[nei] = true; + count++; + q.push(nei); + } + } + } + res = max(res, count); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} bombs + * @return {number} + */ + maximumDetonation(bombs) { + let n = bombs.length; + let adj = Array.from({ length: n }, () => []); + + for (let i = 0; i < n; i++) { + let [x1, y1, r1] = bombs[i]; + for (let j = i + 1; j < n; j++) { + let [x2, y2, r2] = bombs[j]; + let d = (x1 - x2) ** 2 + (y1 - y2) ** 2; + + if (d <= r1 ** 2) adj[i].push(j); + if (d <= r2 ** 2) adj[j].push(i); + } + } + + let res = 0; + for (let i = 0; i < n; i++) { + let q = new Queue([i]); + let visit = new Array(n).fill(false); + visit[i] = true; + let count = 1; + + while (!q.isEmpty()) { + let node = q.pop(); + for (let nei of adj[node]) { + if (!visit[nei]) { + visit[nei] = true; + count++; + q.push(nei); + } + } + } + res = Math.max(res, count); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 3)$ +* Space complexity: $O(n ^ 2)$ + +--- + +## 3. Iterative DFS + +::tabs-start + +```python +class Solution: + def maximumDetonation(self, bombs: list[list[int]]) -> int: + n = len(bombs) + adj = [[] for _ in range(n)] + + for i in range(n): + x1, y1, r1 = bombs[i] + for j in range(i + 1, n): + x2, y2, r2 = bombs[j] + d = (x1 - x2) ** 2 + (y1 - y2) ** 2 + + if d <= r1 ** 2: + adj[i].append(j) + if d <= r2 ** 2: + adj[j].append(i) + + res = 0 + for i in range(n): + stack = [i] + visit = [False] * n + visit[i] = True + count = 1 + + while stack: + node = stack.pop() + for nei in adj[node]: + if not visit[nei]: + visit[nei] = True + count += 1 + stack.append(nei) + res = max(res, count) + return res +``` + +```java +public class Solution { + public int maximumDetonation(int[][] bombs) { + int n = bombs.length; + List[] adj = new ArrayList[n]; + for (int i = 0; i < n; i++) { + adj[i] = new ArrayList<>(); + } + + for (int i = 0; i < n; i++) { + int x1 = bombs[i][0], y1 = bombs[i][1], r1 = bombs[i][2]; + for (int j = i + 1; j < n; j++) { + int x2 = bombs[j][0], y2 = bombs[j][1], r2 = bombs[j][2]; + long d = (long) (x1 - x2) * (x1 - x2) + (long) (y1 - y2) * (y1 - y2); + + if (d <= (long) r1 * r1) adj[i].add(j); + if (d <= (long) r2 * r2) adj[j].add(i); + } + } + + int res = 0; + for (int i = 0; i < n; i++) { + Stack stack = new Stack<>(); + boolean[] visit = new boolean[n]; + stack.push(i); + visit[i] = true; + int count = 1; + + while (!stack.isEmpty()) { + int node = stack.pop(); + for (int nei : adj[node]) { + if (!visit[nei]) { + visit[nei] = true; + count++; + stack.push(nei); + } + } + } + res = Math.max(res, count); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int maximumDetonation(vector>& bombs) { + int n = bombs.size(); + vector> adj(n); + + for (int i = 0; i < n; i++) { + int x1 = bombs[i][0], y1 = bombs[i][1], r1 = bombs[i][2]; + for (int j = i + 1; j < n; j++) { + int x2 = bombs[j][0], y2 = bombs[j][1], r2 = bombs[j][2]; + long long d = (long long)(x1 - x2) * (x1 - x2) + (long long)(y1 - y2) * (y1 - y2); + + if (d <= (long long) r1 * r1) adj[i].push_back(j); + if (d <= (long long) r2 * r2) adj[j].push_back(i); + } + } + + int res = 0; + for (int i = 0; i < n; i++) { + stack stk; + vector visit(n, false); + stk.push(i); + visit[i] = true; + int count = 1; + + while (!stk.empty()) { + int node = stk.top();stk.pop(); + for (int& nei : adj[node]) { + if (!visit[nei]) { + visit[nei] = true; + count++; + stk.push(nei); + } + } + } + res = max(res, count); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} bombs + * @return {number} + */ + maximumDetonation(bombs) { + let n = bombs.length; + let adj = Array.from({ length: n }, () => []); + + for (let i = 0; i < n; i++) { + let [x1, y1, r1] = bombs[i]; + for (let j = i + 1; j < n; j++) { + let [x2, y2, r2] = bombs[j]; + let d = (x1 - x2) ** 2 + (y1 - y2) ** 2; + + if (d <= r1 ** 2) adj[i].push(j); + if (d <= r2 ** 2) adj[j].push(i); + } + } + + let res = 0; + for (let i = 0; i < n; i++) { + let stack = [i]; + let visit = new Array(n).fill(false); + visit[i] = true; + let count = 1; + + while (stack.length) { + let node = stack.pop(); + for (let nei of adj[node]) { + if (!visit[nei]) { + visit[nei] = true; + count++; + stack.push(nei); + } + } + } + res = Math.max(res, count); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 3)$ +* Space complexity: $O(n ^ 2)$ \ No newline at end of file diff --git a/articles/distribute-coins-in-binary-tree.md b/articles/distribute-coins-in-binary-tree.md new file mode 100644 index 000000000..4e26d25e9 --- /dev/null +++ b/articles/distribute-coins-in-binary-tree.md @@ -0,0 +1,723 @@ +## 1. Depth First Search + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def distributeCoins(self, root: Optional[TreeNode]) -> int: + self.res = 0 + + def dfs(cur): + if not cur: + return [0, 0] # [size, coins] + + l_size, l_coins = dfs(cur.left) + r_size, r_coins = dfs(cur.right) + + size = 1 + l_size + r_size + coins = cur.val + l_coins + r_coins + self.res += abs(size - coins) + + return [size, coins] + + dfs(root) + return self.res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + private int res; + + public int distributeCoins(TreeNode root) { + res = 0; + dfs(root); + return res; + } + + private int[] dfs(TreeNode cur) { + if (cur == null) { + return new int[]{0, 0}; // [size, coins] + } + + int[] left = dfs(cur.left); + int[] right = dfs(cur.right); + + int size = 1 + left[0] + right[0]; + int coins = cur.val + left[1] + right[1]; + res += Math.abs(size - coins); + + return new int[]{size, coins}; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +private: + int res; + + vector dfs(TreeNode* cur) { + if (!cur) { + return {0, 0}; // [size, coins] + } + + vector left = dfs(cur->left); + vector right = dfs(cur->right); + + int size = 1 + left[0] + right[0]; + int coins = cur->val + left[1] + right[1]; + res += abs(size - coins); + + return {size, coins}; + } + +public: + int distributeCoins(TreeNode* root) { + res = 0; + dfs(root); + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number} + */ + distributeCoins(root) { + let res = 0; + + const dfs = (cur) => { + if (!cur) { + return [0, 0]; // [size, coins] + } + + let [lSize, lCoins] = dfs(cur.left); + let [rSize, rCoins] = dfs(cur.right); + + let size = 1 + lSize + rSize; + let coins = cur.val + lCoins + rCoins; + res += Math.abs(size - coins); + + return [size, coins]; + }; + + dfs(root); + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ for recursion stack. + +--- + +## 2. Depth First Search (Optimal) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def distributeCoins(self, root: Optional[TreeNode]) -> int: + self.res = 0 + + def dfs(cur): + if not cur: + return 0 # extra_coins + + l_extra = dfs(cur.left) + r_extra = dfs(cur.right) + + extra_coins = cur.val - 1 + l_extra + r_extra + self.res += abs(extra_coins) + return extra_coins + + dfs(root) + return self.res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + private int res; + + public int distributeCoins(TreeNode root) { + res = 0; + dfs(root); + return res; + } + + private int dfs(TreeNode cur) { + if (cur == null) { + return 0; // extra_coins + } + + int lExtra = dfs(cur.left); + int rExtra = dfs(cur.right); + + int extraCoins = cur.val - 1 + lExtra + rExtra; + res += Math.abs(extraCoins); + return extraCoins; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +private: + int res; + + int dfs(TreeNode* cur) { + if (!cur) { + return 0; // extra_coins + } + + int lExtra = dfs(cur->left); + int rExtra = dfs(cur->right); + + int extraCoins = cur->val - 1 + lExtra + rExtra; + res += abs(extraCoins); + return extraCoins; + } + +public: + int distributeCoins(TreeNode* root) { + res = 0; + dfs(root); + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number} + */ + distributeCoins(root) { + let res = 0; + + const dfs = (cur) => { + if (!cur) { + return 0; // extra_coins + } + + let lExtra = dfs(cur.left); + let rExtra = dfs(cur.right); + + let extraCoins = cur.val - 1 + lExtra + rExtra; + res += Math.abs(extraCoins); + return extraCoins; + }; + + dfs(root); + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ fo recursion stack. + +--- + +## 3. Breadth First Search + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def distributeCoins(self, root: Optional[TreeNode]) -> int: + res = 0 + q = deque([root]) + parent_map = {} + + nodes = [] + while q: + node = q.popleft() + nodes.append(node) + if node.left: + parent_map[node.left] = node + q.append(node.left) + if node.right: + parent_map[node.right] = node + q.append(node.right) + + while nodes: + node = nodes.pop() + if node in parent_map: + parent = parent_map[node] + parent.val += node.val - 1 + res += abs(node.val - 1) + + return res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public int distributeCoins(TreeNode root) { + int res = 0; + Queue q = new LinkedList<>(); + Map parentMap = new HashMap<>(); + List nodes = new ArrayList<>(); + + q.offer(root); + while (!q.isEmpty()) { + TreeNode node = q.poll(); + nodes.add(node); + if (node.left != null) { + parentMap.put(node.left, node); + q.offer(node.left); + } + if (node.right != null) { + parentMap.put(node.right, node); + q.offer(node.right); + } + } + + for (int i = nodes.size() - 1; i >= 0; i--) { + TreeNode node = nodes.get(i); + if (parentMap.containsKey(node)) { + TreeNode parent = parentMap.get(node); + parent.val += node.val - 1; + res += Math.abs(node.val - 1); + } + } + + return res; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + int distributeCoins(TreeNode* root) { + int res = 0; + queue q; + unordered_map parentMap; + vector nodes; + + q.push(root); + while (!q.empty()) { + TreeNode* node = q.front(); + q.pop(); + nodes.push_back(node); + if (node->left) { + parentMap[node->left] = node; + q.push(node->left); + } + if (node->right) { + parentMap[node->right] = node; + q.push(node->right); + } + } + + for (int i = nodes.size() - 1; i >= 0; i--) { + TreeNode* node = nodes[i]; + if (parentMap.count(node)) { + TreeNode* parent = parentMap[node]; + parent->val += node->val - 1; + res += abs(node->val - 1); + } + } + + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number} + */ + distributeCoins(root) { + let res = 0; + let q = new Queue(); + let parentMap = new Map(); + let nodes = []; + + q.push(root); + while (!q.isEmpty()) { + let node = q.pop(); + nodes.push(node); + if (node.left) { + parentMap.set(node.left, node); + q.push(node.left); + } + if (node.right) { + parentMap.set(node.right, node); + q.push(node.right); + } + } + + for (let i = nodes.length - 1; i >= 0; i--) { + let node = nodes[i]; + if (parentMap.has(node)) { + let parent = parentMap.get(node); + parent.val += node.val - 1; + res += Math.abs(node.val - 1); + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 4. Iterative DFS + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def distributeCoins(self, root: Optional[TreeNode]) -> int: + stack = [root] + res = 0 + visit = set() + + while stack: + node = stack.pop() + + if node not in visit: + stack.append(node) + visit.add(node) + + if node.right: + stack.append(node.right) + if node.left: + stack.append(node.left) + else: + if node.left: + node.val += node.left.val + if node.right: + node.val += node.right.val + + node.val -= 1 + res += abs(node.val) + visit.remove(node) + + return res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public int distributeCoins(TreeNode root) { + Stack stack = new Stack<>(); + Set visit = new HashSet<>(); + stack.push(root); + int res = 0; + + while (!stack.isEmpty()) { + TreeNode node = stack.pop(); + + if (!visit.contains(node)) { + stack.push(node); + visit.add(node); + + if (node.right != null) { + stack.push(node.right); + } + if (node.left != null) { + stack.push(node.left); + } + } else { + if (node.left != null) { + node.val += node.left.val; + } + if (node.right != null) { + node.val += node.right.val; + } + + node.val -= 1; + res += Math.abs(node.val); + visit.remove(node); + } + } + + return res; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + int distributeCoins(TreeNode* root) { + stack stack; + unordered_set visit; + stack.push(root); + int res = 0; + + while (!stack.empty()) { + TreeNode* node = stack.top(); + stack.pop(); + + if (visit.find(node) == visit.end()) { + stack.push(node); + visit.insert(node); + + if (node->right) { + stack.push(node->right); + } + if (node->left) { + stack.push(node->left); + } + } else { + if (node->left) { + node->val += node->left->val; + } + if (node->right) { + node->val += node->right->val; + } + + visit.erase(node); + node->val -= 1; + res += abs(node->val); + } + } + + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number} + */ + distributeCoins(root) { + let stack = [root]; + let visit = new Set(); + let res = 0; + + while (stack.length) { + let node = stack.pop(); + + if (!visit.has(node)) { + stack.push(node); + visit.add(node); + + if (node.right) { + stack.push(node.right); + } + if (node.left) { + stack.push(node.left); + } + } else { + if (node.left) { + node.val += node.left.val; + } + if (node.right) { + node.val += node.right.val; + } + + visit.delete(node); + node.val -= 1; + res += Math.abs(node.val); + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ \ No newline at end of file diff --git a/articles/eliminate-maximum-number-of-monsters.md b/articles/eliminate-maximum-number-of-monsters.md new file mode 100644 index 000000000..551c82473 --- /dev/null +++ b/articles/eliminate-maximum-number-of-monsters.md @@ -0,0 +1,298 @@ +## 1. Sorting + +::tabs-start + +```python +class Solution: + def eliminateMaximum(self, dist: List[int], speed: List[int]) -> int: + minReach = [math.ceil(d / s) for d, s in zip(dist, speed)] + minReach.sort() + + res = 0 + for minute in range(len(minReach)): + if minute >= minReach[minute]: + return res + res += 1 + + return res +``` + +```java +public class Solution { + public int eliminateMaximum(int[] dist, int[] speed) { + int n = dist.length; + int[] minReach = new int[n]; + + for (int i = 0; i < n; i++) { + minReach[i] = (int) Math.ceil((double) dist[i] / speed[i]); + } + + Arrays.sort(minReach); + + int res = 0; + for (int minute = 0; minute < n; minute++) { + if (minute >= minReach[minute]) { + return res; + } + res++; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int eliminateMaximum(vector& dist, vector& speed) { + int n = dist.size(); + vector minReach(n); + + for (int i = 0; i < n; i++) { + minReach[i] = ceil((double)dist[i] / speed[i]); + } + + sort(minReach.begin(), minReach.end()); + + int res = 0; + for (int minute = 0; minute < n; minute++) { + if (minute >= minReach[minute]) { + return res; + } + res++; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} dist + * @param {number[]} speed + * @return {number} + */ + eliminateMaximum(dist, speed) { + let n = dist.length; + let minReach = new Array(n); + + for (let i = 0; i < n; i++) { + minReach[i] = Math.ceil(dist[i] / speed[i]); + } + + minReach.sort((a, b) => a - b); + + let res = 0; + for (let minute = 0; minute < n; minute++) { + if (minute >= minReach[minute]) { + return res; + } + res++; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(n)$ + +--- + +## 2. Sorting (Overwrting Input Array) + +::tabs-start + +```python +class Solution: + def eliminateMaximum(self, dist: List[int], speed: List[int]) -> int: + for i in range(len(dist)): + dist[i] = math.ceil(dist[i] / speed[i]) + + dist.sort() + for minute in range(len(dist)): + if minute >= dist[minute]: + return minute + + return len(dist) +``` + +```java +public class Solution { + public int eliminateMaximum(int[] dist, int[] speed) { + int n = dist.length; + for (int i = 0; i < n; i++) { + dist[i] = (int) Math.ceil((double) dist[i] / speed[i]); + } + + Arrays.sort(dist); + for (int minute = 0; minute < n; minute++) { + if (minute >= dist[minute]) { + return minute; + } + } + + return n; + } +} +``` + +```cpp +class Solution { +public: + int eliminateMaximum(vector& dist, vector& speed) { + int n = dist.size(); + for (int i = 0; i < n; i++) { + dist[i] = ceil((double)dist[i] / speed[i]); + } + + sort(dist.begin(), dist.end()); + for (int minute = 0; minute < n; minute++) { + if (minute >= dist[minute]) { + return minute; + } + } + + return n; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} dist + * @param {number[]} speed + * @return {number} + */ + eliminateMaximum(dist, speed) { + let n = dist.length; + for (let i = 0; i < n; i++) { + dist[i] = Math.ceil(dist[i] / speed[i]); + } + + dist.sort((a, b) => a - b); + for (let minute = 0; minute < n; minute++) { + if (minute >= dist[minute]) { + return minute; + } + } + + return n; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. + +--- + +## 3. Min-Heap + +::tabs-start + +```python +class Solution: + def eliminateMaximum(self, dist: List[int], speed: List[int]) -> int: + minHeap = [] + for i in range(len(dist)): + heapq.heappush(minHeap, dist[i] / speed[i]) + + res = 0 + while minHeap: + if res >= heapq.heappop(minHeap): + return res + res += 1 + + return res +``` + +```java +public class Solution { + public int eliminateMaximum(int[] dist, int[] speed) { + PriorityQueue minHeap = new PriorityQueue<>(); + for (int i = 0; i < dist.length; i++) { + minHeap.add((double) dist[i] / speed[i]); + } + + int res = 0; + while (!minHeap.isEmpty()) { + if (res >= minHeap.poll()) { + return res; + } + res++; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int eliminateMaximum(vector& dist, vector& speed) { + priority_queue, greater> minHeap; + for (int i = 0; i < dist.size(); i++) { + minHeap.push((double)dist[i] / speed[i]); + } + + int res = 0; + while (!minHeap.empty()) { + if (res >= minHeap.top()) { + return res; + } + minHeap.pop(); + res++; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} dist + * @param {number[]} speed + * @return {number} + */ + eliminateMaximum(dist, speed) { + const minHeap = new MinPriorityQueue(); + for (let i = 0; i < dist.length; i++) { + minHeap.enqueue(dist[i] / speed[i]); + } + + let res = 0; + while (!minHeap.isEmpty()) { + if (res >= minHeap.dequeue().element) { + return res; + } + res++; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(n)$ \ No newline at end of file diff --git a/articles/find-all-people-with-secret.md b/articles/find-all-people-with-secret.md new file mode 100644 index 000000000..1d1b58e20 --- /dev/null +++ b/articles/find-all-people-with-secret.md @@ -0,0 +1,834 @@ +## 1. Depth First Search + +::tabs-start + +```python +class Solution: + def findAllPeople(self, n: int, meetings: list[list[int]], firstPerson: int) -> list[int]: + secrets = set([0, firstPerson]) # People with secret + time_map = {} # time -> adjacency list meetings + + for src, dst, t in meetings: + if t not in time_map: + time_map[t] = defaultdict(list) + time_map[t][src].append(dst) + time_map[t][dst].append(src) + + def dfs(src, adj): + if src in visit: + return + visit.add(src) + secrets.add(src) + for nei in adj[src]: + dfs(nei, adj) + + for t in sorted(time_map.keys()): + visit = set() + for src in time_map[t]: + if src in secrets: + dfs(src, time_map[t]) + + return list(secrets) +``` + +```java +public class Solution { + private Set secrets, visit; + + public List findAllPeople(int n, int[][] meetings, int firstPerson) { + secrets = new HashSet<>(); + visit = new HashSet<>(); + secrets.add(0); + secrets.add(firstPerson); + Map>> time_map = new HashMap<>(); + + for (int[] meet : meetings) { + int src = meet[0], dst = meet[1], t = meet[2]; + time_map.putIfAbsent(t, new HashMap<>()); + time_map.get(t).putIfAbsent(src, new ArrayList<>()); + time_map.get(t).putIfAbsent(dst, new ArrayList<>()); + time_map.get(t).get(src).add(dst); + time_map.get(t).get(dst).add(src); + } + + List timeKeys = new ArrayList<>(time_map.keySet()); + Collections.sort(timeKeys); + for (int t : timeKeys) { + visit = new HashSet<>(); + for (int src : time_map.get(t).keySet()) { + if (secrets.contains(src)) { + dfs(src, time_map.get(t)); + } + } + } + return new ArrayList<>(secrets); + } + + private void dfs(int src, Map> adj) { + if (!visit.add(src)) return; + secrets.add(src); + for (int nei : adj.getOrDefault(src, new ArrayList<>())) { + dfs(nei, adj); + } + } +} +``` + +```cpp +class Solution { +public: + unordered_set secrets, visit; + + vector findAllPeople(int n, vector>& meetings, int firstPerson) { + secrets = {0, firstPerson}; + unordered_map>> time_map; + + for (auto& meet : meetings) { + int src = meet[0], dst = meet[1], t = meet[2]; + time_map[t][src].push_back(dst); + time_map[t][dst].push_back(src); + } + + vector timeKeys; + for (auto& [t, _] : time_map) { + timeKeys.push_back(t); + } + sort(timeKeys.begin(), timeKeys.end()); + + for (int& t : timeKeys) { + visit.clear(); + for (auto& [src, _] : time_map[t]) { + if (secrets.count(src)) { + dfs(src, time_map[t]); + } + } + } + + return vector(secrets.begin(), secrets.end()); + } + +private: + void dfs(int src, unordered_map>& adj) { + if (!visit.insert(src).second) return; + secrets.insert(src); + for (int& nei : adj[src]) { + dfs(nei, adj); + } + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number[][]} meetings + * @param {number} firstPerson + * @return {number[]} + */ + findAllPeople(n, meetings, firstPerson) { + const secrets = new Set([0, firstPerson]); + let visit = new Set(); + let time_map = new Map(); + + for (let [src, dst, t] of meetings) { + if (!time_map.has(t)) time_map.set(t, new Map()); + if (!time_map.get(t).has(src)) time_map.get(t).set(src, []); + if (!time_map.get(t).has(dst)) time_map.get(t).set(dst, []); + time_map.get(t).get(src).push(dst); + time_map.get(t).get(dst).push(src); + } + const dfs = (src, adj) => { + if (visit.has(src)) return; + visit.add(src); + secrets.add(src); + for (let nei of (adj.get(src) || [])) { + dfs(nei, adj); + } + }; + + let timeKeys = [...time_map.keys()].sort((a, b) => a - b); + for (let t of timeKeys) { + visit.clear(); + for (let src of time_map.get(t).keys()) { + if (secrets.has(src)) { + dfs(src, time_map.get(t)); + } + } + } + + return [...secrets]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m \log m + n)$ +* Space complexity: $O(m + n)$ + +> Where $m$ is the number of meetings and $n$ is the number of people. + +--- + +## 2. Breadth First Search + +::tabs-start + +```python +class Solution: + def findAllPeople(self, n: int, meetings: list[list[int]], firstPerson: int) -> list[int]: + secrets = set([0, firstPerson]) # People with secret + time_map = {} # time -> adjacency list meetings + + for src, dst, t in meetings: + if t not in time_map: + time_map[t] = defaultdict(list) + time_map[t][src].append(dst) + time_map[t][dst].append(src) + + for t in sorted(time_map.keys()): + visit = set() + q = deque() + + for src in time_map[t]: + if src in secrets: + q.append(src) + visit.add(src) + + while q: + node = q.popleft() + secrets.add(node) + for nei in time_map[t][node]: + if nei not in visit: + visit.add(nei) + q.append(nei) + + return list(secrets) +``` + +```java +public class Solution { + public List findAllPeople(int n, int[][] meetings, int firstPerson) { + Set secrets = new HashSet<>(); + secrets.add(0); + secrets.add(firstPerson); + TreeMap>> time_map = new TreeMap<>(); + + for (int[] meet : meetings) { + int src = meet[0], dst = meet[1], t = meet[2]; + time_map.putIfAbsent(t, new HashMap<>()); + time_map.get(t).putIfAbsent(src, new ArrayList<>()); + time_map.get(t).putIfAbsent(dst, new ArrayList<>()); + time_map.get(t).get(src).add(dst); + time_map.get(t).get(dst).add(src); + } + + for (int t : time_map.keySet()) { + Set visit = new HashSet<>(); + Queue q = new LinkedList<>(); + + for (int src : time_map.get(t).keySet()) { + if (secrets.contains(src)) { + q.offer(src); + visit.add(src); + } + } + + while (!q.isEmpty()) { + int node = q.poll(); + secrets.add(node); + for (int nei : time_map.get(t).get(node)) { + if (!visit.contains(nei)) { + visit.add(nei); + q.offer(nei); + } + } + } + } + + return new ArrayList<>(secrets); + } +} +``` + +```cpp +class Solution { +public: + vector findAllPeople(int n, vector>& meetings, int firstPerson) { + unordered_set secrets = {0, firstPerson}; + map>> time_map; + + for (auto& meet : meetings) { + int src = meet[0], dst = meet[1], t = meet[2]; + time_map[t][src].push_back(dst); + time_map[t][dst].push_back(src); + } + + for (auto& [t, adj] : time_map) { + unordered_set visit; + queue q; + + for (auto& [src, _] : adj) { + if (secrets.count(src)) { + q.push(src); + visit.insert(src); + } + } + + while (!q.empty()) { + int node = q.front(); + q.pop(); + secrets.insert(node); + for (int nei : adj[node]) { + if (!visit.count(nei)) { + visit.insert(nei); + q.push(nei); + } + } + } + } + + return vector(secrets.begin(), secrets.end()); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number[][]} meetings + * @param {number} firstPerson + * @return {number[]} + */ + findAllPeople(n, meetings, firstPerson) { + const secrets = new Set([0, firstPerson]); + const time_map = new Map(); + + for (let [src, dst, t] of meetings) { + if (!time_map.has(t)) time_map.set(t, new Map()); + if (!time_map.get(t).has(src)) time_map.get(t).set(src, []); + if (!time_map.get(t).has(dst)) time_map.get(t).set(dst, []); + time_map.get(t).get(src).push(dst); + time_map.get(t).get(dst).push(src); + } + + for (let t of [...time_map.keys()].sort((a, b) => a - b)) { + let visit = new Set(); + const q = new Queue(); + + for (let src of time_map.get(t).keys()) { + if (secrets.has(src)) { + q.push(src); + visit.add(src); + } + } + + while (!q.isEmpty()) { + let node = q.pop(); + secrets.add(node); + for (let nei of time_map.get(t).get(node)) { + if (!visit.has(nei)) { + visit.add(nei); + q.push(nei); + } + } + } + } + + return [...secrets]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m \log m + n)$ +* Space complexity: $O(m + n)$ + +> Where $m$ is the number of meetings and $n$ is the number of people. + +--- + +## 3. Iterative DFS + +::tabs-start + +```python +class Solution: + def findAllPeople(self, n: int, meetings: list[list[int]], firstPerson: int) -> list[int]: + meetings.sort(key=lambda x: x[2]) # Sort by time + secrets = [False] * n + secrets[0] = secrets[firstPerson] = True + + for _, group in groupby(meetings, key=lambda x: x[2]): + adj = defaultdict(list) + visited = set() + + for u, v, _ in group: + adj[u].append(v) + adj[v].append(u) + if secrets[u]: + visited.add(u) + if secrets[v]: + visited.add(v) + + stack = list(visited) + while stack: + node = stack.pop() + for nei in adj[node]: + if nei not in visited: + visited.add(nei) + stack.append(nei) + secrets[nei] = True + + return [i for i in range(n) if secrets[i]] +``` + +```java +public class Solution { + public List findAllPeople(int n, int[][] meetings, int firstPerson) { + Arrays.sort(meetings, Comparator.comparingInt(a -> a[2])); + boolean[] secrets = new boolean[n]; + secrets[0] = secrets[firstPerson] = true; + + int i = 0, m = meetings.length; + while (i < m) { + int time = meetings[i][2]; + Map> adj = new HashMap<>(); + Set visited = new HashSet<>(); + + while (i < m && meetings[i][2] == time) { + int u = meetings[i][0], v = meetings[i][1]; + adj.computeIfAbsent(u, k -> new ArrayList<>()).add(v); + adj.computeIfAbsent(v, k -> new ArrayList<>()).add(u); + if (secrets[u]) visited.add(u); + if (secrets[v]) visited.add(v); + i++; + } + + Stack stack = new Stack<>(); + stack.addAll(visited); + while (!stack.isEmpty()) { + int node = stack.pop(); + for (int nei : adj.getOrDefault(node, Collections.emptyList())) { + if (!visited.contains(nei)) { + visited.add(nei); + stack.push(nei); + secrets[nei] = true; + } + } + } + } + + List res = new ArrayList<>(); + for (int j = 0; j < n; j++) { + if (secrets[j]) res.add(j); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + vector findAllPeople(int n, vector>& meetings, int firstPerson) { + sort(meetings.begin(), meetings.end(), [](auto& a, auto& b) { + return a[2] < b[2]; + }); + + vector secrets(n, false); + secrets[0] = secrets[firstPerson] = true; + + int i = 0, m = meetings.size(); + while (i < m) { + int time = meetings[i][2]; + unordered_map> adj; + unordered_set visited; + + while (i < m && meetings[i][2] == time) { + int u = meetings[i][0], v = meetings[i][1]; + adj[u].push_back(v); + adj[v].push_back(u); + if (secrets[u]) visited.insert(u); + if (secrets[v]) visited.insert(v); + i++; + } + + stack stack(visited.begin(), visited.end()); + while (!stack.empty()) { + int node = stack.top(); stack.pop(); + for (int& nei : adj[node]) { + if (!visited.count(nei)) { + visited.insert(nei); + stack.push(nei); + secrets[nei] = true; + } + } + } + } + + vector res; + for (int j = 0; j < n; j++) { + if (secrets[j]) res.push_back(j); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number[][]} meetings + * @param {number} firstPerson + * @return {number[]} + */ + findAllPeople(n, meetings, firstPerson) { + meetings.sort((a, b) => a[2] - b[2]); + const secrets = new Array(n).fill(false); + secrets[0] = secrets[firstPerson] = true; + + let i = 0, m = meetings.length; + while (i < m) { + const time = meetings[i][2]; + const adj = new Map(); + const visited = new Set(); + + while (i < m && meetings[i][2] === time) { + const [u, v] = meetings[i]; + if (!adj.has(u)) adj.set(u, []); + if (!adj.has(v)) adj.set(v, []); + adj.get(u).push(v); + adj.get(v).push(u); + if (secrets[u]) visited.add(u); + if (secrets[v]) visited.add(v); + i++; + } + + const stack = [...visited]; + while (stack.length) { + const node = stack.pop(); + for (const nei of (adj.get(node) || [])) { + if (!visited.has(nei)) { + visited.add(nei); + stack.push(nei); + secrets[nei] = true; + } + } + } + } + + let res = []; + for (let i = 0; i < n; i++) { + if (secrets[i]) res.push(i); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m \log m + n)$ +* Space complexity: $O(m + n)$ + +> Where $m$ is the number of meetings and $n$ is the number of people. + +--- + +## 4. Disjoint Set Union + +::tabs-start + +```python +class DSU: + def __init__(self, n): + self.Parent = list(range(n + 1)) + self.Size = [1] * (n + 1) + + def find(self, node): + if self.Parent[node] != node: + self.Parent[node] = self.find(self.Parent[node]) + return self.Parent[node] + + def union(self, u, v): + pu, pv = self.find(u), self.find(v) + if pu == pv: + return False + if self.Size[pu] < self.Size[pv]: + pu, pv = pv, pu + self.Size[pu] += self.Size[pv] + self.Parent[pv] = pu + return True + + def reset(self, node): + self.Parent[node] = node + self.Size[node] = 1 + +class Solution: + def findAllPeople(self, n: int, meetings: list[list[int]], firstPerson: int) -> list[int]: + meetings.sort(key=lambda x: x[2]) # Sort by time + dsu = DSU(n) + dsu.union(0, firstPerson) + + for _, group in groupby(meetings, key=lambda x: x[2]): + group_nodes = set() + for u, v, _ in group: + dsu.union(u, v) + group_nodes.add(u) + group_nodes.add(v) + + for node in group_nodes: + if dsu.find(node) != dsu.find(0): + dsu.reset(node) + + return [i for i in range(n) if dsu.find(i) == dsu.find(0)] +``` + +```java +class DSU { + int[] Parent, Size; + + DSU(int n) { + Parent = new int[n + 1]; + Size = new int[n + 1]; + for (int i = 0; i <= n; i++) { + Parent[i] = i; + Size[i] = 1; + } + } + + int find(int node) { + if (Parent[node] != node) { + Parent[node] = find(Parent[node]); + } + return Parent[node]; + } + + void union(int u, int v) { + int pu = find(u), pv = find(v); + if (pu == pv) return; + if (Size[pu] < Size[pv]) { + int temp = pu; + pu = pv; + pv = temp; + } + Size[pu] += Size[pv]; + Parent[pv] = pu; + } + + void reset(int node) { + Parent[node] = node; + Size[node] = 1; + } +} + +public class Solution { + public List findAllPeople(int n, int[][] meetings, int firstPerson) { + Arrays.sort(meetings, Comparator.comparingInt(a -> a[2])); + DSU dsu = new DSU(n); + dsu.union(0, firstPerson); + + for (int i = 0; i < meetings.length; ) { + int time = meetings[i][2]; + Set group = new HashSet<>(); + + for (; i < meetings.length && meetings[i][2] == time; i++) { + int u = meetings[i][0], v = meetings[i][1]; + dsu.union(u, v); + group.add(u); + group.add(v); + } + + for (int node : group) { + if (dsu.find(node) != dsu.find(0)) { + dsu.reset(node); + } + } + } + + List result = new ArrayList<>(); + for (int i = 0; i < n; i++) { + if (dsu.find(i) == dsu.find(0)) result.add(i); + } + return result; + } +} +``` + +```cpp +class DSU { +public: + vector Parent, Size; + + DSU(int n) { + Parent.resize(n + 1); + Size.resize(n + 1, 1); + for (int i = 0; i <= n; i++) { + Parent[i] = i; + } + } + + int find(int node) { + if (Parent[node] != node) { + Parent[node] = find(Parent[node]); + } + return Parent[node]; + } + + void unionSets(int u, int v) { + int pu = find(u), pv = find(v); + if (pu == pv) return; + if (Size[pu] < Size[pv]) swap(pu, pv); + Size[pu] += Size[pv]; + Parent[pv] = pu; + } + + void reset(int node) { + Parent[node] = node; + Size[node] = 1; + } +}; + +class Solution { +public: + vector findAllPeople(int n, vector>& meetings, int firstPerson) { + sort(meetings.begin(), meetings.end(), [](auto &a, auto &b) { + return a[2] < b[2]; + }); + DSU dsu(n); + dsu.unionSets(0, firstPerson); + + for (int i = 0; i < meetings.size(); ) { + int time = meetings[i][2]; + unordered_set group; + + for (; i < meetings.size() && meetings[i][2] == time; i++) { + int u = meetings[i][0], v = meetings[i][1]; + dsu.unionSets(u, v); + group.insert(u); + group.insert(v); + } + + for (int node : group) { + if (dsu.find(node) != dsu.find(0)) { + dsu.reset(node); + } + } + } + + vector result; + for (int i = 0; i < n; i++) { + if (dsu.find(i) == dsu.find(0)) result.push_back(i); + } + return result; + } +}; +``` + +```javascript +class DSU { + /** + * @constructor + * @param {number} n + */ + constructor(n) { + this.Parent = Array.from({ length: n + 1 }, (_, i) => i); + this.Size = Array(n + 1).fill(1); + } + + /** + * @param {number} node + * @return {number} + */ + find(node) { + if (this.Parent[node] !== node) { + this.Parent[node] = this.find(this.Parent[node]); + } + return this.Parent[node]; + } + + /** + * @param {number} u + * @param {number} v + * @return {boolean} + */ + union(u, v) { + let pu = this.find(u); + let pv = this.find(v); + if (pu === pv) return false; + if (this.Size[pu] >= this.Size[pv]) { + this.Size[pu] += this.Size[pv]; + this.Parent[pv] = pu; + } else { + this.Size[pv] += this.Size[pu]; + this.Parent[pu] = pv; + } + return true; + } + + /** + * @param {number} node + * @return {void} + */ + reset(node) { + this.Parent[node] = node; + this.Size[node] = 1; + } +} + +class Solution { + /** + * @param {number} n + * @param {number[][]} meetings + * @param {number} firstPerson + * @return {number[]} + */ + findAllPeople(n, meetings, firstPerson) { + meetings.sort((a, b) => a[2] - b[2]); + let dsu = new DSU(n); + dsu.union(0, firstPerson); + + for (let i = 0; i < meetings.length; ) { + let time = meetings[i][2]; + let group = new Set(); + + for (; i < meetings.length && meetings[i][2] === time; i++) { + let [u, v] = meetings[i]; + dsu.union(u, v); + group.add(u); + group.add(v); + } + + group.forEach(node => { + if (dsu.find(node) !== dsu.find(0)) { + dsu.reset(node); + } + }); + } + + return [...Array(n).keys()].filter(i => dsu.find(i) === dsu.find(0)); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m \log m + (m * α(n)))$ +* Space complexity: + * $O(n)$ extra space. + * $O(m)$ space depending on the sorting algorithm. + +> Where $m$ is the number of meetings and $n$ is the number of people. \ No newline at end of file diff --git a/articles/find-the-maximum-sum-of-node-values.md b/articles/find-the-maximum-sum-of-node-values.md new file mode 100644 index 000000000..d48258892 --- /dev/null +++ b/articles/find-the-maximum-sum-of-node-values.md @@ -0,0 +1,637 @@ +## 1. Depth First Search + +::tabs-start + +```python +class Solution: + def maximumValueSum(self, nums: List[int], k: int, edges: List[List[int]]) -> int: + adj = [[] for _ in range(len(nums))] + for u, v in edges: + adj[u].append(v) + adj[v].append(u) + + def dfs(node, par): + res = [nums[node], nums[node] ^ k] + for child in adj[node]: + if child == par: + continue + + cur = dfs(child, node) + tmp = [] + tmp.append(max(res[0] + cur[0], res[1] + cur[1])) + tmp.append(max(res[1] + cur[0], res[0] + cur[1])) + res = tmp + + return res + + return dfs(0, -1)[0] +``` + +```java +public class Solution { + public long maximumValueSum(int[] nums, int k, int[][] edges) { + int n = nums.length; + List[] adj = new ArrayList[n]; + for (int i = 0; i < n; i++) adj[i] = new ArrayList<>(); + for (int[] edge : edges) { + adj[edge[0]].add(edge[1]); + adj[edge[1]].add(edge[0]); + } + + return dfs(0, -1, nums, k, adj)[0]; + } + + private long[] dfs(int node, int parent, int[] nums, int k, List[] adj) { + long[] res = { nums[node], nums[node] ^ k }; + for (int child : adj[node]) { + if (child == parent) continue; + + long[] cur = dfs(child, node, nums, k, adj); + long[] tmp = new long[2]; + tmp[0] = Math.max(res[0] + cur[0], res[1] + cur[1]); + tmp[1] = Math.max(res[1] + cur[0], res[0] + cur[1]); + res = tmp; + } + return res; + } +} +``` + +```cpp +class Solution { + vector> adj; + +public: + long long maximumValueSum(vector& nums, int k, vector>& edges) { + int n = nums.size(); + adj.resize(n); + for (const auto& edge : edges) { + adj[edge[0]].push_back(edge[1]); + adj[edge[1]].push_back(edge[0]); + } + + return dfs(0, -1, nums, k)[0]; + } + +private: + vector dfs(int node, int parent, vector& nums, int k) { + vector res = { nums[node], nums[node] ^ k }; + for (int child : adj[node]) { + if (child == parent) continue; + + vector cur = dfs(child, node, nums, k); + vector tmp(2); + tmp[0] = max(res[0] + cur[0], res[1] + cur[1]); + tmp[1] = max(res[1] + cur[0], res[0] + cur[1]); + res = tmp; + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @param {number[][]} edges + * @return {number} + */ + maximumValueSum(nums, k, edges) { + const n = nums.length; + const adj = Array.from({ length: n }, () => []); + + for (const [u, v] of edges) { + adj[u].push(v); + adj[v].push(u); + } + + const dfs = (node, parent) => { + let res = [nums[node], nums[node] ^ k]; + + for (const child of adj[node]) { + if (child === parent) continue; + + const cur = dfs(child, node); + const tmp = []; + tmp[0] = Math.max(res[0] + cur[0], res[1] + cur[1]); + tmp[1] = Math.max(res[1] + cur[0], res[0] + cur[1]); + res = tmp; + } + + return res; + }; + + return dfs(0, -1)[0]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 2. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def maximumValueSum(self, nums: List[int], k: int, edges: List[List[int]]) -> int: + dp = [[None] * 2 for _ in range(len(nums))] + [[0, float("-inf")]] + + def dfs(i, xorCnt): + if dp[i][xorCnt] is not None: + return dp[i][xorCnt] + + res = nums[i] + dfs(i + 1, xorCnt) + res = max(res, (nums[i] ^ k) + dfs(i + 1, xorCnt ^ 1)) + dp[i][xorCnt] = res + return res + + return dfs(0, 0) +``` + +```java +public class Solution { + private long[][] dp; + + public long maximumValueSum(int[] nums, int k, int[][] edges) { + int n = nums.length; + dp = new long[n + 1][2]; + for (long[] row : dp) Arrays.fill(row, Long.MIN_VALUE); + dp[n][0] = 0; + dp[n][1] = Integer.MIN_VALUE; + + return dfs(0, 0, nums, k); + } + + private long dfs(int i, int xorCnt, int[] nums, int k) { + if (dp[i][xorCnt] != Long.MIN_VALUE) { + return dp[i][xorCnt]; + } + + long res = nums[i] + dfs(i + 1, xorCnt, nums, k); + res = Math.max(res, (nums[i] ^ k) + dfs(i + 1, xorCnt ^ 1, nums, k)); + + return dp[i][xorCnt] = res; + } +} +``` + +```cpp +class Solution { + vector> dp; + +public: + long long maximumValueSum(vector& nums, int k, vector>& edges) { + int n = nums.size(); + dp.assign(n + 1, vector(2, LLONG_MIN)); + dp[n][0] = 0; + dp[n][1] = INT_MIN; + + return dfs(0, 0, nums, k); + } + +private: + long long dfs(int i, int xorCnt, vector& nums, int k) { + if (dp[i][xorCnt] != LLONG_MIN) { + return dp[i][xorCnt]; + } + + long long res = nums[i] + dfs(i + 1, xorCnt, nums, k); + res = max(res, (nums[i] ^ k) + dfs(i + 1, xorCnt ^ 1, nums, k)); + return dp[i][xorCnt] = res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @param {number[][]} edges + * @return {number} + */ + maximumValueSum(nums, k, edges) { + const n = nums.length; + const dp = Array.from({ length: n + 1 }, () => [null, null]); + dp[n][0] = 0; + dp[n][1] = -Infinity; + + const dfs = (i, xorCnt) => { + if (dp[i][xorCnt] !== null) return dp[i][xorCnt]; + + let res = nums[i] + dfs(i + 1, xorCnt); + res = Math.max(res, (nums[i] ^ k) + dfs(i + 1, xorCnt ^ 1)); + return dp[i][xorCnt] = res; + }; + + return dfs(0, 0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 3. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def maximumValueSum(self, nums: List[int], k: int, edges: List[List[int]]) -> int: + n = len(nums) + dp = [[0, 0] for _ in range(n + 1)] + dp[n][1] = float("-inf") + + for i in range(n - 1, -1, -1): + dp[i][0] = max(nums[i] + dp[i + 1][0], (nums[i] ^ k) + dp[i + 1][1]) + dp[i][1] = max(nums[i] + dp[i + 1][1], (nums[i] ^ k) + dp[i + 1][0]) + + return dp[0][0] +``` + +```java +public class Solution { + public long maximumValueSum(int[] nums, int k, int[][] edges) { + int n = nums.length; + long[][] dp = new long[n + 1][2]; + dp[n][1] = Integer.MIN_VALUE; + + for (int i = n - 1; i >= 0; i--) { + dp[i][0] = Math.max(nums[i] + dp[i + 1][0], (nums[i] ^ k) + dp[i + 1][1]); + dp[i][1] = Math.max(nums[i] + dp[i + 1][1], (nums[i] ^ k) + dp[i + 1][0]); + } + + return dp[0][0]; + } +} +``` + +```cpp +class Solution { +public: + long long maximumValueSum(vector& nums, int k, vector>& edges) { + int n = nums.size(); + vector> dp(n + 1, vector(2)); + dp[n][1] = INT_MIN; + + for (int i = n - 1; i >= 0; i--) { + dp[i][0] = max(nums[i] + dp[i + 1][0], (nums[i] ^ k) + dp[i + 1][1]); + dp[i][1] = max(nums[i] + dp[i + 1][1], (nums[i] ^ k) + dp[i + 1][0]); + } + + return dp[0][0]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @param {number[][]} edges + * @return {number} + */ + maximumValueSum(nums, k, edges) { + const n = nums.length; + const dp = Array.from({ length: n + 1 }, () => [0, 0]); + dp[n][1] = -Infinity; + + for (let i = n - 1; i >= 0; i--) { + dp[i][0] = Math.max(nums[i] + dp[i + 1][0], (nums[i] ^ k) + dp[i + 1][1]); + dp[i][1] = Math.max(nums[i] + dp[i + 1][1], (nums[i] ^ k) + dp[i + 1][0]); + } + + return dp[0][0]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 4. Dynamic Programming (Space Optimized) + +::tabs-start + +```python +class Solution: + def maximumValueSum(self, nums: List[int], k: int, edges: List[List[int]]) -> int: + dp = [0, float("-inf")] + + for i in range(len(nums) - 1, -1, -1): + next_dp = [0, 0] + next_dp[0] = max(nums[i] + dp[0], (nums[i] ^ k) + dp[1]) + next_dp[1] = max(nums[i] + dp[1], (nums[i] ^ k) + dp[0]) + dp = next_dp + + return dp[0] +``` + +```java +public class Solution { + public long maximumValueSum(int[] nums, int k, int[][] edges) { + int n = nums.length; + long[] dp = {0, Long.MIN_VALUE}; + + for (int i = n - 1; i >= 0; i--) { + long[] nextDp = new long[2]; + nextDp[0] = Math.max(nums[i] + dp[0], (nums[i] ^ k) + dp[1]); + nextDp[1] = Math.max(nums[i] + dp[1], (nums[i] ^ k) + dp[0]); + dp = nextDp; + } + + return dp[0]; + } +} +``` + +```cpp +class Solution { +public: + long long maximumValueSum(vector& nums, int k, vector>& edges) { + int n = nums.size(); + vector dp = {0, LLONG_MIN}; + + for (int i = n - 1; i >= 0; i--) { + vector nextDp(2); + nextDp[0] = max(nums[i] + dp[0], (nums[i] ^ k) + dp[1]); + nextDp[1] = max(nums[i] + dp[1], (nums[i] ^ k) + dp[0]); + dp = nextDp; + } + + return dp[0]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @param {number[][]} edges + * @return {number} + */ + maximumValueSum(nums, k, edges) { + const n = nums.length; + let dp = [0, -Infinity]; + + for (let i = n - 1; i >= 0; i--) { + let nextDp = [0, 0]; + nextDp[0] = Math.max(nums[i] + dp[0], (nums[i] ^ k) + dp[1]); + nextDp[1] = Math.max(nums[i] + dp[1], (nums[i] ^ k) + dp[0]); + dp = nextDp; + } + + return dp[0]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ extra space. + +--- + +## 5. Greedy + +::tabs-start + +```python +class Solution: + def maximumValueSum(self, nums: List[int], k: int, edges: List[List[int]]) -> int: + delta = [(num ^ k) - num for num in nums] + delta.sort(reverse=True) + res = sum(nums) + + for i in range(0, len(nums), 2): + if i == len(nums) - 1: + break + path_delta = delta[i] + delta[i + 1] + if path_delta <= 0: + break + res += path_delta + + return res +``` + +```java +public class Solution { + public long maximumValueSum(int[] nums, int k, int[][] edges) { + int n = nums.length; + int[] delta = new int[n]; + long res = 0; + for (int i = 0; i < n; i++) { + res += nums[i]; + delta[i] = (nums[i] ^ k) - nums[i]; + } + + Arrays.sort(delta); + for (int i = n - 1; i > 0; i -= 2) { + int pathDelta = delta[i] + delta[i - 1]; + if (pathDelta <= 0) { + break; + } + res += pathDelta; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + long long maximumValueSum(vector& nums, int k, vector>& edges) { + int n = nums.size(); + vector delta(n); + long long res = 0; + for (int i = 0; i < n; i++) { + res += nums[i]; + delta[i] = (nums[i] ^ k) - nums[i]; + } + + sort(delta.rbegin(), delta.rend()); + + for (int i = 0; i + 1 < n; i += 2) { + int pathDelta = delta[i] + delta[i + 1]; + if (pathDelta <= 0) { + break; + } + res += pathDelta; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @param {number[][]} edges + * @return {number} + */ + maximumValueSum(nums, k, edges) { + const n = nums.length; + let res = 0; + let delta = []; + for (let i = 0; i < n; i++) { + res += nums[i]; + delta.push((nums[i] ^ k) - nums[i]); + } + + delta.sort((a, b) => b - a); + for (let i = 0; i + 1 < n; i += 2) { + let pathDelta = delta[i] + delta[i + 1]; + if (pathDelta <= 0) { + break; + } + res += pathDelta; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(n)$ + +--- + +## 6. Greedy (Optimal) + +::tabs-start + +```python +class Solution: + def maximumValueSum(self, nums: List[int], k: int, edges: List[List[int]]) -> int: + xorCnt = res = 0 + minDiff = 1 << 30 + + for num in nums: + xorNum = num ^ k + if xorNum > num: + res += xorNum + xorCnt ^= 1 + else: + res += num + minDiff = min(minDiff, abs(xorNum - num)) + + return res - xorCnt * minDiff +``` + +```java +public class Solution { + public long maximumValueSum(int[] nums, int k, int[][] edges) { + int xorCnt = 0, minDiff = 1 << 30; + long res = 0; + + for (int num : nums) { + int xorNum = num ^ k; + if (xorNum > num) { + res += xorNum; + xorCnt ^= 1; + } else { + res += num; + } + minDiff = Math.min(minDiff, Math.abs(xorNum - num)); + } + + return res - xorCnt * minDiff; + } +} +``` + +```cpp +class Solution { +public: + long long maximumValueSum(vector& nums, int k, vector>& edges) { + int xorCnt = 0, minDiff = 1 << 30; + long long res = 0; + + for (int& num : nums) { + int xorNum = num ^ k; + if (xorNum > num) { + res += xorNum; + xorCnt ^= 1; + } else { + res += num; + } + minDiff = min(minDiff, abs(xorNum - num)); + } + + return res - (xorCnt * minDiff); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @param {number[][]} edges + * @return {number} + */ + maximumValueSum(nums, k, edges) { + let xorCnt = 0, res = 0, minDiff = 1 << 30; + + for (let num of nums) { + let xorNum = num ^ k; + if (xorNum > num) { + res += xorNum; + xorCnt ^= 1; + } else { + res += num; + } + minDiff = Math.min(minDiff, Math.abs(xorNum - num)); + } + + return res - (xorCnt * minDiff); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ extra space. \ No newline at end of file diff --git a/articles/find-the-safest-path-in-a-grid.md b/articles/find-the-safest-path-in-a-grid.md new file mode 100644 index 000000000..f547fa423 --- /dev/null +++ b/articles/find-the-safest-path-in-a-grid.md @@ -0,0 +1,1054 @@ +## 1. Multi Source BFS + Dijkstra's Algorithm + +::tabs-start + +```python +class Solution: + def maximumSafenessFactor(self, grid: List[List[int]]) -> int: + N = len(grid) + + def in_bounds(r, c): + return min(r, c) >= 0 and max(r, c) < N + + def precompute(): + q = deque() + min_dist = {} + for r in range(N): + for c in range(N): + if grid[r][c]: + q.append([r, c, 0]) + min_dist[(r, c)] = 0 + while q: + r, c, dist = q.popleft() + nei = [[r+1, c], [r-1, c], [r, c+1], [r, c-1]] + for r2, c2 in nei: + if in_bounds(r2, c2) and (r2, c2) not in min_dist: + min_dist[(r2, c2)] = dist + 1 + q.append([r2, c2, dist + 1]) + return min_dist + + min_dist = precompute() + maxHeap = [(-min_dist[(0, 0)], 0, 0)] # (dist, r, c) + visit = set() + visit.add((0, 0)) + + while maxHeap: + dist, r, c = heapq.heappop(maxHeap) + dist = -dist + if (r, c) == (N-1, N-1): + return dist + nei = [[r+1, c], [r-1, c], [r, c+1], [r, c-1]] + for r2, c2 in nei: + if in_bounds(r2, c2) and (r2, c2) not in visit: + visit.add((r2, c2)) + dist2 = min(dist, min_dist[(r2, c2)]) + heapq.heappush(maxHeap, (-dist2, r2, c2)) +``` + +```java +public class Solution { + public int maximumSafenessFactor(List> grid) { + int N = grid.size(); + int[][] minDist = precompute(grid, N); + PriorityQueue maxHeap = new PriorityQueue<>((a, b) -> b[0] - a[0]); + boolean[][] visit = new boolean[N][N]; + + maxHeap.offer(new int[]{minDist[0][0], 0, 0}); + visit[0][0] = true; + + while (!maxHeap.isEmpty()) { + int[] curr = maxHeap.poll(); + int dist = curr[0], r = curr[1], c = curr[2]; + + if (r == N - 1 && c == N - 1) { + return dist; + } + + for (int[] dir : new int[][]{{1, 0}, {-1, 0}, {0, 1}, {0, -1}}) { + int r2 = r + dir[0], c2 = c + dir[1]; + if (inBounds(r2, c2, N) && !visit[r2][c2]) { + visit[r2][c2] = true; + int dist2 = Math.min(dist, minDist[r2][c2]); + maxHeap.offer(new int[]{dist2, r2, c2}); + } + } + } + return 0; + } + + private int[][] precompute(List> grid, int N) { + int[][] minDist = new int[N][N]; + for (int[] row : minDist) Arrays.fill(row, -1); + Queue q = new LinkedList<>(); + + for (int r = 0; r < N; r++) { + for (int c = 0; c < N; c++) { + if (grid.get(r).get(c) == 1) { + q.offer(new int[]{r, c, 0}); + minDist[r][c] = 0; + } + } + } + + while (!q.isEmpty()) { + int[] curr = q.poll(); + int r = curr[0], c = curr[1], dist = curr[2]; + + for (int[] dir : new int[][]{{1, 0}, {-1, 0}, {0, 1}, {0, -1}}) { + int r2 = r + dir[0], c2 = c + dir[1]; + if (inBounds(r2, c2, N) && minDist[r2][c2] == -1) { + minDist[r2][c2] = dist + 1; + q.offer(new int[]{r2, c2, dist + 1}); + } + } + } + return minDist; + } + + private boolean inBounds(int r, int c, int N) { + return r >= 0 && c >= 0 && r < N && c < N; + } +} +``` + +```cpp +class Solution { + static constexpr int directions[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; + +public: + int maximumSafenessFactor(vector>& grid) { + int N = grid.size(); + vector> minDist = precompute(grid, N); + priority_queue> maxHeap; + vector> visit(N, vector(N, false)); + + maxHeap.push({minDist[0][0], 0, 0}); + visit[0][0] = true; + + while (!maxHeap.empty()) { + vector cur = maxHeap.top(); maxHeap.pop(); + int dist = cur[0], r = cur[1], c = cur[2]; + + if (r == N - 1 && c == N - 1) { + return dist; + } + + for (const auto& dir : directions) { + int r2 = r + dir[0], c2 = c + dir[1]; + if (inBounds(r2, c2, N) && !visit[r2][c2]) { + visit[r2][c2] = true; + int dist2 = min(dist, minDist[r2][c2]); + maxHeap.push({dist2, r2, c2}); + } + } + } + return 0; + } + +private: + vector> precompute(vector>& grid, int N) { + vector> minDist(N, vector(N, -1)); + queue> q; + + for (int r = 0; r < N; r++) { + for (int c = 0; c < N; c++) { + if (grid[r][c] == 1) { + q.push({r, c, 0}); + minDist[r][c] = 0; + } + } + } + + while (!q.empty()) { + vector cur = q.front(); + q.pop(); + int r = cur[0], c = cur[1], dist = cur[2]; + + for (const auto& dir : directions) { + int r2 = r + dir[0], c2 = c + dir[1]; + if (inBounds(r2, c2, N) && minDist[r2][c2] == -1) { + minDist[r2][c2] = dist + 1; + q.push({r2, c2, dist + 1}); + } + } + } + return minDist; + } + + bool inBounds(int r, int c, int N) { + return r >= 0 && c >= 0 && r < N && c < N; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + maximumSafenessFactor(grid) { + const N = grid.length; + const directions = [[1, 0], [-1, 0], [0, 1], [0, -1]]; + + const inBounds = (r, c) => { + return r >= 0 && c >= 0 && r < N && c < N; + }; + + const precompute = () => { + const q = new Queue(); + const minDist = Array.from({ length: N }, () => Array(N).fill(-1)); + + for (let r = 0; r < N; r++) { + for (let c = 0; c < N; c++) { + if (grid[r][c] === 1) { + q.push([r, c, 0]); + minDist[r][c] = 0; + } + } + } + + while (!q.isEmpty()) { + let [r, c, dist] = q.pop(); + + for (let [dr, dc] of directions) { + let r2 = r + dr, c2 = c + dc; + if (inBounds(r2, c2) && minDist[r2][c2] === -1) { + minDist[r2][c2] = dist + 1; + q.push([r2, c2, dist + 1]); + } + } + } + return minDist; + }; + + const minDist = precompute(); + const maxHeap = new MaxPriorityQueue({ priority: x => x[0] }); + const visit = Array.from({ length: N }, () => Array(N).fill(false)); + + maxHeap.enqueue([minDist[0][0], 0, 0]); + visit[0][0] = true; + + while (!maxHeap.isEmpty()) { + let [dist, r, c] = maxHeap.dequeue().element; + + if (r === N - 1 && c === N - 1) { + return dist; + } + + for (let [dr, dc] of directions) { + let r2 = r + dr, c2 = c + dc; + if (inBounds(r2, c2) && !visit[r2][c2]) { + visit[r2][c2] = true; + let dist2 = Math.min(dist, minDist[r2][c2]); + maxHeap.enqueue([dist2, r2, c2]); + } + } + } + return 0; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2 \log n)$ +* Space complexity: $O(n ^ 2)$ + +--- + +## 2. Multi Source BFS + Dijkstra's Algorithm (Overwriting the Input) + +::tabs-start + +```python +class Solution: + def maximumSafenessFactor(self, grid): + N = len(grid) + minDist = grid + directions = [0, 1, 0, -1, 0] + + q = deque() + for r in range(N): + for c in range(N): + if grid[r][c] == 1: + q.append(r * N + c) + minDist[r][c] = 0 + else: + minDist[r][c] = -1 + + while q: + node = q.popleft() + r, c = divmod(node, N) + for i in range(4): + r2, c2 = r + directions[i], c + directions[i + 1] + if 0 <= r2 < N and 0 <= c2 < N and minDist[r2][c2] == -1: + minDist[r2][c2] = minDist[r][c] + 1 + q.append(r2 * N + c2) + + maxHeap = [(-minDist[0][0], 0)] + safeFactor = [0] * (N * N) + safeFactor[0] = minDist[0][0] + + while maxHeap: + dist, node = heapq.heappop(maxHeap) + dist = -dist + r, c = divmod(node, N) + if r == N - 1 and c == N - 1: + return dist + if safeFactor[node] > dist: + continue + + for i in range(4): + r2, c2 = r + directions[i], c + directions[i + 1] + node2 = r2 * N + c2 + if 0 <= r2 < N and 0 <= c2 < N: + dist2 = min(dist, minDist[r2][c2]) + if dist2 > safeFactor[node2]: + safeFactor[node2] = dist2 + heapq.heappush(maxHeap, (-dist2, node2)) + + return 0 +``` + +```java +public class Solution { + public int maximumSafenessFactor(List> grid) { + int N = grid.size(); + int[][] minDist = new int[N][N]; + int[] directions = {0, 1, 0, -1, 0}; + + Queue q = new LinkedList<>(); + for (int r = 0; r < N; r++) { + for (int c = 0; c < N; c++) { + if (grid.get(r).get(c) == 1) { + q.offer(r * N + c); + minDist[r][c] = 0; + } else { + minDist[r][c] = -1; + } + } + } + + while (!q.isEmpty()) { + int node = q.poll(); + int r = node / N, c = node % N; + for (int i = 0; i < 4; i++) { + int r2 = r + directions[i], c2 = c + directions[i + 1]; + if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N && minDist[r2][c2] == -1) { + minDist[r2][c2] = minDist[r][c] + 1; + q.offer(r2 * N + c2); + } + } + } + + PriorityQueue maxHeap = new PriorityQueue<>((a, b) -> Integer.compare(b[0], a[0])); + int[] safeFactor = new int[N * N]; + Arrays.fill(safeFactor, -1); + safeFactor[0] = minDist[0][0]; + maxHeap.offer(new int[]{safeFactor[0], 0}); + + while (!maxHeap.isEmpty()) { + int[] top = maxHeap.poll(); + int dist = top[0], node = top[1]; + int r = node / N, c = node % N; + if (r == N - 1 && c == N - 1) { + return dist; + } + if (safeFactor[node] > dist) { + continue; + } + + for (int i = 0; i < 4; i++) { + int r2 = r + directions[i], c2 = c + directions[i + 1]; + int node2 = r2 * N + c2; + if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N) { + int dist2 = Math.min(dist, minDist[r2][c2]); + if (dist2 > safeFactor[node2]) { + safeFactor[node2] = dist2; + maxHeap.offer(new int[]{dist2, node2}); + } + } + } + } + return 0; + } +} +``` + +```cpp +class Solution { +public: + int maximumSafenessFactor(vector>& grid) { + int N = grid.size(); + vector directions = {0, 1, 0, -1, 0}; + vector>& minDist = grid; + + queue q; + for (int r = 0; r < N; r++) { + for (int c = 0; c < N; c++) { + if (grid[r][c] == 1) { + q.push(r * N + c); + minDist[r][c] = 0; + } else { + minDist[r][c] = -1; + } + } + } + + while (!q.empty()) { + int node = q.front(); q.pop(); + int r = node / N, c = node % N; + for (int i = 0; i < 4; i++) { + int r2 = r + directions[i], c2 = c + directions[i + 1]; + if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N && minDist[r2][c2] == -1) { + minDist[r2][c2] = minDist[r][c] + 1; + q.push(r2 * N + c2); + } + } + } + + priority_queue> maxHeap; + vector safeFactor(N * N, 0); + safeFactor[0] = minDist[0][0]; + maxHeap.push({safeFactor[0], 0}); + + while (!maxHeap.empty()) { + auto [dist, node] = maxHeap.top(); maxHeap.pop(); + int r = node / N, c = node % N; + if (r == N - 1 && c == N - 1) { + return dist; + } + if (safeFactor[node] > dist) { + continue; + } + + for (int i = 0; i < 4; i++) { + int r2 = r + directions[i], c2 = c + directions[i + 1], node2 = r2 * N + c2; + if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N) { + int dist2 = min(dist, minDist[r2][c2]); + if (dist2 > safeFactor[node2]) { + safeFactor[node2] = dist2; + maxHeap.push({dist2, node2}); + } + } + } + } + return 0; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + maximumSafenessFactor(grid) { + const N = grid.length; + const directions = [0, 1, 0, -1, 0]; + const minDist = grid; + + const q = new Queue(); + for (let r = 0; r < N; r++) { + for (let c = 0; c < N; c++) { + if (grid[r][c] === 1) { + q.push(r * N + c); + minDist[r][c] = 0; + } else { + minDist[r][c] = -1; + } + } + } + + while (!q.isEmpty()) { + let node = q.pop(); + let r = Math.floor(node / N), c = node % N; + for (let i = 0; i < 4; i++) { + let r2 = r + directions[i], c2 = c + directions[i + 1]; + if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N && minDist[r2][c2] === -1) { + minDist[r2][c2] = minDist[r][c] + 1; + q.push(r2 * N + c2); + } + } + } + + let maxHeap = new MaxPriorityQueue({ priority: x => x[0] }); + let safeFactor = new Array(N * N).fill(0); + safeFactor[0] = minDist[0][0]; + maxHeap.enqueue([safeFactor[0], 0]); + + while (!maxHeap.isEmpty()) { + let [dist, node] = maxHeap.dequeue().element; + let r = Math.floor(node / N), c = node % N; + if (r === N - 1 && c === N - 1) { + return dist; + } + if (safeFactor[node] > dist) { + continue; + } + + for (let i = 0; i < 4; i++) { + let r2 = r + directions[i], c2 = c + directions[i + 1], node2 = r2 * N + c2; + if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N) { + let dist2 = Math.min(dist, minDist[r2][c2]); + if (dist2 > safeFactor[node2]) { + safeFactor[node2] = dist2; + maxHeap.enqueue([dist2, node2]); + } + } + } + } + return 0; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2 \log n)$ +* Space complexity: $O(n ^ 2)$ + +--- + +## 3. Multi Source BFS + Binary Search + +::tabs-start + +```python +class Solution: + def maximumSafenessFactor(self, grid): + N = len(grid) + minDist = grid + directions = [0, 1, 0, -1, 0] + + q = deque() + for r in range(N): + for c in range(N): + if grid[r][c] == 1: + q.append(r * N + c) + minDist[r][c] = 0 + else: + minDist[r][c] = -1 + + while q: + node = q.popleft() + r, c = divmod(node, N) + for i in range(4): + r2, c2 = r + directions[i], c + directions[i + 1] + if 0 <= r2 < N and 0 <= c2 < N and minDist[r2][c2] == -1: + minDist[r2][c2] = minDist[r][c] + 1 + q.append(r2 * N + c2) + + def canReach(threshold): + q = deque([0]) + visited = [False] * (N * N) + visited[0] = True + + while q: + node = q.popleft() + r, c = divmod(node, N) + if r == N - 1 and c == N - 1: + return True + + for i in range(4): + r2, c2 = r + directions[i], c + directions[i + 1] + node2 = r2 * N + c2 + if (0 <= r2 < N and 0 <= c2 < N and not visited[node2] and + minDist[r2][c2] >= threshold + ): + visited[node2] = True + q.append(node2) + + return False + + l, r = 0, min(minDist[0][0], minDist[N - 1][N - 1]) + while l <= r: + mid = (l + r) // 2 + if canReach(mid): + l = mid + 1 + else: + r = mid - 1 + + return l - 1 +``` + +```java +public class Solution { + private static int[] directions = {0, 1, 0, -1, 0}; + + public int maximumSafenessFactor(List> grid) { + int N = grid.size(); + int[][] minDist = new int[N][N]; + + Queue q = new LinkedList<>(); + for (int r = 0; r < N; r++) { + for (int c = 0; c < N; c++) { + if (grid.get(r).get(c) == 1) { + q.offer(r * N + c); + minDist[r][c] = 0; + } else { + minDist[r][c] = -1; + } + } + } + + while (!q.isEmpty()) { + int node = q.poll(); + int r = node / N, c = node % N; + for (int i = 0; i < 4; i++) { + int r2 = r + directions[i], c2 = c + directions[i + 1]; + if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N && minDist[r2][c2] == -1) { + minDist[r2][c2] = minDist[r][c] + 1; + q.offer(r2 * N + c2); + } + } + } + + int l = 0, r = Math.min(minDist[0][0], minDist[N - 1][N - 1]); + while (l <= r) { + int mid = (l + r) / 2; + if (canReach(minDist, N, mid)) { + l = mid + 1; + } else { + r = mid - 1; + } + } + return l - 1; + } + + private boolean canReach(int[][] minDist, int N, int threshold) { + Queue q = new LinkedList<>(); + boolean[] visited = new boolean[N * N]; + q.offer(0); + visited[0] = true; + + while (!q.isEmpty()) { + int node = q.poll(); + int r = node / N, c = node % N; + if (r == N - 1 && c == N - 1) { + return true; + } + + for (int i = 0; i < 4; i++) { + int r2 = r + directions[i], c2 = c + directions[i + 1]; + int node2 = r2 * N + c2; + if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N && !visited[node2] && + minDist[r2][c2] >= threshold) { + visited[node2] = true; + q.offer(node2); + } + } + } + return false; + } +} +``` + +```cpp +class Solution { + static constexpr int directions[5] = {0, 1, 0, -1, 0}; + +public: + int maximumSafenessFactor(vector>& grid) { + int N = grid.size(); + vector>& minDist = grid; + + queue q; + for (int r = 0; r < N; r++) { + for (int c = 0; c < N; c++) { + if (grid[r][c] == 1) { + q.push(r * N + c); + minDist[r][c] = 0; + } else { + minDist[r][c] = -1; + } + } + } + + while (!q.empty()) { + int node = q.front(); q.pop(); + int r = node / N, c = node % N; + for (int i = 0; i < 4; i++) { + int r2 = r + directions[i], c2 = c + directions[i + 1]; + if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N && minDist[r2][c2] == -1) { + minDist[r2][c2] = minDist[r][c] + 1; + q.push(r2 * N + c2); + } + } + } + + int l = 0, r = min(minDist[0][0], minDist[N - 1][N - 1]); + while (l <= r) { + int mid = (l + r) / 2; + if (canReach(minDist, N, mid)) { + l = mid + 1; + } else { + r = mid - 1; + } + } + return l - 1; + } + +private: + bool canReach(vector>& minDist, int N, int threshold) { + queue q; + vector visited(N * N, false); + q.push(0); + visited[0] = true; + + while (!q.empty()) { + int node = q.front(); q.pop(); + int r = node / N, c = node % N; + if (r == N - 1 && c == N - 1) { + return true; + } + + for (int i = 0; i < 4; i++) { + int r2 = r + directions[i], c2 = c + directions[i + 1], node2 = r2 * N + c2; + if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N && !visited[node2] && + minDist[r2][c2] >= threshold) { + visited[node2] = true; + q.push(node2); + } + } + } + return false; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + maximumSafenessFactor(grid) { + const N = grid.length; + const minDist = grid; + const directions = [0, 1, 0, -1, 0]; + + let q = new Queue(); + for (let r = 0; r < N; r++) { + for (let c = 0; c < N; c++) { + if (grid[r][c] === 1) { + q.push(r * N + c); + minDist[r][c] = 0; + } else { + minDist[r][c] = -1; + } + } + } + + while (!q.isEmpty()) { + let node = q.pop(); + let r = Math.floor(node / N), c = node % N; + for (let i = 0; i < 4; i++) { + let r2 = r + directions[i], c2 = c + directions[i + 1]; + if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N && minDist[r2][c2] === -1) { + minDist[r2][c2] = minDist[r][c] + 1; + q.push(r2 * N + c2); + } + } + } + + const canReach = (threshold) => { + q = new Queue([0]); + let visited = new Array(N * N).fill(false); + visited[0] = true; + + while (!q.isEmpty()) { + let node = q.pop(); + let r = Math.floor(node / N), c = node % N; + if (r === N - 1 && c === N - 1) return true; + + for (let i = 0; i < 4; i++) { + let r2 = r + directions[i], c2 = c + directions[i + 1], node2 = r2 * N + c2; + if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N && !visited[node2] && + minDist[r2][c2] >= threshold) { + visited[node2] = true; + q.push(node2); + } + } + } + return false; + }; + + let l = 0, r = Math.min(minDist[0][0], minDist[N - 1][N - 1]); + while (l <= r) { + let mid = Math.floor((l + r) / 2); + if (canReach(mid)) { + l = mid + 1; + } else { + r = mid - 1; + } + } + return l - 1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2 \log n)$ +* Space complexity: $O(n ^ 2)$ + +--- + +## 4. Breadth First Search (0-1 BFS) + +::tabs-start + +```python +class Solution: + def maximumSafenessFactor(self, grid): + N = len(grid) + minDist = grid + directions = [0, 1, 0, -1, 0] + + q = deque() + for r in range(N): + for c in range(N): + if grid[r][c] == 1: + q.append(r * N + c) + minDist[r][c] = 0 + else: + minDist[r][c] = -1 + + while q: + node = q.popleft() + r, c = divmod(node, N) + for i in range(4): + r2, c2 = r + directions[i], c + directions[i + 1] + if 0 <= r2 < N and 0 <= c2 < N and minDist[r2][c2] == -1: + minDist[r2][c2] = minDist[r][c] + 1 + q.append(r2 * N + c2) + + safeFactor = [-1] * (N * N) + res = safeFactor[0] = min(minDist[N - 1][N - 1], minDist[0][0]) + q.append(0) + + while q: + node = q.popleft() + r, c = divmod(node, N) + res = min(res, safeFactor[node]) + if r == N - 1 and c == N - 1: + break + + for i in range(4): + r2, c2 = r + directions[i], c + directions[i + 1] + node2 = r2 * N + c2 + if 0 <= r2 < N and 0 <= c2 < N and safeFactor[node2] == -1: + safeFactor[node2] = min(safeFactor[node], minDist[r2][c2]) + if safeFactor[node2] < res: + q.append(node2) + else: + q.appendleft(node2) + + return res +``` + +```java +public class Solution { + private static final int[] directions = {0, 1, 0, -1, 0}; + + public int maximumSafenessFactor(List> grid) { + int N = grid.size(); + int[][] minDist = new int[N][N]; + + Deque q = new ArrayDeque<>(); + for (int r = 0; r < N; r++) { + for (int c = 0; c < N; c++) { + if (grid.get(r).get(c) == 1) { + q.offerLast(r * N + c); + minDist[r][c] = 0; + } else { + minDist[r][c] = -1; + } + } + } + + while (!q.isEmpty()) { + int node = q.pollFirst(); + int r = node / N, c = node % N; + for (int i = 0; i < 4; i++) { + int r2 = r + directions[i], c2 = c + directions[i + 1]; + if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N && minDist[r2][c2] == -1) { + minDist[r2][c2] = minDist[r][c] + 1; + q.offerLast(r2 * N + c2); + } + } + } + + int[] safeFactor = new int[N * N]; + Arrays.fill(safeFactor, -1); + int res = safeFactor[0] = Math.min(minDist[N - 1][N - 1], minDist[0][0]); + q.offerLast(0); + + while (!q.isEmpty()) { + int node = q.pollFirst(); + int r = node / N, c = node % N; + res = Math.min(res, safeFactor[node]); + if (r == N - 1 && c == N - 1) { + break; + } + + for (int i = 0; i < 4; i++) { + int r2 = r + directions[i], c2 = c + directions[i + 1], node2 = r2 * N + c2; + if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N && safeFactor[node2] == -1) { + safeFactor[node2] = Math.min(safeFactor[node], minDist[r2][c2]); + if (safeFactor[node2] < res) { + q.offerLast(node2); + } else { + q.offerFirst(node2); + } + } + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int maximumSafenessFactor(vector>& grid) { + int N = grid.size(); + vector>& minDist = grid; + constexpr int directions[5] = {0, 1, 0, -1, 0}; + + deque q; + for (int r = 0; r < N; r++) { + for (int c = 0; c < N; c++) { + if (grid[r][c] == 1) { + q.push_back(r * N + c); + minDist[r][c] = 0; + } else { + minDist[r][c] = -1; + } + } + } + + while (!q.empty()) { + int node = q.front(); q.pop_front(); + int r = node / N, c = node % N; + for (int i = 0; i < 4; i++) { + int r2 = r + directions[i], c2 = c + directions[i + 1]; + if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N && minDist[r2][c2] == -1) { + minDist[r2][c2] = minDist[r][c] + 1; + q.push_back(r2 * N + c2); + } + } + } + + vector safeFactor(N * N, -1); + int res = safeFactor[0] = min(minDist[N - 1][N - 1], minDist[0][0]); + q.push_back(0); + + while (!q.empty()) { + int node = q.front(); q.pop_front(); + int r = node / N, c = node % N; + res = min(res, safeFactor[node]); + if (r == N - 1 && c == N - 1) { + break; + } + + for (int i = 0; i < 4; i++) { + int r2 = r + directions[i], c2 = c + directions[i + 1], node2 = r2 * N + c2; + if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N && safeFactor[node2] == -1) { + safeFactor[node2] = min(safeFactor[node], minDist[r2][c2]); + if (safeFactor[node2] < res) { + q.push_back(node2); + } else { + q.push_front(node2); + } + } + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + maximumSafenessFactor(grid) { + const N = grid.length; + const minDist = grid; + const directions = [0, 1, 0, -1, 0]; + + const q = new Deque(); + for (let r = 0; r < N; r++) { + for (let c = 0; c < N; c++) { + if (grid[r][c] === 1) { + q.pushBack(r * N + c); + minDist[r][c] = 0; + } else { + minDist[r][c] = -1; + } + } + } + + while (!q.isEmpty()) { + let node = q.popFront(); + let r = Math.floor(node / N), c = node % N; + for (let i = 0; i < 4; i++) { + let r2 = r + directions[i], c2 = c + directions[i + 1]; + if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N && minDist[r2][c2] === -1) { + minDist[r2][c2] = minDist[r][c] + 1; + q.pushBack(r2 * N + c2); + } + } + } + + let safeFactor = new Array(N * N).fill(-1); + let res = safeFactor[0] = Math.min(minDist[N - 1][N - 1], minDist[0][0]); + q.pushBack(0); + + while (!q.isEmpty()) { + let node = q.popFront(); + let r = Math.floor(node / N), c = node % N; + res = Math.min(res, safeFactor[node]); + if (r === N - 1 && c === N - 1) { + break; + } + + for (let i = 0; i < 4; i++) { + let r2 = r + directions[i], c2 = c + directions[i + 1], node2 = r2 * N + c2; + if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N && safeFactor[node2] === -1) { + safeFactor[node2] = Math.min(safeFactor[node], minDist[r2][c2]); + if (safeFactor[node2] < res) { + q.pushBack(node2); + } else { + q.pushFront(node2); + } + } + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n ^ 2)$ \ No newline at end of file diff --git a/articles/find-unique-binary-string.md b/articles/find-unique-binary-string.md new file mode 100644 index 000000000..ea24db9f9 --- /dev/null +++ b/articles/find-unique-binary-string.md @@ -0,0 +1,685 @@ +## 1. Backtracking (Recursion) + +::tabs-start + +```python +class Solution: + def findDifferentBinaryString(self, nums: List[str]) -> str: + strSet = {s for s in nums} + + def backtrack(i, cur): + if i == len(nums): + res = "".join(cur) + return None if res in strSet else res + + res = backtrack(i + 1, cur) + if res: return res + + cur[i] = "1" + return backtrack(i + 1, cur) + + return backtrack(0, ["0" for _ in nums]) +``` + +```java +public class Solution { + public String findDifferentBinaryString(String[] nums) { + Set strSet = new HashSet<>(); + for (String s : nums) { + strSet.add(s); + } + return backtrack(0, new char[nums.length], strSet, nums.length); + } + + private String backtrack(int i, char[] cur, Set strSet, int n) { + if (i == n) { + String res = new String(cur); + return strSet.contains(res) ? null : res; + } + + cur[i] = '0'; + String res = backtrack(i + 1, cur, strSet, n); + if (res != null) return res; + + cur[i] = '1'; + return backtrack(i + 1, cur, strSet, n); + } +} +``` + +```cpp +class Solution { +public: + string findDifferentBinaryString(vector& nums) { + unordered_set strSet(nums.begin(), nums.end()); + string cur(nums.size(), '0'); + return backtrack(0, cur, strSet, nums.size()); + } + +private: + string backtrack(int i, string& cur, unordered_set& strSet, int n) { + if (i == n) { + return strSet.count(cur) ? "" : cur; + } + + string res = backtrack(i + 1, cur, strSet, n); + if (!res.empty()) return res; + + cur[i] = '1'; + return backtrack(i + 1, cur, strSet, n); + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} nums + * @return {string} + */ + findDifferentBinaryString(nums) { + const strSet = new Set(nums); + const n = nums.length; + + const backtrack = (i, cur) => { + if (i === n) { + const res = cur.join(""); + return strSet.has(res) ? null : res; + } + + let res = backtrack(i + 1, cur); + if (res) return res; + + cur[i] = "1"; + return backtrack(i + 1, cur); + }; + + return backtrack(0, Array(n).fill("0")); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n)$ + +--- + +## 2. Backtracking (Iteration) + +::tabs-start + +```python +class Solution: + def findDifferentBinaryString(self, nums: List[str]) -> str: + strSet = set(nums) + n = len(nums) + + for num in range(1 << n): + res = bin(num)[2:].zfill(n) + if res not in strSet: + return res + + return "" +``` + +```java +public class Solution { + public String findDifferentBinaryString(String[] nums) { + Set strSet = new HashSet<>(); + for (String s : nums) { + strSet.add(s); + } + int n = nums.length; + + for (int num = 0; num < (n + 1); num++) { + String res = String.format("%" + n + "s", + Integer.toBinaryString(num)).replace(' ', '0'); + if (!strSet.contains(res)) { + return res; + } + } + + return ""; + } +} +``` + +```cpp +class Solution { +public: + string findDifferentBinaryString(vector& nums) { + unordered_set strSet(nums.begin(), nums.end()); + int n = nums.size(); + + for (int num = 0; num < (n + 1); num++) { + string res = toBinaryString(num, n); + if (strSet.find(res) == strSet.end()) { + return res; + } + } + + return ""; + } + +private: + string toBinaryString(int num, int length) { + string res = ""; + for (int i = length - 1; i >= 0; i--) { + res += (num & (1 << i)) ? '1' : '0'; + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} nums + * @return {string} + */ + findDifferentBinaryString(nums) { + const strSet = new Set(nums); + const n = nums.length; + + for (let num = 0; num < (n + 1); num++) { + let res = num.toString(2).padStart(n, '0'); + if (!strSet.has(res)) { + return res; + } + } + + return ""; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n)$ + +--- + +## 3. Cantor's Diagonal Argument + +::tabs-start + +```python +class Solution: + def findDifferentBinaryString(self, nums: List[str]) -> str: + res = [] + for i in range(len(nums)): + if nums[i][i] == '0': + res.append('1') + else: + res.append('0') + return "".join(res) +``` + +```java +public class Solution { + public String findDifferentBinaryString(String[] nums) { + StringBuilder res = new StringBuilder(); + for (int i = 0; i < nums.length; i++) { + res.append(nums[i].charAt(i) == '0' ? '1' : '0'); + } + return res.toString(); + } +} +``` + +```cpp +class Solution { +public: + string findDifferentBinaryString(vector& nums) { + string res; + for (int i = 0; i < nums.size(); i++) { + res += (nums[i][i] == '0') ? '1' : '0'; + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} nums + * @return {string} + */ + findDifferentBinaryString(nums) { + let res = []; + for (let i = 0; i < nums.length; i++) { + res.push(nums[i][i] === '0' ? '1' : '0'); + } + return res.join(""); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: + * $O(1)$ extra space. + * $O(n)$ space for the output string. + +--- + +## 4. Randomization + +::tabs-start + +```python +class Solution: + def findDifferentBinaryString(self, nums: List[str]) -> str: + strSet = set(nums) + n = len(nums) + + while True: + res = "".join(random.choice("01") for _ in range(n)) + if res not in strSet: + return res +``` + +```java +public class Solution { + public String findDifferentBinaryString(String[] nums) { + Set strSet = new HashSet<>(); + for (String s : nums) { + strSet.add(s); + } + int n = nums.length; + Random random = new Random(); + + while (true) { + StringBuilder res = new StringBuilder(); + for (int i = 0; i < n; i++) { + res.append(random.nextBoolean() ? '1' : '0'); + } + String result = res.toString(); + if (!strSet.contains(result)) { + return result; + } + } + } +} +``` + +```cpp +class Solution { +public: + string findDifferentBinaryString(vector& nums) { + unordered_set strSet(nums.begin(), nums.end()); + int n = nums.size(); + + while (true) { + string res = ""; + for (int i = 0; i < n; i++) { + res += (rand() % 2) ? '1' : '0'; + } + if (strSet.find(res) == strSet.end()) { + return res; + } + } + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} nums + * @return {string} + */ + findDifferentBinaryString(nums) { + const strSet = new Set(nums); + const n = nums.length; + + while (true) { + let res = Array.from({ length: n }, () => + Math.random() < 0.5 ? '0' : '1').join(""); + if (!strSet.has(res)) { + return res; + } + } + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(∞)$ in worst case. +* Space complexity: $O(n)$ + +--- + +## 5. Trie + +::tabs-start + +```python +class Node: + def __init__(self): + self.children = [None, None] + + def contains_bit(self, bit: int) -> bool: + return self.children[bit] is not None + + def put(self, bit: int): + self.children[bit] = Node() + + def get(self, bit: int): + return self.children[bit] + +class Trie: + def __init__(self): + self.root = Node() + + def insert(self, s: str): + curr = self.root + for c in s: + bit = int(c) + if not curr.contains_bit(bit): + curr.put(bit) + curr = curr.get(bit) + + def search(self, res: str, curr) -> bool: + while curr.contains_bit(0) or curr.contains_bit(1): + if not curr.contains_bit(0): + res.append('0') + return True + if not curr.contains_bit(1): + res.append('1') + return True + + res.append('1') + curr = curr.get(1) + + return False + +class Solution: + def findDifferentBinaryString(self, nums: List[str]) -> str: + trie = Trie() + for s in nums: + trie.insert(s) + + res = [] + trie.search(res, trie.root) + + while len(res) < len(nums): + res.append('1') + + return ''.join(res) +``` + +```java +class Node { + Node[] children; + + Node() { + this.children = new Node[2]; + } + + boolean containsBit(int bit) { + return this.children[bit] != null; + } + + void put(int bit) { + this.children[bit] = new Node(); + } + + Node get(int bit) { + return this.children[bit]; + } +} + +class Trie { + Node root; + + Trie() { + this.root = new Node(); + } + + void insert(String s) { + Node curr = root; + for (char c : s.toCharArray()) { + int bit = c - '0'; + if (!curr.containsBit(bit)) { + curr.put(bit); + } + curr = curr.get(bit); + } + } + + boolean search(StringBuilder res, Node curr) { + while (curr.containsBit(0) || curr.containsBit(1)) { + if (!curr.containsBit(0)) { + res.append('0'); + return true; + } + if (!curr.containsBit(1)) { + res.append('1'); + return true; + } + + res.append('1'); + curr = curr.get(1); + } + + return false; + } +} + +public class Solution { + public String findDifferentBinaryString(String[] nums) { + Trie trie = new Trie(); + for (String s : nums) { + trie.insert(s); + } + + StringBuilder res = new StringBuilder(); + trie.search(res, trie.root); + + while (res.length() < nums.length) { + res.append('1'); + } + + return res.toString(); + } +} +``` + +```cpp +class Node { +public: + Node *children[2]; + + Node() { + this->children[0] = nullptr; + this->children[1] = nullptr; + } + + bool containsBit(int bit) { + return this->children[bit] != nullptr; + } + + void put(int bit) { + this->children[bit] = new Node(); + } + + Node* get(int bit) { + return this->children[bit]; + } +}; + +class Trie { +public: + Node* root; + + Trie() { + this->root = new Node(); + } + + void insert(const string& s) { + Node* curr = root; + for (char c : s) { + int bit = c - '0'; + if (!curr->containsBit(bit)) { + curr->put(bit); + } + curr = curr->get(bit); + } + } + + bool search(string& res, Node* curr) { + while (curr->containsBit(0) || curr->containsBit(1)) { + if (!curr->containsBit(0)) { + res += '0'; + return true; + } + if (!curr->containsBit(1)) { + res += '1'; + return true; + } + + res += '1'; + curr = curr->get(1); + } + + return false; + } +}; + +class Solution { +public: + string findDifferentBinaryString(vector& nums) { + Trie trie; + for (const string& s : nums) { + trie.insert(s); + } + + string res; + trie.search(res, trie.root); + + while (res.length() < nums.size()) { + res += '1'; + } + + return res; + } +}; +``` + +```javascript +class Node { + constructor() { + this.children = [null, null]; + } + + /** + * @param {number} bit + * @return {boolean} + */ + containsBit(bit) { + return this.children[bit] !== null; + } + + /** + * @param {number} bit + */ + put(bit) { + this.children[bit] = new Node(); + } + + /** + * @param {number} bit + * @return {Node} + */ + get(bit) { + return this.children[bit]; + } +} + +class Trie { + constructor() { + this.root = new Node(); + } + + /** + * @param {string} s + */ + insert(s) { + let curr = this.root; + for (const c of s) { + let bit = c === '1' ? 1 : 0; + if (!curr.containsBit(bit)) { + curr.put(bit); + } + curr = curr.get(bit); + } + } + + /** + * @param {string[]} res + * @param {Node} curr + * @return {boolean} + */ + search(res, curr) { + while (curr.containsBit(0) || curr.containsBit(1)) { + if (!curr.containsBit(0)) { + res.push('0'); + return true; + } + if (!curr.containsBit(1)) { + res.push('1'); + return true; + } + + res.push('1'); + curr = curr.get(1); + } + return false; + } +} + +class Solution { + /** + * @param {string[]} nums + * @return {string} + */ + findDifferentBinaryString(nums) { + let trie = new Trie(); + for (const s of nums) { + trie.insert(s); + } + + let res = []; + trie.search(res, trie.root); + + while (res.length < nums.length) { + res.push('1'); + } + + return res.join(""); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n ^ 2)$ \ No newline at end of file diff --git a/articles/furthest-building-you-can-reach.md b/articles/furthest-building-you-can-reach.md new file mode 100644 index 000000000..24ca0ef3b --- /dev/null +++ b/articles/furthest-building-you-can-reach.md @@ -0,0 +1,723 @@ +## 1. Brute Force (Greedy) + +::tabs-start + +```python +class Solution: + def furthestBuilding(self, heights: List[int], bricks: int, ladders: int) -> int: + n = len(heights) + + for i in range(1, n): + if ladders >= i: + continue + + diffs = [] + for j in range(i): + if heights[j + 1] > heights[j]: + diffs.append(heights[j + 1] - heights[j]) + + diffs.sort() + brickSum = 0 + for j in range(len(diffs) - ladders): + brickSum += diffs[j] + + if brickSum > bricks: + return i - 1 + + return n - 1 +``` + +```java +public class Solution { + public int furthestBuilding(int[] heights, int bricks, int ladders) { + int n = heights.length; + + for (int i = 1; i < n; i++) { + if (ladders >= i) { + continue; + } + + List diffs = new ArrayList<>(); + for (int j = 0; j < i; j++) { + if (heights[j + 1] > heights[j]) { + diffs.add(heights[j + 1] - heights[j]); + } + } + + Collections.sort(diffs); + long brickSum = 0; + for (int j = 0; j < diffs.size() - ladders; j++) { + brickSum += diffs.get(j); + } + + if (brickSum > bricks) { + return i - 1; + } + } + + return n - 1; + } +} +``` + +```cpp +class Solution { +public: + int furthestBuilding(vector& heights, int bricks, int ladders) { + int n = heights.size(); + + for (int i = 1; i < n; i++) { + if (ladders >= i) { + continue; + } + + vector diffs; + for (int j = 0; j < i; j++) { + if (heights[j + 1] > heights[j]) { + diffs.push_back(heights[j + 1] - heights[j]); + } + } + + sort(diffs.begin(), diffs.end()); + long long brickSum = 0; + for (int j = 0; j < int(diffs.size()) - ladders; j++) { + brickSum += diffs[j]; + } + + if (brickSum > bricks) { + return i - 1; + } + } + + return n - 1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} heights + * @param {number} bricks + * @param {number} ladders + * @return {number} + */ + furthestBuilding(heights, bricks, ladders) { + let n = heights.length; + + for (let i = 1; i < n; i++) { + if (ladders >= i) { + continue; + } + + let diffs = []; + for (let j = 0; j < i; j++) { + if (heights[j + 1] > heights[j]) { + diffs.push(heights[j + 1] - heights[j]); + } + } + + diffs.sort((a, b) => a - b); + let brickSum = 0; + for (let j = 0; j < diffs.length - ladders; j++) { + brickSum += diffs[j]; + } + + if (brickSum > bricks) { + return i - 1; + } + } + + return n - 1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2 \log n)$ +* Space complexity: $O(n)$ + +--- + +## 2. Binary Search On Buildings + +::tabs-start + +```python +class Solution: + def furthestBuilding(self, heights: List[int], bricks: int, ladders: int) -> int: + def canReach(mid): + diffs = [] + for i in range(mid): + if heights[i + 1] > heights[i]: + diffs.append(heights[i + 1] - heights[i]) + + diffs.sort() + brickSum = 0 + for j in range(len(diffs) - ladders): + brickSum += diffs[j] + if brickSum > bricks: + return False + + return True + + l, r = ladders - 1, len(heights) - 1 + while l <= r: + mid = (l + r) // 2 + if canReach(mid): + l = mid + 1 + else: + r = mid - 1 + + return l - 1 +``` + +```java +public class Solution { + public int furthestBuilding(int[] heights, int bricks, int ladders) { + int l = ladders - 1, r = heights.length - 1; + + while (l <= r) { + int mid = (l + r) / 2; + if (canReach(heights, mid, bricks, ladders)) { + l = mid + 1; + } else { + r = mid - 1; + } + } + + return l - 1; + } + + private boolean canReach(int[] heights, int mid, int bricks, int ladders) { + List diffs = new ArrayList<>(); + + for (int i = 0; i < mid; i++) { + if (heights[i + 1] > heights[i]) { + diffs.add(heights[i + 1] - heights[i]); + } + } + + Collections.sort(diffs); + int brickSum = 0; + + for (int j = 0; j < diffs.size() - ladders; j++) { + brickSum += diffs.get(j); + if (brickSum > bricks) { + return false; + } + } + + return true; + } +} +``` + +```cpp +class Solution { +public: + int furthestBuilding(vector& heights, int bricks, int ladders) { + int l = ladders - 1, r = heights.size() - 1; + + while (l <= r) { + int mid = (l + r) / 2; + if (canReach(heights, mid, bricks, ladders)) { + l = mid + 1; + } else { + r = mid - 1; + } + } + + return l - 1; + } + +private: + bool canReach(vector& heights, int mid, int bricks, int ladders) { + vector diffs; + + for (int i = 0; i < mid; i++) { + if (heights[i + 1] > heights[i]) { + diffs.push_back(heights[i + 1] - heights[i]); + } + } + + sort(diffs.begin(), diffs.end()); + long long brickSum = 0; + + for (int j = 0; j < int(diffs.size()) - ladders; j++) { + brickSum += diffs[j]; + if (brickSum > bricks) { + return false; + } + } + + return true; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} heights + * @param {number} bricks + * @param {number} ladders + * @return {number} + */ + furthestBuilding(heights, bricks, ladders) { + let l = ladders - 1, r = heights.length - 1; + + const canReach = (mid) => { + let diffs = []; + for (let i = 0; i < mid; i++) { + if (heights[i + 1] > heights[i]) { + diffs.push(heights[i + 1] - heights[i]); + } + } + + diffs.sort((a, b) => a - b); + let brickSum = 0; + + for (let j = 0; j < diffs.length - ladders; j++) { + brickSum += diffs[j]; + if (brickSum > bricks) { + return false; + } + } + + return true; + }; + + while (l <= r) { + let mid = Math.floor((l + r) / 2); + if (canReach(mid)) { + l = mid + 1; + } else { + r = mid - 1; + } + } + + return l - 1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log ^ 2 n)$ +* Space complexity: $O(n)$ + +--- + +## 3. Binary Search On Buildings (Optimal) + +::tabs-start + +```python +class Solution: + def furthestBuilding(self, heights: List[int], bricks: int, ladders: int) -> int: + diffs = [] + for i in range(1, len(heights)): + if heights[i] > heights[i - 1]: + diffs.append((heights[i] - heights[i - 1], i)) + + diffs.sort(reverse=True) + + def canReach(index): + useLadders = useBricks = 0 + for diff, i in diffs: + if i > index: + continue + + if useLadders < ladders: + useLadders += 1 + else: + useBricks += diff + if useBricks > bricks: + return False + return True + + l, r = 1, len(heights) - 1 + while l <= r: + mid = (l + r) >> 1 + if canReach(mid): + l = mid + 1 + else: + r = mid - 1 + return l - 1 +``` + +```java +public class Solution { + public int furthestBuilding(int[] heights, int bricks, int ladders) { + List diffs = new ArrayList<>(); + for (int i = 1; i < heights.length; i++) { + if (heights[i] > heights[i - 1]) { + diffs.add(new int[]{heights[i] - heights[i - 1], i}); + } + } + + diffs.sort((a, b) -> Integer.compare(b[0], a[0])); + + int l = 1, r = heights.length - 1; + while (l <= r) { + int mid = (l + r) >> 1; + if (canReach(diffs, mid, bricks, ladders)) { + l = mid + 1; + } else { + r = mid - 1; + } + } + + return l - 1; + } + + private boolean canReach(List diffs, int index, int bricks, int ladders) { + int useLadders = 0; + long useBricks = 0; + for (int[] diff : diffs) { + int jump = diff[0], i = diff[1]; + + if (i > index) continue; + + if (useLadders < ladders) { + useLadders++; + } else { + useBricks += jump; + if (useBricks > bricks) { + return false; + } + } + } + return true; + } +} +``` + +```cpp +class Solution { +public: + int furthestBuilding(vector& heights, int bricks, int ladders) { + vector> diffs; + for (int i = 1; i < heights.size(); i++) { + if (heights[i] > heights[i - 1]) { + diffs.emplace_back(heights[i] - heights[i - 1], i); + } + } + + sort(diffs.rbegin(), diffs.rend()); // Sort in descending order + + int l = 1, r = heights.size() - 1; + while (l <= r) { + int mid = (l + r) >> 1; + if (canReach(diffs, mid, bricks, ladders)) { + l = mid + 1; + } else { + r = mid - 1; + } + } + + return l - 1; + } + +private: + bool canReach(vector>& diffs, int index, int bricks, int ladders) { + int useLadders = 0; + long long useBricks = 0; + for (auto& diff : diffs) { + int jump = diff.first, i = diff.second; + + if (i > index) continue; + + if (useLadders < ladders) { + useLadders++; + } else { + useBricks += jump; + if (useBricks > bricks) { + return false; + } + } + } + return true; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} heights + * @param {number} bricks + * @param {number} ladders + * @return {number} + */ + furthestBuilding(heights, bricks, ladders) { + let diffs = []; + for (let i = 1; i < heights.length; i++) { + if (heights[i] > heights[i - 1]) { + diffs.push([heights[i] - heights[i - 1], i]); + } + } + + diffs.sort((a, b) => b[0] - a[0]); + + const canReach = (index) => { + let useLadders = 0, useBricks = 0; + for (let [diff, i] of diffs) { + if (i > index) continue; + + if (useLadders < ladders) { + useLadders++; + } else { + useBricks += diff; + if (useBricks > bricks) { + return false; + } + } + } + return true; + }; + + let l = 1, r = heights.length - 1; + while (l <= r) { + let mid = (l + r) >> 1; + if (canReach(mid)) { + l = mid + 1; + } else { + r = mid - 1; + } + } + + return l - 1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(n)$ + +--- + +## 4. Max-Heap + +::tabs-start + +```python +class Solution: + def furthestBuilding(self, heights: List[int], bricks: int, ladders: int) -> int: + heap = [] # Max heap of bricks used + + for i in range(len(heights) - 1): + diff = heights[i + 1] - heights[i] + if diff <= 0: + continue + + bricks -= diff + heapq.heappush(heap, -diff) + + if bricks < 0: + if ladders == 0: + return i + ladders -= 1 + bricks += -heapq.heappop(heap) + + return len(heights) - 1 +``` + +```java +public class Solution { + public int furthestBuilding(int[] heights, int bricks, int ladders) { + PriorityQueue maxHeap = new PriorityQueue<>((a, b) -> b - a); + + for (int i = 0; i < heights.length - 1; i++) { + int diff = heights[i + 1] - heights[i]; + if (diff <= 0) continue; + + bricks -= diff; + maxHeap.offer(diff); + + if (bricks < 0) { + if (ladders == 0) return i; + ladders--; + bricks += maxHeap.poll(); + } + } + + return heights.length - 1; + } +} +``` + +```cpp +class Solution { +public: + int furthestBuilding(vector& heights, int bricks, int ladders) { + priority_queue maxHeap; + + for (int i = 0; i < heights.size() - 1; i++) { + int diff = heights[i + 1] - heights[i]; + if (diff <= 0) continue; + + bricks -= diff; + maxHeap.push(diff); + + if (bricks < 0) { + if (ladders == 0) return i; + ladders--; + bricks += maxHeap.top(); + maxHeap.pop(); + } + } + + return heights.size() - 1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} heights + * @param {number} bricks + * @param {number} ladders + * @return {number} + */ + furthestBuilding(heights, bricks, ladders) { + const maxHeap = new MaxPriorityQueue(); + + for (let i = 0; i < heights.length - 1; i++) { + let diff = heights[i + 1] - heights[i]; + if (diff <= 0) continue; + + bricks -= diff; + maxHeap.enqueue(diff); + + if (bricks < 0) { + if (ladders === 0) return i; + ladders--; + bricks += maxHeap.dequeue().element; + } + } + + return heights.length - 1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(n)$ + +--- + +## 5. Min-Heap + +::tabs-start + +```python +class Solution: + def furthestBuilding(self, heights: List[int], bricks: int, ladders: int) -> int: + minHeap = [] + + for i in range(len(heights) - 1): + diff = heights[i + 1] - heights[i] + if diff <= 0: + continue + + heapq.heappush(minHeap, diff) + if len(minHeap) > ladders: + bricks -= heapq.heappop(minHeap) + if bricks < 0: + return i + + return len(heights) - 1 +``` + +```java +public class Solution { + public int furthestBuilding(int[] heights, int bricks, int ladders) { + PriorityQueue minHeap = new PriorityQueue<>(); + + for (int i = 0; i < heights.length - 1; i++) { + int diff = heights[i + 1] - heights[i]; + if (diff <= 0) continue; + + minHeap.offer(diff); + if (minHeap.size() > ladders) { + bricks -= minHeap.poll(); + if (bricks < 0) return i; + } + } + + return heights.length - 1; + } +} +``` + +```cpp +class Solution { +public: + int furthestBuilding(vector& heights, int bricks, int ladders) { + priority_queue, greater> minHeap; + + for (int i = 0; i < int(heights.size()) - 1; i++) { + int diff = heights[i + 1] - heights[i]; + if (diff <= 0) continue; + + minHeap.push(diff); + if (minHeap.size() > ladders) { + bricks -= minHeap.top(); minHeap.pop(); + if (bricks < 0) return i; + } + } + + return int(heights.size()) - 1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} heights + * @param {number} bricks + * @param {number} ladders + * @return {number} + */ + furthestBuilding(heights, bricks, ladders) { + const minHeap = new MinPriorityQueue(); + + for (let i = 0; i < heights.length - 1; i++) { + let diff = heights[i + 1] - heights[i]; + if (diff <= 0) continue; + + minHeap.enqueue(diff); + if (minHeap.size() > ladders) { + bricks -= minHeap.dequeue().element; + if (bricks < 0) return i; + } + } + + return heights.length - 1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(n)$ \ No newline at end of file diff --git a/articles/integer-to-roman.md b/articles/integer-to-roman.md new file mode 100644 index 000000000..6bb15bb30 --- /dev/null +++ b/articles/integer-to-roman.md @@ -0,0 +1,195 @@ +## 1. Math - I + +::tabs-start + +```python +class Solution: + def intToRoman(self, num: int) -> str: + symList = [ + ["I", 1], ["IV", 4], ["V", 5], ["IX", 9], + ["X", 10], ["XL", 40], ["L", 50], ["XC", 90], + ["C", 100], ["CD", 400], ["D", 500], ["CM", 900], + ["M", 1000] + ] + + res = "" + for sym, val in reversed(symList): + count = num // val + if count: + res += sym * count + num %= val + + return res +``` + +```java +public class Solution { + public String intToRoman(int num) { + String[][] symList = { + {"I", "1"}, {"IV", "4"}, {"V", "5"}, {"IX", "9"}, + {"X", "10"}, {"XL", "40"}, {"L", "50"}, {"XC", "90"}, + {"C", "100"}, {"CD", "400"}, {"D", "500"}, {"CM", "900"}, + {"M", "1000"} + }; + + StringBuilder res = new StringBuilder(); + for (int i = symList.length - 1; i >= 0; i--) { + String sym = symList[i][0]; + int val = Integer.parseInt(symList[i][1]); + int count = num / val; + if (count > 0) { + res.append(sym.repeat(count)); + num %= val; + } + } + + return res.toString(); + } +} +``` + +```cpp +class Solution { +public: + string intToRoman(int num) { + vector> symList = { + {"I", 1}, {"IV", 4}, {"V", 5}, {"IX", 9}, + {"X", 10}, {"XL", 40}, {"L", 50}, {"XC", 90}, + {"C", 100}, {"CD", 400}, {"D", 500}, {"CM", 900}, + {"M", 1000} + }; + + string res = ""; + for (int i = symList.size() - 1; i >= 0; i--) { + string sym = symList[i].first; + int val = symList[i].second; + int count = num / val; + if (count > 0) { + res.append(count, sym[0]); + if (sym.size() == 2) res.append(1, sym[1]); + num %= val; + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} num + * @return {string} + */ + intToRoman(num) { + const symList = [ + ["I", 1], ["IV", 4], ["V", 5], ["IX", 9], + ["X", 10], ["XL", 40], ["L", 50], ["XC", 90], + ["C", 100], ["CD", 400], ["D", 500], ["CM", 900], + ["M", 1000] + ]; + + let res = ""; + for (let i = symList.length - 1; i >= 0; i--) { + const [sym, val] = symList[i]; + let count = Math.floor(num / val); + if (count > 0) { + res += sym.repeat(count); + num %= val; + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(1)$ +* Space complexity: $O(1)$ + +--- + +## 2. Math - II + +::tabs-start + +```python +class Solution: + def intToRoman(self, num: int) -> str: + thousands = ["", "M", "MM", "MMM"] + hundreds = ["", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"] + tens = ["", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"] + ones = ["", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"] + + return ( + thousands[num // 1000] + + hundreds[(num % 1000) // 100] + + tens[(num % 100) // 10] + + ones[num % 10] + ) +``` + +```java +public class Solution { + public String intToRoman(int num) { + String[] thousands = {"", "M", "MM", "MMM"}; + String[] hundreds = {"", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"}; + String[] tens = {"", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"}; + String[] ones = {"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"}; + + return thousands[num / 1000] + + hundreds[(num % 1000) / 100] + + tens[(num % 100) / 10] + + ones[num % 10]; + } +} +``` + +```cpp +class Solution { +public: + string intToRoman(int num) { + string thousands[] = {"", "M", "MM", "MMM"}; + string hundreds[] = {"", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"}; + string tens[] = {"", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"}; + string ones[] = {"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"}; + + return thousands[num / 1000] + + hundreds[(num % 1000) / 100] + + tens[(num % 100) / 10] + + ones[num % 10]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} num + * @return {string} + */ + intToRoman(num) { + const thousands = ["", "M", "MM", "MMM"]; + const hundreds = ["", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"]; + const tens = ["", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"]; + const ones = ["", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"]; + + return thousands[Math.floor(num / 1000)] + + hundreds[Math.floor((num % 1000) / 100)] + + tens[Math.floor((num % 100) / 10)] + + ones[num % 10]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(1)$ +* Space complexity: $O(1)$ \ No newline at end of file diff --git a/articles/is-graph-bipartite.md b/articles/is-graph-bipartite.md new file mode 100644 index 000000000..2db1c9d94 --- /dev/null +++ b/articles/is-graph-bipartite.md @@ -0,0 +1,611 @@ +## 1. Depth First Search + +::tabs-start + +```python +class Solution: + def isBipartite(self, graph: List[List[int]]) -> bool: + color = [0] * len(graph) # Map node i -> odd=1, even=-1 + + def dfs(i, c): + color[i] = c + for nei in graph[i]: + if color[nei] == c: + return False + if color[nei] == 0 and not dfs(nei, -c): + return False + return True + + for i in range(len(graph)): + if color[i] == 0 and not dfs(i, 1): + return False + return True +``` + +```java +public class Solution { + private int[] color; + + public boolean isBipartite(int[][] graph) { + int n = graph.length; + color = new int[n]; // Map node i -> odd=1, even=-1 + + for (int i = 0; i < n; i++) { + if (color[i] == 0 && !dfs(graph, i, 1)) { + return false; + } + } + return true; + } + + private boolean dfs(int[][] graph, int i, int c) { + color[i] = c; + for (int nei : graph[i]) { + if (color[nei] == c) { + return false; + } + if (color[nei] == 0 && !dfs(graph, nei, -c)) { + return false; + } + } + return true; + } +} +``` + +```cpp +class Solution { +private: + vector color; + + bool dfs(vector>& graph, int i, int c) { + color[i] = c; + for (int nei : graph[i]) { + if (color[nei] == c) { + return false; + } + if (color[nei] == 0 && !dfs(graph, nei, -c)) { + return false; + } + } + return true; + } + +public: + bool isBipartite(vector>& graph) { + int n = graph.size(); + color.assign(n, 0); // Map node i -> odd=1, even=-1 + + for (int i = 0; i < n; i++) { + if (color[i] == 0 && !dfs(graph, i, 1)) { + return false; + } + } + return true; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} graph + * @return {boolean} + */ + isBipartite(graph) { + let n = graph.length; + let color = new Array(n).fill(0); // Map node i -> odd=1, even=-1 + + const dfs = (i, c) => { + color[i] = c; + for (let nei of graph[i]) { + if (color[nei] === c) { + return false; + } + if (color[nei] === 0 && !dfs(nei, -c)) { + return false; + } + } + return true; + }; + + for (let i = 0; i < n; i++) { + if (color[i] === 0 && !dfs(i, 1)) { + return false; + } + } + return true; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(V + E)$ +* Space complexity: $O(V)$ + +> Where $V$ is the number of vertices and $E$ is the number of edges. + +--- + +## 2. Breadth First Search + +::tabs-start + +```python +class Solution: + def isBipartite(self, graph: List[List[int]]) -> bool: + color = [0] * len(graph) # Map node i -> odd=1, even=-1 + + def bfs(i): + if color[i]: + return True + q = deque([i]) + color[i] = -1 + while q: + i = q.popleft() + for nei in graph[i]: + if color[i] == color[nei]: + return False + elif not color[nei]: + q.append(nei) + color[nei] = -1 * color[i] + return True + + for i in range(len(graph)): + if not bfs(i): + return False + return True +``` + +```java +public class Solution { + public boolean isBipartite(int[][] graph) { + int n = graph.length; + int[] color = new int[n]; // Map node i -> odd=1, even=-1 + + for (int i = 0; i < n; i++) { + if (color[i] != 0) continue; + Queue q = new LinkedList<>(); + q.offer(i); + color[i] = -1; + + while (!q.isEmpty()) { + int node = q.poll(); + for (int nei : graph[node]) { + if (color[nei] == color[node]) { + return false; + } else if (color[nei] == 0) { + q.offer(nei); + color[nei] = -color[node]; + } + } + } + } + return true; + } +} +``` + +```cpp +class Solution { +public: + bool isBipartite(vector>& graph) { + int n = graph.size(); + vector color(n, 0); // Map node i -> odd=1, even=-1 + + for (int i = 0; i < n; i++) { + if (color[i] != 0) continue; + queue q; + q.push(i); + color[i] = -1; + + while (!q.empty()) { + int node = q.front(); + q.pop(); + for (int nei : graph[node]) { + if (color[nei] == color[node]) { + return false; + } else if (color[nei] == 0) { + q.push(nei); + color[nei] = -color[node]; + } + } + } + } + return true; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} graph + * @return {boolean} + */ + isBipartite(graph) { + let n = graph.length; + let color = new Array(n).fill(0); // Map node i -> odd=1, even=-1 + + for (let i = 0; i < n; i++) { + if (color[i] !== 0) continue; + let q = new Queue([i]); + color[i] = -1; + + while (!q.isEmpty()) { + let node = q.pop(); + for (let nei of graph[node]) { + if (color[nei] === color[node]) { + return false; + } else if (color[nei] === 0) { + q.push(nei); + color[nei] = -color[node]; + } + } + } + } + return true; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(V + E)$ +* Space complexity: $O(V)$ + +> Where $V$ is the number of vertices and $E$ is the number of edges. + +--- + +## 3. Iterative DFS + +::tabs-start + +```python +class Solution: + def isBipartite(self, graph: List[List[int]]) -> bool: + color = [0] * len(graph) # Map node i -> odd=1, even=-1 + stack = [] + + for i in range(len(graph)): + if color[i] != 0: + continue + color[i] = -1 + stack.append(i) + while stack: + node = stack.pop() + for nei in graph[node]: + if color[node] == color[nei]: + return False + elif not color[nei]: + stack.append(nei) + color[nei] = -1 * color[node] + + return True +``` + +```java +public class Solution { + public boolean isBipartite(int[][] graph) { + int n = graph.length; + int[] color = new int[n]; // Map node i -> odd=1, even=-1 + Stack stack = new Stack<>(); + + for (int i = 0; i < n; i++) { + if (color[i] != 0) continue; + color[i] = -1; + stack.push(i); + while (!stack.isEmpty()) { + int node = stack.pop(); + for (int nei : graph[node]) { + if (color[node] == color[nei]) return false; + if (color[nei] == 0) { + stack.push(nei); + color[nei] = -color[node]; + } + } + } + } + return true; + } +} +``` + +```cpp +class Solution { +public: + bool isBipartite(vector>& graph) { + int n = graph.size(); + vector color(n); // Map node i -> odd=1, even=-1 + stack stack; + + for (int i = 0; i < n; i++) { + if (color[i] != 0) continue; + color[i] = -1; + stack.push(i); + while (!stack.empty()) { + int node = stack.top(); + stack.pop(); + for (int nei : graph[node]) { + if (color[node] == color[nei]) return false; + if (color[nei] == 0) { + stack.push(nei); + color[nei] = -color[node]; + } + } + } + } + return true; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} graph + * @return {boolean} + */ + isBipartite(graph) { + let n = graph.length; + let color = new Array(n).fill(0); // Map node i -> odd=1, even=-1 + let stack = []; + + for (let i = 0; i < n; i++) { + if (color[i] !== 0) continue; + color[i] = -1; + stack.push(i); + while (stack.length > 0) { + let node = stack.pop(); + for (let nei of graph[node]) { + if (color[node] === color[nei]) return false; + if (color[nei] === 0) { + stack.push(nei); + color[nei] = -color[node]; + } + } + } + } + return true; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(V + E)$ +* Space complexity: $O(V)$ + +> Where $V$ is the number of vertices and $E$ is the number of edges. + +--- + +## 4. Disjoint Set Union + +::tabs-start + +```python +class DSU: + def __init__(self, n): + self.Parent = list(range(n)) + self.Size = [0] * n + + def find(self, node): + if self.Parent[node] != node: + self.Parent[node] = self.find(self.Parent[node]) + return self.Parent[node] + + def union(self, u, v): + pu, pv = self.find(u), self.find(v) + if pu == pv: + return False + if self.Size[pu] > self.Size[pv]: + self.Parent[pv] = pu + elif self.Size[pu] < self.Size[pv]: + self.Parent[pu] = pv + else: + self.Parent[pv] = pu + self.Size[pu] += 1 + return True + +class Solution: + def isBipartite(self, graph: List[List[int]]) -> bool: + n = len(graph) + dsu = DSU(n) + + for node in range(n): + for nei in graph[node]: + if dsu.find(node) == dsu.find(nei): + return False + dsu.union(graph[node][0], nei) + + return True +``` + +```java +public class DSU { + private int[] Parent, Size; + + public DSU(int n) { + Parent = new int[n]; + Size = new int[n]; + for (int i = 0; i < n; i++) { + Parent[i] = i; + Size[i] = 0; + } + } + + public int find(int node) { + if (Parent[node] != node) { + Parent[node] = find(Parent[node]); + } + return Parent[node]; + } + + public boolean union(int u, int v) { + int pu = find(u), pv = find(v); + if (pu == pv) return false; + if (Size[pu] > Size[pv]) { + Parent[pv] = pu; + } else if (Size[pu] < Size[pv]) { + Parent[pu] = pv; + } else { + Parent[pv] = pu; + Size[pu]++; + } + return true; + } +} + +class Solution { + public boolean isBipartite(int[][] graph) { + int n = graph.length; + DSU dsu = new DSU(n); + + for (int node = 0; node < n; node++) { + for (int nei : graph[node]) { + if (dsu.find(node) == dsu.find(nei)) { + return false; + } + dsu.union(graph[node][0], nei); + } + } + return true; + } +} +``` + +```cpp +class DSU { +private: + vector Parent, Size; + +public: + DSU(int n) { + Parent.resize(n); + Size.resize(n, 0); + for (int i = 0; i < n; i++) { + Parent[i] = i; + } + } + + int find(int node) { + if (Parent[node] != node) { + Parent[node] = find(Parent[node]); + } + return Parent[node]; + } + + bool unionSet(int u, int v) { + int pu = find(u), pv = find(v); + if (pu == pv) return false; + if (Size[pu] > Size[pv]) { + Parent[pv] = pu; + } else if (Size[pu] < Size[pv]) { + Parent[pu] = pv; + } else { + Parent[pv] = pu; + Size[pu]++; + } + return true; + } +}; + +class Solution { +public: + bool isBipartite(vector>& graph) { + int n = graph.size(); + DSU dsu(n); + + for (int node = 0; node < n; node++) { + for (int& nei : graph[node]) { + if (dsu.find(node) == dsu.find(nei)) { + return false; + } + dsu.unionSet(graph[node][0], nei); + } + } + return true; + } +}; +``` + +```javascript +class DSU { + /** + * @constructor + * @param {number} n + */ + constructor(n) { + this.parent = Array.from({ length: n + 1 }, (_, i) => i); + this.size = new Array(n + 1).fill(1); + } + + /** + * @param {number} node + * @return {number} + */ + find(node) { + if (this.parent[node] !== node) { + this.parent[node] = this.find(this.parent[node]); + } + return this.parent[node]; + } + + /** + * @param {number} u + * @param {number} u=v + * @return {boolean} + */ + union(u, v) { + let pu = this.find(u), pv = this.find(v); + if (pu === pv) return false; + if (this.size[pu] >= this.size[pv]) { + this.size[pu] += this.size[pv]; + this.parent[pv] = pu; + } else { + this.size[pv] += this.size[pu]; + this.parent[pu] = pv; + } + return true; + } +} + +class Solution { + /** + * @param {number[][]} graph + * @return {boolean} + */ + isBipartite(graph) { + let n = graph.length; + let dsu = new DSU(n); + + for (let node = 0; node < n; node++) { + for (let nei of graph[node]) { + if (dsu.find(node) === dsu.find(nei)) { + return false; + } + dsu.union(graph[node][0], nei); + } + } + return true; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(V + (E * α(V)))$ +* Space complexity: $O(V)$ + +> Where $V$ is the number of vertices and $E$ is the number of edges. $α()$ is used for amortized complexity. \ No newline at end of file diff --git a/articles/knight-dialer.md b/articles/knight-dialer.md new file mode 100644 index 000000000..9c87f4c13 --- /dev/null +++ b/articles/knight-dialer.md @@ -0,0 +1,946 @@ +## 1. Recursion + +::tabs-start + +```python +class Solution: + def knightDialer(self, n: int) -> int: + if n == 1: + return 10 + + mod = 1000000007 + jumps = [ + [4, 6], [6, 8], [7, 9], [4, 8], [0, 3, 9], + [], [0, 1, 7], [2, 6], [1, 3], [2, 4] + ] + + def dfs(n, d): + if n == 0: + return 1 + + res = 0 + for j in jumps[d]: + res = (res + dfs(n - 1, j)) % mod + return res + + res = 0 + for d in range(10): + res = (res + dfs(n - 1, d)) % mod + return res +``` + +```java +public class Solution { + private static final int MOD = 1000000007; + private static final int[][] jumps = { + {4, 6}, {6, 8}, {7, 9}, {4, 8}, {0, 3, 9}, + {}, {0, 1, 7}, {2, 6}, {1, 3}, {2, 4} + }; + + public int knightDialer(int n) { + if (n == 1) return 10; + int res = 0; + + for (int d = 0; d < 10; d++) { + res = (res + dfs(n - 1, d)) % MOD; + } + return res; + } + + private int dfs(int n, int d) { + if (n == 0) return 1; + + int res = 0; + for (int next : jumps[d]) { + res = (res + dfs(n - 1, next)) % MOD; + } + return res; + } +} +``` + +```cpp +class Solution { +private: + static constexpr int MOD = 1000000007; + const vector> jumps = { + {4, 6}, {6, 8}, {7, 9}, {4, 8}, {0, 3, 9}, + {}, {0, 1, 7}, {2, 6}, {1, 3}, {2, 4} + }; + +public: + int knightDialer(int n) { + if (n == 1) return 10; + int res = 0; + + for (int d = 0; d < 10; d++) { + res = (res + dfs(n - 1, d)) % MOD; + } + return res; + } + +private: + int dfs(int n, int d) { + if (n == 0) return 1; + + int res = 0; + for (int next : jumps[d]) { + res = (res + dfs(n - 1, next)) % MOD; + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + knightDialer(n) { + if (n === 1) return 10; + const MOD = 1000000007; + const jumps = [ + [4, 6], [6, 8], [7, 9], [4, 8], [0, 3, 9], + [], [0, 1, 7], [2, 6], [1, 3], [2, 4] + ]; + + const dfs = (n, d) => { + if (n === 0) return 1; + + let res = 0; + for (const next of jumps[d]) { + res = (res + dfs(n - 1, next)) % MOD; + } + return res; + }; + + let res = 0; + for (let d = 0; d < 10; d++) { + res = (res + dfs(n - 1, d)) % MOD; + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(3 ^ n)$ +* Space complexity: $O(n)$ for recursion stack. + +--- + +## 2. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def knightDialer(self, n: int) -> int: + if n == 1: + return 10 + + mod = 1000000007 + jumps = [ + [4, 6], [6, 8], [7, 9], [4, 8], [0, 3, 9], + [], [0, 1, 7], [2, 6], [1, 3], [2, 4] + ] + + dp = [[-1] * (n + 1) for _ in range(10)] + + def dfs(n, d): + if n == 0: + return 1 + if dp[d][n] != -1: + return dp[d][n] + + dp[d][n] = 0 + for j in jumps[d]: + dp[d][n] = (dp[d][n] + dfs(n - 1, j)) % mod + return dp[d][n] + + res = 0 + for d in range(10): + res = (res + dfs(n - 1, d)) % mod + return res +``` + +```java +public class Solution { + private static final int MOD = 1000000007; + private static final int[][] jumps = { + {4, 6}, {6, 8}, {7, 9}, {4, 8}, {0, 3, 9}, + {}, {0, 1, 7}, {2, 6}, {1, 3}, {2, 4} + }; + private int[][] dp; + + public int knightDialer(int n) { + if (n == 1) return 10; + dp = new int[10][n + 1]; + for (int[] row : dp) Arrays.fill(row, -1); + + int res = 0; + for (int d = 0; d < 10; d++) { + res = (res + dfs(n - 1, d)) % MOD; + } + return res; + } + + private int dfs(int n, int d) { + if (n == 0) return 1; + if (dp[d][n] != -1) return dp[d][n]; + + dp[d][n] = 0; + for (int next : jumps[d]) { + dp[d][n] = (dp[d][n] + dfs(n - 1, next)) % MOD; + } + return dp[d][n]; + } +} +``` + +```cpp +class Solution { +private: + static constexpr int MOD = 1000000007; + vector> jumps = { + {4, 6}, {6, 8}, {7, 9}, {4, 8}, {0, 3, 9}, + {}, {0, 1, 7}, {2, 6}, {1, 3}, {2, 4} + }; + vector> dp; + +public: + int knightDialer(int n) { + if (n == 1) return 10; + dp.assign(10, vector(n + 1, -1)); + + int res = 0; + for (int d = 0; d < 10; d++) { + res = (res + dfs(n - 1, d)) % MOD; + } + return res; + } + +private: + int dfs(int n, int d) { + if (n == 0) return 1; + if (dp[d][n] != -1) return dp[d][n]; + + dp[d][n] = 0; + for (int next : jumps[d]) { + dp[d][n] = (dp[d][n] + dfs(n - 1, next)) % MOD; + } + return dp[d][n]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + knightDialer(n) { + if (n === 1) return 10; + const MOD = 1000000007; + const jumps = [ + [4, 6], [6, 8], [7, 9], [4, 8], [0, 3, 9], + [], [0, 1, 7], [2, 6], [1, 3], [2, 4] + ]; + + const dp = Array.from({ length: 10 }, () => Array(n + 1).fill(-1)); + + const dfs = (n, d) => { + if (n === 0) return 1; + if (dp[d][n] !== -1) return dp[d][n]; + + dp[d][n] = 0; + for (const next of jumps[d]) { + dp[d][n] = (dp[d][n] + dfs(n - 1, next)) % MOD; + } + return dp[d][n]; + }; + + let res = 0; + for (let d = 0; d < 10; d++) { + res = (res + dfs(n - 1, d)) % MOD; + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 3. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def knightDialer(self, n: int) -> int: + if n == 1: + return 10 + + mod = 1000000007 + jumps = [ + [4, 6], [6, 8], [7, 9], [4, 8], [0, 3, 9], + [], [0, 1, 7], [2, 6], [1, 3], [2, 4] + ] + + dp = [[0] * (n + 1) for _ in range(10)] + + for d in range(10): + dp[d][0] = 1 + + for step in range(1, n): + for d in range(10): + dp[d][step] = sum(dp[j][step - 1] for j in jumps[d]) % mod + + return sum(dp[d][n - 1] for d in range(10)) % mod +``` + +```java +public class Solution { + private static final int MOD = 1000000007; + private static final int[][] jumps = { + {4, 6}, {6, 8}, {7, 9}, {4, 8}, {0, 3, 9}, + {}, {0, 1, 7}, {2, 6}, {1, 3}, {2, 4} + }; + + public int knightDialer(int n) { + if (n == 1) return 10; + + int[][] dp = new int[10][n + 1]; + for (int d = 0; d < 10; d++) { + dp[d][0] = 1; + } + + for (int step = 1; step < n; step++) { + for (int d = 0; d < 10; d++) { + for (int j : jumps[d]) { + dp[d][step] = (dp[d][step] + dp[j][step - 1]) % MOD; + } + } + } + + int res = 0; + for (int d = 0; d < 10; d++) { + res = (res + dp[d][n - 1]) % MOD; + } + return res; + } +} +``` + +```cpp +class Solution { +private: + static constexpr int MOD = 1000000007; + vector> jumps = { + {4, 6}, {6, 8}, {7, 9}, {4, 8}, {0, 3, 9}, + {}, {0, 1, 7}, {2, 6}, {1, 3}, {2, 4} + }; + +public: + int knightDialer(int n) { + if (n == 1) return 10; + + vector> dp(10, vector(n + 1, 0)); + for (int d = 0; d < 10; d++) { + dp[d][0] = 1; + } + + for (int step = 1; step < n; step++) { + for (int d = 0; d < 10; d++) { + for (int j : jumps[d]) { + dp[d][step] = (dp[d][step] + dp[j][step - 1]) % MOD; + } + } + } + + int res = 0; + for (int d = 0; d < 10; d++) { + res = (res + dp[d][n - 1]) % MOD; + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + knightDialer(n) { + if (n === 1) return 10; + const MOD = 1000000007; + const jumps = [ + [4, 6], [6, 8], [7, 9], [4, 8], [0, 3, 9], + [], [0, 1, 7], [2, 6], [1, 3], [2, 4] + ]; + + const dp = Array.from({ length: 10 }, () => Array(n + 1).fill(0)); + for (let d = 0; d < 10; d++) { + dp[d][0] = 1; + } + + for (let step = 1; step < n; step++) { + for (let d = 0; d < 10; d++) { + for (const j of jumps[d]) { + dp[d][step] = (dp[d][step] + dp[j][step - 1]) % MOD; + } + } + } + + let res = 0; + for (let d = 0; d < 10; d++) { + res = (res + dp[d][n - 1]) % MOD; + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 4. Dynamic Programming (Space Optimized) + +::tabs-start + +```python +class Solution: + def knightDialer(self, n: int) -> int: + if n == 1: + return 10 + + mod = 1000000007 + jumps = [ + [4, 6], [6, 8], [7, 9], [4, 8], [0, 3, 9], + [], [0, 1, 7], [2, 6], [1, 3], [2, 4] + ] + + dp = [1] * 10 + for step in range(n - 1): + next_dp = [0] * 10 + for d in range(10): + for j in jumps[d]: + next_dp[j] = (next_dp[j] + dp[d]) % mod + dp = next_dp + + res = 0 + for d in dp: + res = (res + d) % mod + return res +``` + +```java +public class Solution { + private static final int MOD = 1000000007; + private static final int[][] jumps = { + {4, 6}, {6, 8}, {7, 9}, {4, 8}, {0, 3, 9}, + {}, {0, 1, 7}, {2, 6}, {1, 3}, {2, 4} + }; + + public int knightDialer(int n) { + if (n == 1) return 10; + + int[] dp = new int[10]; + Arrays.fill(dp, 1); + + for (int step = 0; step < n - 1; step++) { + int[] nextDp = new int[10]; + for (int d = 0; d < 10; d++) { + for (int j : jumps[d]) { + nextDp[j] = (nextDp[j] + dp[d]) % MOD; + } + } + dp = nextDp; + } + + int res = 0; + for (int d : dp) { + res = (res + d) % MOD; + } + return res; + } +} +``` + +```cpp +class Solution { +private: + static constexpr int MOD = 1000000007; + vector> jumps = { + {4, 6}, {6, 8}, {7, 9}, {4, 8}, {0, 3, 9}, + {}, {0, 1, 7}, {2, 6}, {1, 3}, {2, 4} + }; + +public: + int knightDialer(int n) { + if (n == 1) return 10; + + vector dp(10, 1); + + for (int step = 0; step < n - 1; step++) { + vector nextDp(10, 0); + for (int d = 0; d < 10; d++) { + for (int j : jumps[d]) { + nextDp[j] = (nextDp[j] + dp[d]) % MOD; + } + } + dp = nextDp; + } + + int res = 0; + for (int d : dp) { + res = (res + d) % MOD; + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + knightDialer(n) { + if (n === 1) return 10; + const MOD = 1000000007; + const jumps = [ + [4, 6], [6, 8], [7, 9], [4, 8], [0, 3, 9], + [], [0, 1, 7], [2, 6], [1, 3], [2, 4] + ]; + + let dp = new Array(10).fill(1); + + for (let step = 0; step < n - 1; step++) { + let nextDp = new Array(10).fill(0); + for (let d = 0; d < 10; d++) { + for (const j of jumps[d]) { + nextDp[j] = (nextDp[j] + dp[d]) % MOD; + } + } + dp = nextDp; + } + + return dp.reduce((res, d) => (res + d) % MOD, 0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ + +--- + +## 5. Dynamic Programming (Optimal) + +::tabs-start + +```python +class Solution: + def knightDialer(self, n: int) -> int: + if n == 1: + return 10 + + mod = 10**9 + 7 + jumps = [1, 4, 2, 2] # [D, A, B, C] + + for _ in range(n - 1): + tmp = [0] * 4 + tmp[0] = jumps[3] + tmp[1] = 2 * jumps[2] + 2 * jumps[3] + tmp[2] = jumps[1] + tmp[3] = 2 * jumps[0] + jumps[1] + jumps = tmp + + return sum(jumps) % mod +``` + +```java +public class Solution { + public int knightDialer(int n) { + if (n == 1) return 10; + + int MOD = 1000000007; + long[] jumps = {1, 4, 2, 2}; // [D, A, B, C] + + for (int i = 0; i < n - 1; i++) { + long[] tmp = new long[4]; + tmp[0] = jumps[3]; + tmp[1] = (2 * jumps[2] + 2 * jumps[3]) % MOD; + tmp[2] = jumps[1]; + tmp[3] = (2 * jumps[0] + jumps[1]) % MOD; + jumps = tmp; + } + + long res = 0; + for (long num : jumps) { + res = (res + num) % MOD; + } + return (int) res; + } +} +``` + +```cpp +class Solution { +public: + int knightDialer(int n) { + if (n == 1) return 10; + + const int MOD = 1000000007; + vector jumps = {1, 4, 2, 2}; // [D, A, B, C] + + for (int i = 0; i < n - 1; i++) { + vector tmp(4); + tmp[0] = jumps[3]; + tmp[1] = (2 * jumps[2] + 2 * jumps[3]) % MOD; + tmp[2] = jumps[1]; + tmp[3] = (2 * jumps[0] + jumps[1]) % MOD; + jumps = tmp; + } + + return (jumps[0] + jumps[1] + jumps[2] + jumps[3]) % MOD; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + knightDialer(n) { + if (n === 1) return 10; + + const MOD = 1000000007; + let jumps = [1, 4, 2, 2]; // [D, A, B, C] + + for (let i = 0; i < n - 1; i++) { + let tmp = new Array(4).fill(0); + tmp[0] = jumps[3]; + tmp[1] = (2 * jumps[2] + 2 * jumps[3]) % MOD; + tmp[2] = jumps[1]; + tmp[3] = (2 * jumps[0] + jumps[1]) % MOD; + jumps = tmp; + } + + return jumps.reduce((sum, num) => (sum + num) % MOD, 0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ + +--- + +## 6. Matrix Exponentiation + +::tabs-start + +```python +class Matrix: + def __init__(self, size): + self.n = size + self.a = [[0] * size for _ in range(size)] + + def __mul__(self, other): + n = self.n + MOD = 10**9 + 7 + product = Matrix(n) + for i in range(n): + for j in range(n): + for k in range(n): + product.a[i][k] = (product.a[i][k] + self.a[i][j] * other.a[j][k]) % MOD + return product + + +def matpow(mat, n, size): + res = Matrix(size) + for i in range(size): + res.a[i][i] = 1 # Identity matrix + + while n: + if n & 1: + res = res * mat + mat = mat * mat + n >>= 1 + + return res + + +class Solution: + def knightDialer(self, n: int) -> int: + if n == 1: + return 10 + + MOD = 10**9 + 7 + jumps = [ + [4, 6], [6, 8], [7, 9], [4, 8], [0, 3, 9], + [], [0, 1, 7], [2, 6], [1, 3], [2, 4] + ] + + mat = Matrix(10) + for i in range(10): + for j in jumps[i]: + mat.a[i][j] = 1 + + res = matpow(mat, n - 1, 10) + + ans = sum(sum(res.a[i]) for i in range(10)) % MOD + return ans +``` + +```java +class Matrix { + int[][] a; + int size; + static final int MOD = 1_000_000_007; + + public Matrix(int size) { + this.size = size; + a = new int[size][size]; + } + + public Matrix multiply(Matrix other) { + Matrix product = new Matrix(size); + for (int i = 0; i < size; i++) { + for (int j = 0; j < size; j++) { + for (int k = 0; k < size; k++) { + product.a[i][k] = (int)((product.a[i][k] + (long) a[i][j] * other.a[j][k]) % MOD); + } + } + } + return product; + } +} + +public class Solution { + private Matrix matpow(Matrix mat, int n, int size) { + Matrix res = new Matrix(size); + for (int i = 0; i < size; i++) { + res.a[i][i] = 1; // Identity matrix + } + + while (n > 0) { + if ((n & 1) == 1) { + res = res.multiply(mat); + } + mat = mat.multiply(mat); + n >>= 1; + } + return res; + } + + public int knightDialer(int n) { + if (n == 1) return 10; + + int[][] jumps = { + {4, 6}, {6, 8}, {7, 9}, {4, 8}, {0, 3, 9}, + {}, {0, 1, 7}, {2, 6}, {1, 3}, {2, 4} + }; + + Matrix mat = new Matrix(10); + for (int i = 0; i < 10; i++) { + for (int j : jumps[i]) { + mat.a[i][j] = 1; + } + } + + Matrix res = matpow(mat, n - 1, 10); + + int ans = 0; + for (int i = 0; i < 10; i++) { + for (int j = 0; j < 10; j++) { + ans = (ans + res.a[i][j]) % Matrix.MOD; + } + } + return ans; + } +} +``` + +```cpp +class Matrix { +public: + vector> a; + int size; + static const int MOD = 1'000'000'007; + + Matrix(int n) : size(n) { + a.assign(n, vector(n, 0)); + } + + Matrix operator*(const Matrix &other) const { + Matrix product(size); + for (int i = 0; i < size; i++) { + for (int j = 0; j < size; j++) { + for (int k = 0; k < size; k++) { + product.a[i][k] = (product.a[i][k] + 1LL * a[i][j] * other.a[j][k]) % MOD; + } + } + } + return product; + } +}; + +Matrix matpow(Matrix mat, int n, int size) { + Matrix res(size); + for (int i = 0; i < size; i++) { + res.a[i][i] = 1; // Identity matrix + } + + while (n > 0) { + if (n & 1) res = res * mat; + mat = mat * mat; + n >>= 1; + } + return res; +} + +class Solution { +public: + int knightDialer(int n) { + if (n == 1) return 10; + + vector> jumps = { + {4, 6}, {6, 8}, {7, 9}, {4, 8}, {0, 3, 9}, + {}, {0, 1, 7}, {2, 6}, {1, 3}, {2, 4} + }; + + Matrix mat(10); + for (int i = 0; i < 10; i++) { + for (int j : jumps[i]) { + mat.a[i][j] = 1; + } + } + + Matrix res = matpow(mat, n - 1, 10); + + int ans = 0; + for (int i = 0; i < 10; i++) { + for (int j = 0; j < 10; j++) { + ans = (ans + res.a[i][j]) % Matrix::MOD; + } + } + return ans; + } +}; +``` + +```javascript +class Matrix { + constructor(size) { + this.size = size; + this.a = Array.from({ length: size }, () => Array(size).fill(0)); + this.MOD = BigInt(1e9 + 7); + } + + multiply(other) { + const product = new Matrix(this.size); + for (let i = 0; i < this.size; i++) { + for (let j = 0; j < this.size; j++) { + let sum = BigInt(0); + for (let k = 0; k < this.size; k++) { + sum = (sum + BigInt(this.a[i][k]) * BigInt(other.a[k][j])) % this.MOD; + } + product.a[i][j] = Number(sum); + } + } + return product; + } +} + +class Solution { + /** + * @param {number} n + * @return {number} + */ + knightDialer(n) { + if (n === 1) return 10; + + const matpow = (mat, exp, size) => { + let res = new Matrix(size); + for (let i = 0; i < size; i++) { + res.a[i][i] = 1; // Identity matrix + } + + while (exp > 0) { + if (exp & 1) { + res = res.multiply(mat); + } + mat = mat.multiply(mat); + exp >>= 1; + } + return res; + }; + + const jumps = [ + [4, 6], [6, 8], [7, 9], [4, 8], [0, 3, 9], + [], [0, 1, 7], [2, 6], [1, 3], [2, 4] + ]; + + const mat = new Matrix(10); + for (let i = 0; i < 10; i++) { + for (let j of jumps[i]) { + mat.a[i][j] = 1; + } + } + + const res = matpow(mat, n - 1, 10); + const mod = 1e9 + 7 + let ans = 0; + + for (let i = 0; i < 10; i++) { + for (let j = 0; j < 10; j++) { + ans = (ans + res.a[i][j]) % mod; + } + } + + return ans; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(\log n)$ +* Space complexity: $O(1)$ \ No newline at end of file diff --git a/articles/largest-color-value-in-a-directed-graph.md b/articles/largest-color-value-in-a-directed-graph.md new file mode 100644 index 000000000..dcbf467a4 --- /dev/null +++ b/articles/largest-color-value-in-a-directed-graph.md @@ -0,0 +1,589 @@ +## 1. Brute Force (DFS) + +::tabs-start + +```python +class Solution: + def largestPathValue(self, colors: str, edges: list[list[int]]) -> int: + n = len(colors) + adj = [[] for _ in range(n)] + for u, v in edges: + adj[u].append(v) + + visit = [False] * n + def dfs(node, c): + if visit[node]: + return float("inf") + + visit[node] = True + clrCnt = 0 + for nei in adj[node]: + cur = dfs(nei, c) + if cur == float("inf"): + return cur + clrCnt = max(clrCnt, cur) + visit[node] = False + return clrCnt + (c == (ord(colors[node]) - ord('a'))) + + res = -1 + for i in range(n): + for c in range(26): + cnt = dfs(i, c) + if cnt == float("inf"): + return -1 + res = max(res, cnt) + return res +``` + +```java +public class Solution { + private int n; + private List[] adj; + private boolean[] visit; + + public int largestPathValue(String colors, int[][] edges) { + this.n = colors.length(); + this.adj = new ArrayList[n]; + this.visit = new boolean[n]; + + for (int i = 0; i < n; i++) { + adj[i] = new ArrayList<>(); + } + for (int[] edge : edges) { + adj[edge[0]].add(edge[1]); + } + + int res = -1; + for (int i = 0; i < n; i++) { + for (int c = 0; c < 26; c++) { + int cnt = dfs(i, c, colors); + if (cnt == Integer.MAX_VALUE) return -1; + res = Math.max(res, cnt); + } + } + return res; + } + + private int dfs(int node, int c, String colors) { + if (visit[node]) return Integer.MAX_VALUE; + + visit[node] = true; + int clrCnt = 0; + for (int nei : adj[node]) { + int cur = dfs(nei, c, colors); + if (cur == Integer.MAX_VALUE) return cur; + clrCnt = Math.max(clrCnt, cur); + } + visit[node] = false; + return clrCnt + ((colors.charAt(node) - 'a') == c ? 1 : 0); + } +} +``` + +```cpp +class Solution { +public: + int n; + vector> adj; + vector visit; + + int largestPathValue(string colors, vector>& edges) { + n = colors.size(); + adj.assign(n, vector()); + visit.assign(n, false); + + for (auto& edge : edges) { + adj[edge[0]].push_back(edge[1]); + } + + int res = -1; + for (int i = 0; i < n; i++) { + for (int c = 0; c < 26; c++) { + int cnt = dfs(i, c, colors); + if (cnt == 1e9) return -1; + res = max(res, cnt); + } + } + return res; + } + +private: + int dfs(int node, int c, string& colors) { + if (visit[node]) return 1e9; + + visit[node] = true; + int clrCnt = 0; + for (int nei : adj[node]) { + int cur = dfs(nei, c, colors); + if (cur == 1e9) return cur; + clrCnt = max(clrCnt, cur); + } + visit[node] = false; + return clrCnt + ((colors[node] - 'a') == c ? 1 : 0); + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} colors + * @param {number[][]} edges + * @return {number} + */ + largestPathValue(colors, edges) { + const n = colors.length; + const adj = Array.from({ length: n }, () => []); + for (const [u, v] of edges) { + adj[u].push(v); + } + + const visit = new Array(n).fill(false); + const dfs = (node, c) => { + if (visit[node]) return Infinity; + + visit[node] = true; + let clrCnt = 0; + for (const nei of adj[node]) { + const cur = dfs(nei, c); + if (cur === Infinity) return cur; + clrCnt = Math.max(clrCnt, cur); + } + visit[node] = false; + return clrCnt + (c === colors.charCodeAt(node) - 97 ? 1 : 0); + }; + + let res = -1; + for (let i = 0; i < n; i++) { + for (let c = 0; c < 26; c++) { + const cnt = dfs(i, c); + if (cnt === Infinity) return -1; + res = Math.max(res, cnt); + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(V * (V + E))$ +* Space complexity: $O(V + E)$ + +> Where $V$ is the number of verticies and $E$ is the number of edges. + +--- + +## 2. Depth First Search + +::tabs-start + +```python +class Solution: + def largestPathValue(self, colors: str, edges: list[list[int]]) -> int: + adj = defaultdict(list) + for src, dst in edges: + adj[src].append(dst) + + def dfs(node): + if node in path: + return float("inf") + if node in visit: + return 0 + + visit.add(node) + path.add(node) + colorIndex = ord(colors[node]) - ord('a') + count[node][colorIndex] = 1 + + for nei in adj[node]: + if dfs(nei) == float("inf"): + return float("inf") + for c in range(26): + count[node][c] = max( + count[node][c], + (1 if c == colorIndex else 0) + count[nei][c] + ) + + path.remove(node) + return 0 + + n, res = len(colors), 0 + visit, path = set(), set() + count = [[0] * 26 for _ in range(n)] + + for i in range(n): + if dfs(i) == float("inf"): + return -1 + res = max(res, max(count[i])) + + return res +``` + +```java +public class Solution { + private int n; + private List[] adj; + private boolean[] visit, path; + private int[][] count; + + public int largestPathValue(String colors, int[][] edges) { + this.n = colors.length(); + this.adj = new ArrayList[n]; + this.visit = new boolean[n]; + this.path = new boolean[n]; + this.count = new int[n][26]; + + for (int i = 0; i < n; i++) { + adj[i] = new ArrayList<>(); + } + for (int[] edge : edges) { + adj[edge[0]].add(edge[1]); + } + + int res = 0; + for (int i = 0; i < n; i++) { + if (dfs(i, colors) == Integer.MAX_VALUE) return -1; + for (int c = 0; c < 26; c++) { + res = Math.max(res, count[i][c]); + } + } + return res; + } + + private int dfs(int node, String colors) { + if (path[node]) return Integer.MAX_VALUE; + if (visit[node]) return 0; + + visit[node] = true; + path[node] = true; + int colorIndex = colors.charAt(node) - 'a'; + count[node][colorIndex] = 1; + + for (int nei : adj[node]) { + if (dfs(nei, colors) == Integer.MAX_VALUE) { + return Integer.MAX_VALUE; + } + for (int c = 0; c < 26; c++) { + count[node][c] = Math.max( + count[node][c], + (c == colorIndex ? 1 : 0) + count[nei][c] + ); + } + } + + path[node] = false; + return 0; + } +} +``` + +```cpp +class Solution { +public: + int n, INF = 1e9; + vector> adj; + vector visit, path; + vector> count; + + int largestPathValue(string colors, vector>& edges) { + this->n = colors.size(); + adj.resize(n); + visit.assign(n, false); + path.assign(n, false); + count.assign(n, vector(26)); + + for (auto& edge : edges) { + adj[edge[0]].push_back(edge[1]); + } + + int res = 0; + for (int i = 0; i < n; i++) { + if (dfs(i, colors) == INF) return -1; + for (int c = 0; c < 26; c++) { + res = max(res, count[i][c]); + } + } + return res; + } + +private: + int dfs(int node, string& colors) { + if (path[node]) return INF; + if (visit[node]) return 0; + + visit[node] = true; + path[node] = true; + int colorIndex = colors[node] - 'a'; + count[node][colorIndex] = 1; + + for (int& nei : adj[node]) { + if (dfs(nei, colors) == INF) return INF; + for (int c = 0; c < 26; c++) { + count[node][c] = max( + count[node][c], + (c == colorIndex ? 1 : 0) + count[nei][c] + ); + } + } + + path[node] = false; + return 0; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} colors + * @param {number[][]} edges + * @return {number} + */ + largestPathValue(colors, edges) { + const n = colors.length; + const adj = Array.from({ length: n }, () => []); + for (const [src, dst] of edges) { + adj[src].push(dst); + } + + const visit = new Array(n).fill(false); + const path = new Array(n).fill(false); + const count = Array.from({ length: n }, () => new Array(26).fill(0)); + + const dfs = (node) => { + if (path[node]) return Infinity; + if (visit[node]) return 0; + + visit[node] = true; + path[node] = true; + const colorIndex = colors.charCodeAt(node) - 'a'.charCodeAt(0); + count[node][colorIndex] = 1; + + for (const nei of adj[node]) { + if (dfs(nei) === Infinity) return Infinity; + for (let c = 0; c < 26; c++) { + count[node][c] = Math.max( + count[node][c], + (c === colorIndex ? 1 : 0) + count[nei][c] + ); + } + } + + path[node] = false; + return 0; + }; + + let res = 0; + for (let i = 0; i < n; i++) { + if (dfs(i) === Infinity) return -1; + for (let c = 0; c < 26; c++) { + res = Math.max(res, count[i][c]); + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(V + E)$ +* Space complexity: $O(V + E)$ + +> Where $V$ is the number of verticies and $E$ is the number of edges. + +--- + +## 3. Topological Sort (Kahn's Algorithm) + +::tabs-start + +```python +class Solution: + def largestPathValue(self, colors: str, edges: list[list[int]]) -> int: + n = len(colors) + adj = [[] for _ in range(n)] + indegree = [0] * n + count = [[0] * 26 for _ in range(n)] + + for u, v in edges: + adj[u].append(v) + indegree[v] += 1 + + q = deque() + for i in range(n): + if indegree[i] == 0: + q.append(i) + + visit = res = 0 + while q: + node = q.popleft() + visit += 1 + colorIndex = ord(colors[node]) - ord('a') + count[node][colorIndex] += 1 + res = max(res, count[node][colorIndex]) + + for nei in adj[node]: + for c in range(26): + count[nei][c] = max(count[nei][c], count[node][c]) + + indegree[nei] -= 1 + if indegree[nei] == 0: + q.append(nei) + + return res if visit == n else -1 +``` + +```java +public class Solution { + public int largestPathValue(String colors, int[][] edges) { + int n = colors.length(); + List[] adj = new ArrayList[n]; + int[] indegree = new int[n]; + int[][] count = new int[n][26]; + + for (int i = 0; i < n; i++) { + adj[i] = new ArrayList<>(); + } + + for (int[] edge : edges) { + adj[edge[0]].add(edge[1]); + indegree[edge[1]]++; + } + + Queue q = new LinkedList<>(); + for (int i = 0; i < n; i++) { + if (indegree[i] == 0) { + q.add(i); + } + } + + int visit = 0, res = 0; + while (!q.isEmpty()) { + int node = q.poll(); + visit++; + int colorIndex = colors.charAt(node) - 'a'; + count[node][colorIndex]++; + res = Math.max(res, count[node][colorIndex]); + + for (int nei : adj[node]) { + for (int c = 0; c < 26; c++) { + count[nei][c] = Math.max(count[nei][c], count[node][c]); + } + if (--indegree[nei] == 0) { + q.add(nei); + } + } + } + + return visit == n ? res : -1; + } +} +``` + +```cpp +class Solution { +public: + int largestPathValue(string colors, vector>& edges) { + int n = colors.size(); + vector> adj(n); + vector indegree(n); + vector> count(n, vector(26)); + + for (auto& edge : edges) { + adj[edge[0]].push_back(edge[1]); + indegree[edge[1]]++; + } + + queue q; + for (int i = 0; i < n; i++) { + if (indegree[i] == 0) { + q.push(i); + } + } + + int visit = 0, res = 0; + while (!q.empty()) { + int node = q.front();q.pop(); + visit++; + int colorIndex = colors[node] - 'a'; + count[node][colorIndex]++; + res = max(res, count[node][colorIndex]); + + for (int& nei : adj[node]) { + for (int c = 0; c < 26; c++) { + count[nei][c] = max(count[nei][c], count[node][c]); + } + if (--indegree[nei] == 0) { + q.push(nei); + } + } + } + + return visit == n ? res : -1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} colors + * @param {number[][]} edges + * @return {number} + */ + largestPathValue(colors, edges) { + const n = colors.length; + const adj = Array.from({ length: n }, () => []); + const indegree = new Array(n).fill(0); + const count = Array.from({ length: n }, () => new Array(26).fill(0)); + + for (const [u, v] of edges) { + adj[u].push(v); + indegree[v]++; + } + + const q = new Queue(); + for (let i = 0; i < n; i++) { + if (indegree[i] === 0) { + q.push(i); + } + } + + let visit = 0, res = 0; + while (!q.isEmpty()) { + const node = q.pop(); + visit++; + const colorIndex = colors.charCodeAt(node) - 'a'.charCodeAt(0); + count[node][colorIndex]++; + res = Math.max(res, count[node][colorIndex]); + + for (const nei of adj[node]) { + for (let c = 0; c < 26; c++) { + count[nei][c] = Math.max(count[nei][c], count[node][c]); + } + if (--indegree[nei] === 0) { + q.push(nei); + } + } + } + + return visit === n ? res : -1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(V + E)$ +* Space complexity: $O(V + E)$ + +> Where $V$ is the number of verticies and $E$ is the number of edges. \ No newline at end of file diff --git a/articles/largest-divisible-subset.md b/articles/largest-divisible-subset.md new file mode 100644 index 000000000..c5d8fa381 --- /dev/null +++ b/articles/largest-divisible-subset.md @@ -0,0 +1,738 @@ +## 1. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def largestDivisibleSubset(self, nums: List[int]) -> List[int]: + nums.sort() + cache = {} # (i, prevIndex) -> List + + def dfs(i, prevIndex): + if i == len(nums): + return [] + if (i, prevIndex) in cache: + return cache[(i, prevIndex)] + + res = dfs(i + 1, prevIndex) # Skip nums[i] + if prevIndex == -1 or nums[i] % nums[prevIndex] == 0: + tmp = [nums[i]] + dfs(i + 1, i) # Include nums[i] + res = tmp if len(tmp) > len(res) else res + + cache[(i, prevIndex)] = res + return res + + return dfs(0, -1) +``` + +```java +public class Solution { + private List[][] cache; + + public List largestDivisibleSubset(int[] nums) { + Arrays.sort(nums); + int n = nums.length; + cache = new ArrayList[n][n + 1]; + return dfs(0, -1, nums); + } + + private List dfs(int i, int prevIndex, int[] nums) { + if (i == nums.length) return new ArrayList<>(); + if (cache[i][prevIndex + 1] != null) return cache[i][prevIndex + 1]; + + List res = dfs(i + 1, prevIndex, nums); + + if (prevIndex == -1 || nums[i] % nums[prevIndex] == 0) { + List tmp = new ArrayList<>(); + tmp.add(nums[i]); + tmp.addAll(dfs(i + 1, i, nums)); + if (tmp.size() > res.size()) res = tmp; + } + + cache[i][prevIndex + 1] = res; + return res; + } +} +``` + +```cpp +class Solution { +private: + vector>> cache; + +public: + vector largestDivisibleSubset(vector& nums) { + sort(nums.begin(), nums.end()); + int n = nums.size(); + cache = vector>>(n, vector>(n + 1)); + return dfs(0, -1, nums); + } + + vector dfs(int i, int prevIndex, vector& nums) { + if (i == nums.size()) return {}; + if (!cache[i][prevIndex + 1].empty()) return cache[i][prevIndex + 1]; + + vector res = dfs(i + 1, prevIndex, nums); + + if (prevIndex == -1 || nums[i] % nums[prevIndex] == 0) { + vector tmp = {nums[i]}; + vector next = dfs(i + 1, i, nums); + tmp.insert(tmp.end(), next.begin(), next.end()); + if (tmp.size() > res.size()) res = tmp; + } + + return cache[i][prevIndex + 1] = res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number[]} + */ + largestDivisibleSubset(nums) { + nums.sort((a, b) => a - b); + const cache = new Map(); + + const dfs = (i, prevIndex) => { + if (i === nums.length) return []; + + let key = `${i},${prevIndex}`; + if (cache.has(key)) return cache.get(key); + + let res = dfs(i + 1, prevIndex); + if (prevIndex === -1 || nums[i] % nums[prevIndex] === 0) { + let tmp = [nums[i], ...dfs(i + 1, i)]; + if (tmp.length > res.length) res = tmp; + } + + cache.set(key, res); + return res; + }; + + return dfs(0, -1); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n ^ 2)$ + +--- + +## 2. Dynamic Programming (Top-Down) Space Optimized + +::tabs-start + +```python +class Solution: + def largestDivisibleSubset(self, nums: List[int]) -> List[int]: + nums.sort() + cache = {} + + def dfs(i): + if i in cache: + return cache[i] + + res = [nums[i]] + for j in range(i + 1, len(nums)): + if nums[j] % nums[i] == 0: + tmp = [nums[i]] + dfs(j) + if len(tmp) > len(res): + res = tmp + + cache[i] = res + return res + + res = [] + for i in range(len(nums)): + tmp = dfs(i) + if len(tmp) > len(res): + res = tmp + return res +``` + +```java +public class Solution { + private List[] cache; + + public List largestDivisibleSubset(int[] nums) { + Arrays.sort(nums); + int n = nums.length; + cache = new ArrayList[n]; + + List res = new ArrayList<>(); + for (int i = 0; i < n; i++) { + List tmp = dfs(i, nums); + if (tmp.size() > res.size()) { + res = tmp; + } + } + return res; + } + + private List dfs(int i, int[] nums) { + if (cache[i] != null) return cache[i]; + + List res = new ArrayList<>(); + res.add(nums[i]); + for (int j = i + 1; j < nums.length; j++) { + if (nums[j] % nums[i] == 0) { + List tmp = new ArrayList<>(); + tmp.add(nums[i]); + tmp.addAll(dfs(j, nums)); + + if (tmp.size() > res.size()) { + res = tmp; + } + } + } + return cache[i] = res; + } +} +``` + +```cpp +class Solution { +private: + vector> cache; + +public: + vector largestDivisibleSubset(vector& nums) { + sort(nums.begin(), nums.end()); + int n = nums.size(); + cache.resize(n, vector()); + + vector res; + for (int i = 0; i < n; i++) { + vector tmp = dfs(i, nums); + if (tmp.size() > res.size()) { + res = tmp; + } + } + return res; + } + + vector dfs(int i, vector& nums) { + if (!cache[i].empty()) return cache[i]; + + vector res = {nums[i]}; + for (int j = i + 1; j < nums.size(); j++) { + if (nums[j] % nums[i] == 0) { + vector tmp = {nums[i]}; + vector next = dfs(j, nums); + tmp.insert(tmp.end(), next.begin(), next.end()); + + if (tmp.size() > res.size()) { + res = tmp; + } + } + } + return cache[i] = res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number[]} + */ + largestDivisibleSubset(nums) { + nums.sort((a, b) => a - b); + const n = nums.length; + const cache = new Array(n).fill(null); + + const dfs = (i) => { + if (cache[i] !== null) return cache[i]; + + let res = [nums[i]]; + for (let j = i + 1; j < n; j++) { + if (nums[j] % nums[i] === 0) { + let tmp = [nums[i], ...dfs(j)]; + if (tmp.length > res.length) { + res = tmp; + } + } + } + return (cache[i] = res); + }; + + let res = []; + for (let i = 0; i < n; i++) { + let tmp = dfs(i); + if (tmp.length > res.length) { + res = tmp; + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n)$ + +--- + +## 3. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def largestDivisibleSubset(self, nums: List[int]) -> List[int]: + nums.sort() + dp = [[num] for num in nums] # dp[i] = longest start at i + res = [] + for i in range(len(nums) - 1, -1, -1): + for j in range(i + 1, len(nums)): + if nums[j] % nums[i] == 0: + tmp = [nums[i]] + dp[j] + dp[i] = tmp if len(tmp) > len(dp[i]) else dp[i] + res = dp[i] if len(dp[i]) > len(res) else res + return res +``` + +```java +public class Solution { + public List largestDivisibleSubset(int[] nums) { + Arrays.sort(nums); + int n = nums.length; + List[] dp = new ArrayList[n]; + List res = new ArrayList<>(); + + for (int i = n - 1; i >= 0; i--) { + dp[i] = new ArrayList<>(); + dp[i].add(nums[i]); + + for (int j = i + 1; j < n; j++) { + if (nums[j] % nums[i] == 0) { + List tmp = new ArrayList<>(); + tmp.add(nums[i]); + tmp.addAll(dp[j]); + + if (tmp.size() > dp[i].size()) { + dp[i] = tmp; + } + } + } + if (dp[i].size() > res.size()) { + res = dp[i]; + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + vector largestDivisibleSubset(vector& nums) { + sort(nums.begin(), nums.end()); + int n = nums.size(); + vector> dp(n); + vector res; + + for (int i = n - 1; i >= 0; i--) { + dp[i].push_back(nums[i]); + + for (int j = i + 1; j < n; j++) { + if (nums[j] % nums[i] == 0) { + vector tmp = dp[j]; + tmp.insert(tmp.begin(), nums[i]); + + if (tmp.size() > dp[i].size()) { + dp[i] = tmp; + } + } + } + if (dp[i].size() > res.size()) { + res = dp[i]; + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number[]} + */ + largestDivisibleSubset(nums) { + nums.sort((a, b) => a - b); + const n = nums.length; + const dp = new Array(n).fill(0).map(() => []); + let res = []; + + for (let i = n - 1; i >= 0; i--) { + dp[i] = [nums[i]]; + + for (let j = i + 1; j < n; j++) { + if (nums[j] % nums[i] === 0) { + let tmp = [nums[i], ...dp[j]]; + + if (tmp.length > dp[i].length) { + dp[i] = tmp; + } + } + } + if (dp[i].length > res.length) { + res = dp[i]; + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n)$ + +--- + +## 4. Dynamic Programming (Top-Down) + Tracing + +::tabs-start + +```python +class Solution: + def largestDivisibleSubset(self, nums: List[int]) -> List[int]: + nums.sort() + n = len(nums) + dp = [[-1, -1] for _ in range(n)] # dp[i] = [maxLen, prevIdx] + + def dfs(i): + if dp[i][0] != -1: + return dp[i][0] + + dp[i][0] = 1 + for j in range(i + 1, n): + if nums[j] % nums[i] == 0: + length = dfs(j) + 1 + if length > dp[i][0]: + dp[i][0] = length + dp[i][1] = j + + return dp[i][0] + + max_len, start_index = 1, 0 + for i in range(n): + if dfs(i) > max_len: + max_len = dfs(i) + start_index = i + + subset = [] + while start_index != -1: + subset.append(nums[start_index]) + start_index = dp[start_index][1] + + return subset +``` + +```java +public class Solution { + private int[][] dp; + + public List largestDivisibleSubset(int[] nums) { + Arrays.sort(nums); + int n = nums.length; + dp = new int[n][2]; + for (int i = 0; i < n; i++) { + dp[i][0] = -1; + dp[i][1] = -1; + } + + int maxLen = 1, startIndex = 0; + for (int i = 0; i < n; i++) { + if (dfs(i, nums) > maxLen) { + maxLen = dp[i][0]; + startIndex = i; + } + } + + List subset = new ArrayList<>(); + while (startIndex != -1) { + subset.add(nums[startIndex]); + startIndex = dp[startIndex][1]; + } + return subset; + } + + private int dfs(int i, int[] nums) { + if (dp[i][0] != -1) return dp[i][0]; + + dp[i][0] = 1; + for (int j = i + 1; j < nums.length; j++) { + if (nums[j] % nums[i] == 0) { + int length = dfs(j, nums) + 1; + if (length > dp[i][0]) { + dp[i][0] = length; + dp[i][1] = j; + } + } + } + return dp[i][0]; + } +} +``` + +```cpp +class Solution { + vector> dp; + +public: + vector largestDivisibleSubset(vector& nums) { + sort(nums.begin(), nums.end()); + int n = nums.size(); + dp.assign(n, vector(2, -1)); + + int maxLen = 1, startIndex = 0; + for (int i = 0; i < n; i++) { + if (dfs(i, nums) > maxLen) { + maxLen = dp[i][0]; + startIndex = i; + } + } + + vector subset; + while (startIndex != -1) { + subset.push_back(nums[startIndex]); + startIndex = dp[startIndex][1]; + } + return subset; + } + +private: + int dfs(int i, vector& nums) { + if (dp[i][0] != -1) return dp[i][0]; + + dp[i][0] = 1; + for (int j = i + 1; j < nums.size(); j++) { + if (nums[j] % nums[i] == 0) { + int length = dfs(j, nums) + 1; + if (length > dp[i][0]) { + dp[i][0] = length; + dp[i][1] = j; + } + } + } + return dp[i][0]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number[]} + */ + largestDivisibleSubset(nums) { + nums.sort((a, b) => a - b); + let n = nums.length; + let dp = Array.from({ length: n }, () => [-1, -1]); // dp[i] = [maxLen, prevIdx] + + const dfs = (i) => { + if (dp[i][0] !== -1) return dp[i][0]; + + dp[i][0] = 1; + for (let j = i + 1; j < n; j++) { + if (nums[j] % nums[i] === 0) { + let length = dfs(j) + 1; + if (length > dp[i][0]) { + dp[i][0] = length; + dp[i][1] = j; + } + } + } + return dp[i][0]; + }; + + let maxLen = 1, startIndex = 0; + for (let i = 0; i < n; i++) { + if (dfs(i) > maxLen) { + maxLen = dfs(i); + startIndex = i; + } + } + + let subset = []; + while (startIndex !== -1) { + subset.push(nums[startIndex]); + startIndex = dp[startIndex][1]; + } + return subset; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n)$ + +--- + +## 5. Dynamic Programming (Bottom-Up) + Tracing + +::tabs-start + +```python +class Solution: + def largestDivisibleSubset(self, nums: List[int]) -> List[int]: + nums.sort() + n = len(nums) + dp = [[1, -1] for _ in range(n)] # dp[i] = [maxLen, prevIdx] + + max_len, start_index = 1, 0 + + for i in range(n): + for j in range(i): + if nums[i] % nums[j] == 0 and dp[j][0] + 1 > dp[i][0]: + dp[i][0] = dp[j][0] + 1 + dp[i][1] = j + + if dp[i][0] > max_len: + max_len = dp[i][0] + start_index = i + + subset = [] + while start_index != -1: + subset.append(nums[start_index]) + start_index = dp[start_index][1] + return subset +``` + +```java +public class Solution { + public List largestDivisibleSubset(int[] nums) { + Arrays.sort(nums); + int n = nums.length; + int[][] dp = new int[n][2]; // dp[i] = {maxLen, prevIdx} + + int maxLen = 1, startIndex = 0; + for (int i = 0; i < n; i++) { + dp[i][0] = 1; + dp[i][1] = -1; + for (int j = 0; j < i; j++) { + if (nums[i] % nums[j] == 0 && dp[j][0] + 1 > dp[i][0]) { + dp[i][0] = dp[j][0] + 1; + dp[i][1] = j; + } + } + + if (dp[i][0] > maxLen) { + maxLen = dp[i][0]; + startIndex = i; + } + } + + List subset = new ArrayList<>(); + while (startIndex != -1) { + subset.add(nums[startIndex]); + startIndex = dp[startIndex][1]; + } + return subset; + } +} +``` + +```cpp +class Solution { +public: + vector largestDivisibleSubset(vector& nums) { + sort(nums.begin(), nums.end()); + int n = nums.size(); + vector> dp(n, vector(2, -1)); // dp[i] = {maxLen, prevIdx} + + int maxLen = 1, startIndex = 0; + for (int i = 0; i < n; i++) { + dp[i][0] = 1; + dp[i][1] = -1; + for (int j = 0; j < i; j++) { + if (nums[i] % nums[j] == 0 && dp[j][0] + 1 > dp[i][0]) { + dp[i][0] = dp[j][0] + 1; + dp[i][1] = j; + } + } + + if (dp[i][0] > maxLen) { + maxLen = dp[i][0]; + startIndex = i; + } + } + + vector subset; + while (startIndex != -1) { + subset.push_back(nums[startIndex]); + startIndex = dp[startIndex][1]; + } + return subset; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number[]} + */ + largestDivisibleSubset(nums) { + nums.sort((a, b) => a - b); + let n = nums.length; + let dp = Array.from({ length: n }, () => [1, -1]); // dp[i] = [maxLen, prevIdx] + + let maxLen = 1, startIndex = 0; + for (let i = 0; i < n; i++) { + for (let j = 0; j < i; j++) { + if (nums[i] % nums[j] === 0 && dp[j][0] + 1 > dp[i][0]) { + dp[i][0] = dp[j][0] + 1; + dp[i][1] = j; + } + } + + if (dp[i][0] > maxLen) { + maxLen = dp[i][0]; + startIndex = i; + } + } + + let subset = []; + while (startIndex !== -1) { + subset.push(nums[startIndex]); + startIndex = dp[startIndex][1]; + } + return subset; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n)$ \ No newline at end of file diff --git a/articles/largest-submatrix-with-rearrangements.md b/articles/largest-submatrix-with-rearrangements.md new file mode 100644 index 000000000..bebc4c94e --- /dev/null +++ b/articles/largest-submatrix-with-rearrangements.md @@ -0,0 +1,522 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def largestSubmatrix(self, matrix: List[List[int]]) -> int: + ROWS, COLS = len(matrix), len(matrix[0]) + res = 0 + + for start_row in range(ROWS): + ones = deque(list(range(COLS))) + + for r in range(start_row, ROWS): + if not ones: + break + for _ in range(len(ones)): + c = ones.popleft() + if matrix[r][c] == 1: + ones.append(c) + + res = max(res, len(ones) * (r - start_row + 1)) + + return res +``` + +```java +public class Solution { + public int largestSubmatrix(int[][] matrix) { + int ROWS = matrix.length, COLS = matrix[0].length; + int res = 0; + + for (int startRow = 0; startRow < ROWS; startRow++) { + Queue ones = new LinkedList<>(); + for (int c = 0; c < COLS; c++) { + ones.add(c); + } + + for (int r = startRow; r < ROWS; r++) { + if (ones.isEmpty()) break; + + for (int i = ones.size(); i > 0; i--) { + int c = ones.poll(); + if (matrix[r][c] == 1) { + ones.add(c); + } + } + + res = Math.max(res, ones.size() * (r - startRow + 1)); + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int largestSubmatrix(vector>& matrix) { + int ROWS = matrix.size(), COLS = matrix[0].size(); + int res = 0; + + for (int startRow = 0; startRow < ROWS; startRow++) { + queue ones; + for (int c = 0; c < COLS; c++) { + ones.push(c); + } + + for (int r = startRow; r < ROWS; r++) { + if (ones.empty()) break; + + for (int i = ones.size(); i > 0; i--) { + int c = ones.front(); ones.pop(); + if (matrix[r][c] == 1) { + ones.push(c); + } + } + + res = max(res, (int)ones.size() * (r - startRow + 1)); + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} matrix + * @return {number} + */ + largestSubmatrix(matrix) { + const ROWS = matrix.length, COLS = matrix[0].length; + let res = 0; + + for (let startRow = 0; startRow < ROWS; startRow++) { + const ones = new Queue(); + for (let c = 0; c < COLS; c++) { + ones.push(c); + } + + for (let r = startRow; r < ROWS; r++) { + if (ones.isEmpty()) break; + + for (let i = ones.size(); i > 0; i--) { + let c = ones.pop(); + if (matrix[r][c] === 1) { + ones.push(c); + } + } + + res = Math.max(res, ones.size() * (r - startRow + 1)); + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * n ^ 2)$ +* Space complexity: $O(n)$ + +> Where $m$ is the number of rows and $n$ is the number of columns. + +--- + +## 2. Greedy + Sorting + +::tabs-start + +```python +class Solution: + def largestSubmatrix(self, matrix: List[List[int]]) -> int: + ROWS, COLS = len(matrix), len(matrix[0]) + res = 0 + prev_heights = [0] * COLS + + for r in range(ROWS): + heights = matrix[r][:] + for c in range(COLS): + if heights[c] > 0: + heights[c] += prev_heights[c] + + sorted_heights = sorted(heights, reverse=True) + for i in range(COLS): + res = max(res, (i + 1) * sorted_heights[i]) + + prev_heights = heights + + return res +``` + +```java +public class Solution { + public int largestSubmatrix(int[][] matrix) { + int ROWS = matrix.length, COLS = matrix[0].length; + int res = 0; + int[] prevHeights = new int[COLS]; + + for (int r = 0; r < ROWS; r++) { + int[] heights = Arrays.copyOf(matrix[r], COLS); + int[] sortedHgts = Arrays.copyOf(matrix[r], COLS); + + for (int c = 0; c < COLS; c++) { + if (heights[c] > 0) { + heights[c] += prevHeights[c]; + sortedHgts[c] = heights[c]; + } + } + + Arrays.sort(sortedHgts); + for (int i = COLS - 1; i >= 0; i--) { + res = Math.max(res, (COLS - i) * sortedHgts[i]); + } + + prevHeights = heights; + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int largestSubmatrix(vector>& matrix) { + int ROWS = matrix.size(), COLS = matrix[0].size(); + int res = 0; + vector prevHeights(COLS); + + for (int r = 0; r < ROWS; r++) { + vector heights = matrix[r]; + vector sortedHgts = matrix[r]; + + for (int c = 0; c < COLS; c++) { + if (heights[c] > 0) { + heights[c] += prevHeights[c]; + sortedHgts[c] = heights[c]; + } + } + + sort(sortedHgts.begin(), sortedHgts.end(), greater()); + for (int i = 0; i < COLS; i++) { + res = max(res, (i + 1) * sortedHgts[i]); + } + + prevHeights = heights; + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} matrix + * @return {number} + */ + largestSubmatrix(matrix) { + const ROWS = matrix.length, COLS = matrix[0].length; + let res = 0; + let prevHeights = new Array(COLS).fill(0); + + for (let r = 0; r < ROWS; r++) { + let heights = [...matrix[r]]; + let sortedHgts = [...matrix[r]]; + + for (let c = 0; c < COLS; c++) { + if (heights[c] > 0) { + heights[c] += prevHeights[c]; + sortedHgts[c] = heights[c]; + } + } + + sortedHgts.sort((a, b) => b - a); + for (let i = 0; i < COLS; i++) { + res = Math.max(res, (i + 1) * sortedHgts[i]); + } + + prevHeights = heights; + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * n \log n)$ +* Space complexity: $O(n)$ + +> Where $m$ is the number of rows and $n$ is the number of columns. + +--- + +## 3. Greedy + Sorting (Overwriting the Input) + +::tabs-start + +```python +class Solution: + def largestSubmatrix(self, matrix: List[List[int]]) -> int: + ROWS, COLS = len(matrix), len(matrix[0]) + res = 0 + + for r in range(1, ROWS): + for c in range(COLS): + if matrix[r][c]: + matrix[r][c] += matrix[r - 1][c] + + for r in range(ROWS): + matrix[r].sort(reverse=True) + for i in range(COLS): + res = max(res, (i + 1) * matrix[r][i]) + + return res +``` + +```java +public class Solution { + public int largestSubmatrix(int[][] matrix) { + int ROWS = matrix.length, COLS = matrix[0].length; + int res = 0; + + for (int r = 1; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + if (matrix[r][c] > 0) { + matrix[r][c] += matrix[r - 1][c]; + } + } + } + + for (int r = 0; r < ROWS; r++) { + Arrays.sort(matrix[r]); + for (int i = 0; i < COLS; i++) { + res = Math.max(res, (COLS - i) * matrix[r][i]); + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int largestSubmatrix(vector>& matrix) { + int ROWS = matrix.size(), COLS = matrix[0].size(); + int res = 0; + + for (int r = 1; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + if (matrix[r][c] > 0) { + matrix[r][c] += matrix[r - 1][c]; + } + } + } + + for (int r = 0; r < ROWS; r++) { + sort(matrix[r].begin(), matrix[r].end(), greater()); + for (int i = 0; i < COLS; i++) { + res = max(res, (i + 1) * matrix[r][i]); + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} matrix + * @return {number} + */ + largestSubmatrix(matrix) { + const ROWS = matrix.length, COLS = matrix[0].length; + let res = 0; + + for (let r = 1; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (matrix[r][c] > 0) { + matrix[r][c] += matrix[r - 1][c]; + } + } + } + + for (let r = 0; r < ROWS; r++) { + matrix[r].sort((a, b) => b - a); + for (let i = 0; i < COLS; i++) { + res = Math.max(res, (i + 1) * matrix[r][i]); + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * n \log n)$ +* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algoirhtm. + +> Where $m$ is the number of rows and $n$ is the number of columns. + +--- + +## 4. Greedy + +::tabs-start + +```python +class Solution: + def largestSubmatrix(self, matrix: List[List[int]]) -> int: + ROWS, COLS = len(matrix), len(matrix[0]) + res = 0 + prevHeights = [] + + for r in range(ROWS): + heights = [] + for c in prevHeights: + if matrix[r][c]: + matrix[r][c] += matrix[r - 1][c] + heights.append(c) + + for c in range(COLS): + if matrix[r][c] == 1: + heights.append(c) + + for i, c in enumerate(heights): + res = max(res, (i + 1) * matrix[r][c]) + + prevHeights = heights + + return res +``` + +```java +public class Solution { + public int largestSubmatrix(int[][] matrix) { + int ROWS = matrix.length, COLS = matrix[0].length; + int res = 0; + List prevHeights = new ArrayList<>(); + + for (int r = 0; r < ROWS; r++) { + List heights = new ArrayList<>(); + + for (int c : prevHeights) { + if (matrix[r][c] == 1) { + matrix[r][c] += matrix[r - 1][c]; + heights.add(c); + } + } + + for (int c = 0; c < COLS; c++) { + if (matrix[r][c] == 1) { + heights.add(c); + } + } + + for (int i = 0; i < heights.size(); i++) { + res = Math.max(res, (i + 1) * matrix[r][heights.get(i)]); + } + + prevHeights = heights; + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int largestSubmatrix(vector>& matrix) { + int ROWS = matrix.size(), COLS = matrix[0].size(), res = 0; + vector prevHeights; + + for (int r = 0; r < ROWS; r++) { + vector heights; + + for (int c : prevHeights) { + if (matrix[r][c] == 1) { + matrix[r][c] += matrix[r - 1][c]; + heights.push_back(c); + } + } + + for (int c = 0; c < COLS; c++) { + if (matrix[r][c] == 1) { + heights.push_back(c); + } + } + + for (int i = 0; i < heights.size(); i++) { + res = max(res, (i + 1) * matrix[r][heights[i]]); + } + + prevHeights = heights; + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} matrix + * @return {number} + */ + largestSubmatrix(matrix) { + const ROWS = matrix.length, COLS = matrix[0].length; + let res = 0, prevHeights = []; + + for (let r = 0; r < ROWS; r++) { + let heights = []; + + for (let c of prevHeights) { + if (matrix[r][c] === 1) { + matrix[r][c] += matrix[r - 1][c]; + heights.push(c); + } + } + + for (let c = 0; c < COLS; c++) { + if (matrix[r][c] === 1) { + heights.push(c); + } + } + + for (let i = 0; i < heights.length; i++) { + res = Math.max(res, (i + 1) * matrix[r][heights[i]]); + } + + prevHeights = heights; + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * n)$ +* Space complexity: $O(n)$ + +> Where $m$ is the number of rows and $n$ is the number of columns. \ No newline at end of file diff --git a/articles/maximize-score-after-n-operations.md b/articles/maximize-score-after-n-operations.md new file mode 100644 index 000000000..bf90e9d55 --- /dev/null +++ b/articles/maximize-score-after-n-operations.md @@ -0,0 +1,629 @@ +## 1. Brute Force (Backtracking) + +::tabs-start + +```python +class Solution: + def maxScore(self, nums: List[int]) -> int: + N = len(nums) + visit = [False] * N + + def dfs(n): + if n > (N // 2): + return 0 + + res = 0 + for i in range(N): + if visit[i]: + continue + visit[i] = True + for j in range(i + 1, N): + if visit[j]: + continue + visit[j] = True + g = gcd(nums[i], nums[j]) + res = max(res, n * g + dfs(n + 1)) + visit[j] = False + visit[i] = False + + return res + + return dfs(1) +``` + +```java +public class Solution { + public int maxScore(int[] nums) { + int N = nums.length; + boolean[] visit = new boolean[N]; + return dfs(nums, visit, 1, N); + } + + private int dfs(int[] nums, boolean[] visit, int n, int N) { + if (n > N / 2) { + return 0; + } + + int res = 0; + for (int i = 0; i < N; i++) { + if (visit[i]) continue; + visit[i] = true; + for (int j = i + 1; j < N; j++) { + if (visit[j]) continue; + visit[j] = true; + int g = gcd(nums[i], nums[j]); + res = Math.max(res, n * g + dfs(nums, visit, n + 1, N)); + visit[j] = false; + } + visit[i] = false; + } + + return res; + } + + private int gcd(int a, int b) { + return b == 0 ? a : gcd(b, a % b); + } +} +``` + +```cpp +class Solution { +public: + int maxScore(vector& nums) { + int N = nums.size(); + vector visit(N, false); + return dfs(nums, visit, 1, N); + } + +private: + int dfs(vector& nums, vector& visit, int n, int N) { + if (n > N / 2) { + return 0; + } + + int res = 0; + for (int i = 0; i < N; i++) { + if (visit[i]) continue; + visit[i] = true; + for (int j = i + 1; j < N; j++) { + if (visit[j]) continue; + visit[j] = true; + int g = gcd(nums[i], nums[j]); + res = max(res, n * g + dfs(nums, visit, n + 1, N)); + visit[j] = false; + } + visit[i] = false; + } + + return res; + } + + int gcd(int a, int b) { + return b == 0 ? a : gcd(b, a % b); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + maxScore(nums) { + const N = nums.length; + const visit = new Array(N).fill(false); + + const gcd = (a, b) => { + return b === 0 ? a : gcd(b, a % b); + }; + const dfs = (n) => { + if (n > N / 2) { + return 0; + } + + let res = 0; + for (let i = 0; i < N; i++) { + if (visit[i]) continue; + visit[i] = true; + for (let j = i + 1; j < N; j++) { + if (visit[j]) continue; + visit[j] = true; + let g = gcd(nums[i], nums[j]); + res = Math.max(res, n * g + dfs(n + 1)); + visit[j] = false; + } + visit[i] = false; + } + + return res; + }; + + return dfs(1); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ n * \log m)$ +* Space complexity: $O(n)$ + +> Where $n$ is the size of the array $nums$ and $m$ is the maximum element in the array. + +--- + +## 2. Bitmask DP (Top-Down) - I + +::tabs-start + +```python +class Solution: + def maxScore(self, nums: List[int]) -> int: + cache = collections.defaultdict(int) + + def dfs(mask, op): + if mask in cache: + return cache[mask] + + for i in range(len(nums)): + for j in range(i + 1, len(nums)): + if (1 << i) & mask or (1 << j) & mask: + continue + + newMask = mask | (1 << i) | (1 << j) + score = op * math.gcd(nums[i], nums[j]) + cache[mask] = max( + cache[mask], + score + dfs(newMask, op + 1) + ) + + return cache[mask] + + return dfs(0, 1) +``` + +```java +public class Solution { + private Map cache; + + public int maxScore(int[] nums) { + cache = new HashMap<>(); + return dfs(0, 1, nums); + } + + private int dfs(int mask, int op, int[] nums) { + if (cache.containsKey(mask)) { + return cache.get(mask); + } + + int maxScore = 0; + int n = nums.length; + for (int i = 0; i < n; i++) { + if ((mask & (1 << i)) != 0) continue; + for (int j = i + 1; j < n; j++) { + if ((mask & (1 << j)) != 0) continue; + int newMask = mask | (1 << i) | (1 << j); + int score = op * gcd(nums[i], nums[j]) + dfs(newMask, op + 1, nums); + maxScore = Math.max(maxScore, score); + } + } + + cache.put(mask, maxScore); + return maxScore; + } + + private int gcd(int a, int b) { + return b == 0 ? a : gcd(b, a % b); + } +} +``` + +```cpp +class Solution { +public: + int maxScore(vector& nums) { + return dfs(0, 1, nums); + } + +private: + unordered_map cache; + + int dfs(int mask, int op, vector& nums) { + if (cache.count(mask)) { + return cache[mask]; + } + + int maxScore = 0; + int n = nums.size(); + for (int i = 0; i < n; i++) { + if ((mask & (1 << i)) != 0) continue; + for (int j = i + 1; j < n; j++) { + if ((mask & (1 << j)) != 0) continue; + int newMask = mask | (1 << i) | (1 << j); + int score = op * gcd(nums[i], nums[j]) + dfs(newMask, op + 1, nums); + maxScore = max(maxScore, score); + } + } + + return cache[mask] = maxScore; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + maxScore(nums) { + const cache = new Map(); + + const gcd = (a, b) => (b === 0 ? a : gcd(b, a % b)); + + const dfs = (mask, op) => { + if (cache.has(mask)) { + return cache.get(mask); + } + + let maxScore = 0; + const n = nums.length; + for (let i = 0; i < n; i++) { + if ((mask & (1 << i)) !== 0) continue; + for (let j = i + 1; j < n; j++) { + if ((mask & (1 << j)) !== 0) continue; + let newMask = mask | (1 << i) | (1 << j); + let score = op * gcd(nums[i], nums[j]) + dfs(newMask, op + 1); + maxScore = Math.max(maxScore, score); + } + } + + cache.set(mask, maxScore); + return maxScore; + }; + + + return dfs(0, 1); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2 * 2 ^ n * \log m)$ +* Space complexity: $O(2 ^ n)$ + +> Where $n$ is the size of the array $nums$ and $m$ is the maximum element in the array. + +--- + +## 3. Bitmask DP (Top-Down) - II + +::tabs-start + +```python +class Solution: + def maxScore(self, nums: List[int]) -> int: + n = len(nums) + GCD = [[0] * n for _ in range(n)] + for i in range(n): + for j in range(i + 1, n): + GCD[i][j] = gcd(nums[i], nums[j]) + + dp = [-1] * (1 << n) + def dfs(mask, op): + if dp[mask] != -1: + return dp[mask] + + max_score = 0 + for i in range(n): + if mask & (1 << i): + continue + for j in range(i + 1, n): + if mask & (1 << j): + continue + new_mask = mask | (1 << i) | (1 << j) + max_score = max( + max_score, + op * GCD[i][j] + dfs(new_mask, op + 1) + ) + + dp[mask] = max_score + return max_score + + return dfs(0, 1) +``` + +```java +public class Solution { + private int[][] GCD; + private int[] dp; + + public int maxScore(int[] nums) { + int n = nums.length; + GCD = new int[n][n]; + dp = new int[1 << n]; + Arrays.fill(dp, -1); + + for (int i = 0; i < n; i++) { + for (int j = i + 1; j < n; j++) { + GCD[i][j] = gcd(nums[i], nums[j]); + } + } + + return (int) dfs(0, 1, nums); + } + + private int dfs(int mask, int op, int[] nums) { + if (dp[mask] != -1) return dp[mask]; + + int maxScore = 0; + for (int i = 0; i < nums.length; i++) { + if ((mask & (1 << i)) != 0) continue; + for (int j = i + 1; j < nums.length; j++) { + if ((mask & (1 << j)) != 0) continue; + int newMask = mask | (1 << i) | (1 << j); + maxScore = Math.max( + maxScore, + op * GCD[i][j] + dfs(newMask, op + 1, nums) + ); + } + } + return dp[mask] = maxScore; + } + + private int gcd(int a, int b) { + return b == 0 ? a : gcd(b, a % b); + } +} +``` + +```cpp +class Solution { +public: + int maxScore(vector& nums) { + int n = nums.size(); + GCD.assign(n, vector(n, 0)); + dp.assign(1 << n, -1); + + for (int i = 0; i < n; i++) { + for (int j = i + 1; j < n; j++) { + GCD[i][j] = gcd(nums[i], nums[j]); + } + } + + return dfs(0, 1, nums); + } + +private: + vector> GCD; + vector dp; + + int dfs(int mask, int op, vector& nums) { + if (dp[mask] != -1) return dp[mask]; + + int maxScore = 0; + for (int i = 0; i < nums.size(); i++) { + if (mask & (1 << i)) continue; + for (int j = i + 1; j < nums.size(); j++) { + if (mask & (1 << j)) continue; + int newMask = mask | (1 << i) | (1 << j); + maxScore = max( + maxScore, + op * GCD[i][j] + dfs(newMask, op + 1, nums) + ); + } + } + return dp[mask] = maxScore; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + maxScore(nums) { + const n = nums.length; + const GCD = Array.from({ length: n }, () => Array(n).fill(0)); + const dp = Array(1 << n).fill(-1); + + const gcd = (a, b) => (b === 0 ? a : gcd(b, a % b)); + for (let i = 0; i < n; i++) { + for (let j = i + 1; j < n; j++) { + GCD[i][j] = gcd(nums[i], nums[j]); + } + } + + const dfs = (mask, op) => { + if (dp[mask] !== -1) return dp[mask]; + + let maxScore = 0; + for (let i = 0; i < n; i++) { + if (mask & (1 << i)) continue; + for (let j = i + 1; j < n; j++) { + if (mask & (1 << j)) continue; + const newMask = mask | (1 << i) | (1 << j); + maxScore = Math.max( + maxScore, + op * GCD[i][j] + dfs(newMask, op + 1) + ); + } + } + return dp[mask] = maxScore; + }; + + return dfs(0, 1); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2 * (2 ^ n + \log m))$ +* Space complexity: $O(n ^ 2 + 2 ^ n)$ + +> Where $n$ is the size of the array $nums$ and $m$ is the maximum element in the array. + +--- + +## 4. Bitmask DP (Bottom-Up) + +::tabs-start + +```python +class Solution: + def maxScore(self, nums: List[int]) -> int: + n = len(nums) + N = 1 << n + GCD = [[0] * n for _ in range(n)] + for i in range(n): + for j in range(i + 1, n): + GCD[i][j] = gcd(nums[i], nums[j]) + + dp = [0] * N + for mask in range(N - 1, -1, -1): + bits = bin(mask).count('1') + if bits % 2 == 1: + continue + op = bits // 2 + 1 + + for i in range(n): + if mask & (1 << i): + continue + for j in range(i + 1, n): + if mask & (1 << j): + continue + new_mask = mask | (1 << i) | (1 << j) + dp[mask] = max(dp[mask], op * GCD[i][j] + dp[new_mask]) + + return dp[0] +``` + +```java +public class Solution { + public int maxScore(int[] nums) { + int n = nums.length; + int N = 1 << n; + int[][] GCD = new int[n][n]; + + for (int i = 0; i < n; i++) { + for (int j = i + 1; j < n; j++) { + GCD[i][j] = gcd(nums[i], nums[j]); + } + } + + int[] dp = new int[N]; + for (int mask = N - 1; mask >= 0; mask--) { + int bits = Integer.bitCount(mask); + if (bits % 2 == 1) continue; + int op = bits / 2 + 1; + + for (int i = 0; i < n; i++) { + if ((mask & (1 << i)) != 0) continue; + for (int j = i + 1; j < n; j++) { + if ((mask & (1 << j)) != 0) continue; + int newMask = mask | (1 << i) | (1 << j); + dp[mask] = Math.max(dp[mask], op * GCD[i][j] + dp[newMask]); + } + } + } + return dp[0]; + } + + private int gcd(int a, int b) { + return b == 0 ? a : gcd(b, a % b); + } +} +``` + +```cpp +class Solution { +public: + int maxScore(vector& nums) { + int n = nums.size(); + int N = 1 << n; + vector> GCD(n, vector(n, 0)); + + for (int i = 0; i < n; i++) { + for (int j = i + 1; j < n; j++) { + GCD[i][j] = __gcd(nums[i], nums[j]); + } + } + + vector dp(N, 0); + for (int mask = N - 1; mask >= 0; mask--) { + int bits = __builtin_popcount(mask); + if (bits % 2 == 1) continue; + int op = bits / 2 + 1; + + for (int i = 0; i < n; i++) { + if (mask & (1 << i)) continue; + for (int j = i + 1; j < n; j++) { + if (mask & (1 << j)) continue; + int newMask = mask | (1 << i) | (1 << j); + dp[mask] = max(dp[mask], op * GCD[i][j] + dp[newMask]); + } + } + } + return dp[0]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + maxScore(nums) { + const n = nums.length; + const N = 1 << n; + const GCD = Array.from({ length: n }, () => Array(n).fill(0)); + + const gcd = (a, b) => (b === 0 ? a : gcd(b, a % b)); + for (let i = 0; i < n; i++) { + for (let j = i + 1; j < n; j++) { + GCD[i][j] = gcd(nums[i], nums[j]); + } + } + + const dp = Array(N).fill(0); + for (let mask = N - 1; mask >= 0; mask--) { + let bits = mask.toString(2).split("0").join("").length; + if (bits % 2 === 1) continue; + let op = bits / 2 + 1; + + for (let i = 0; i < n; i++) { + if ((mask & (1 << i)) !== 0) continue; + for (let j = i + 1; j < n; j++) { + if ((mask & (1 << j)) !== 0) continue; + let newMask = mask | (1 << i) | (1 << j); + dp[mask] = Math.max(dp[mask], op * GCD[i][j] + dp[newMask]); + } + } + } + return dp[0]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2 * (2 ^ n + \log m))$ +* Space complexity: $O(n ^ 2 + 2 ^ n)$ + +> Where $n$ is the size of the array $nums$ and $m$ is the maximum element in the array. \ No newline at end of file diff --git a/articles/maximum-element-after-decreasing-and-rearranging.md b/articles/maximum-element-after-decreasing-and-rearranging.md new file mode 100644 index 000000000..b7c01b0db --- /dev/null +++ b/articles/maximum-element-after-decreasing-and-rearranging.md @@ -0,0 +1,158 @@ +## 1. Greedy + Sorting + +::tabs-start + +```python +class Solution: + def maximumElementAfterDecrementingAndRearranging(self, arr: List[int]) -> int: + arr.sort() + prev = 0 + for num in arr: + prev = min(prev + 1, num) + return prev +``` + +```java +public class Solution { + public int maximumElementAfterDecrementingAndRearranging(int[] arr) { + Arrays.sort(arr); + int prev = 0; + for (int num : arr) { + prev = Math.min(prev + 1, num); + } + return prev; + } +} +``` + +```cpp +class Solution { +public: + int maximumElementAfterDecrementingAndRearranging(vector& arr) { + sort(arr.begin(), arr.end()); + int prev = 0; + for (int num : arr) { + prev = min(prev + 1, num); + } + return prev; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr + * @return {number} + */ + maximumElementAfterDecrementingAndRearranging(arr) { + arr.sort((a, b) => a - b); + let prev = 0; + for (let num of arr) { + prev = Math.min(prev + 1, num); + } + return prev; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. + +--- + +## 2. Greedy + +::tabs-start + +```python +class Solution: + def maximumElementAfterDecrementingAndRearranging(self, arr: List[int]) -> int: + n = len(arr) + count = [0] * (n + 1) + + for num in arr: + count[min(num, n)] += 1 + + prev = 1 + for num in range(2, n + 1): + prev = min(prev + count[num], num) + + return prev +``` + +```java +public class Solution { + public int maximumElementAfterDecrementingAndRearranging(int[] arr) { + int n = arr.length; + int[] count = new int[n + 1]; + + for (int num : arr) { + count[Math.min(num, n)]++; + } + + int prev = 1; + for (int num = 2; num <= n; num++) { + prev = Math.min(prev + count[num], num); + } + + return prev; + } +} +``` + +```cpp +class Solution { +public: + int maximumElementAfterDecrementingAndRearranging(vector& arr) { + int n = arr.size(); + vector count(n + 1, 0); + + for (int num : arr) { + count[min(num, n)]++; + } + + int prev = 1; + for (int num = 2; num <= n; num++) { + prev = min(prev + count[num], num); + } + + return prev; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr + * @return {number} + */ + maximumElementAfterDecrementingAndRearranging(arr) { + let n = arr.length; + let count = new Array(n + 1).fill(0); + + for (let num of arr) { + count[Math.min(num, n)]++; + } + + let prev = 1; + for (let num = 2; num <= n; num++) { + prev = Math.min(prev + count[num], num); + } + + return prev; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ \ No newline at end of file diff --git a/articles/maximum-length-of-a-concatenated-string-with-unique-characters.md b/articles/maximum-length-of-a-concatenated-string-with-unique-characters.md new file mode 100644 index 000000000..f8cdea423 --- /dev/null +++ b/articles/maximum-length-of-a-concatenated-string-with-unique-characters.md @@ -0,0 +1,857 @@ +## 1. Backtracking (Hash Set) + +::tabs-start + +```python +class Solution: + def maxLength(self, arr: List[str]) -> int: + charSet = set() + + def overlap(charSet, s): + prev = set() + for c in s: + if c in charSet or c in prev: + return True + prev.add(c) + return False + + def backtrack(i): + if i == len(arr): + return len(charSet) + + res = 0 + if not overlap(charSet, arr[i]): + for c in arr[i]: + charSet.add(c) + res = backtrack(i + 1) + for c in arr[i]: + charSet.remove(c) + + return max(res, backtrack(i + 1)) + + return backtrack(0) +``` + +```java +public class Solution { + public int maxLength(List arr) { + Set charSet = new HashSet<>(); + return backtrack(0, arr, charSet); + } + + private boolean overlap(Set charSet, String s) { + Set prev = new HashSet<>(); + for (char c : s.toCharArray()) { + if (charSet.contains(c) || prev.contains(c)) { + return true; + } + prev.add(c); + } + return false; + } + + private int backtrack(int i, List arr, Set charSet) { + if (i == arr.size()) { + return charSet.size(); + } + + int res = 0; + if (!overlap(charSet, arr.get(i))) { + for (char c : arr.get(i).toCharArray()) { + charSet.add(c); + } + res = backtrack(i + 1, arr, charSet); + for (char c : arr.get(i).toCharArray()) { + charSet.remove(c); + } + } + + return Math.max(res, backtrack(i + 1, arr, charSet)); + } +} +``` + +```cpp +class Solution { +public: + int maxLength(vector& arr) { + unordered_set charSet; + return backtrack(0, arr, charSet); + } + +private: + bool overlap(unordered_set& charSet, const string& s) { + unordered_set prev; + for (char c : s) { + if (charSet.count(c) || prev.count(c)) { + return true; + } + prev.insert(c); + } + return false; + } + + int backtrack(int i, vector& arr, unordered_set& charSet) { + if (i == arr.size()) { + return charSet.size(); + } + + int res = 0; + if (!overlap(charSet, arr[i])) { + for (char c : arr[i]) { + charSet.insert(c); + } + res = backtrack(i + 1, arr, charSet); + for (char c : arr[i]) { + charSet.erase(c); + } + } + + return max(res, backtrack(i + 1, arr, charSet)); + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} arr + * @return {number} + */ + maxLength(arr) { + let charSet = new Set(); + + const overlap = (charSet, s) => { + let prev = new Set(); + for (const c of s) { + if (charSet.has(c) || prev.has(c)) { + return true; + } + prev.add(c); + } + return false; + }; + + const backtrack = (i) => { + if (i === arr.length) { + return charSet.size; + } + + let res = 0; + if (!overlap(charSet, arr[i])) { + for (const c of arr[i]) { + charSet.add(c); + } + res = backtrack(i + 1); + for (const c of arr[i]) { + charSet.delete(c); + } + } + + return Math.max(res, backtrack(i + 1)); + }; + + return backtrack(0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * 2 ^ n)$ +* Space complexity: $O(n)$ for recursion stack. + +> Where $n$ is the number of strings and $m$ is the maximum length of a string. + +--- + +## 2. Backtracking (Boolean Array) + +::tabs-start + +```python +class Solution: + def maxLength(self, arr: List[str]) -> int: + charSet = [False] * 26 + + def getIdx(c): + return ord(c) - ord('a') + + def overlap(charSet, s): + for i in range(len(s)): + c = getIdx(s[i]) + if charSet[c]: + for j in range(i): + charSet[getIdx(s[j])] = False + return True + charSet[c] = True + return False + + def backtrack(i): + if i == len(arr): + return 0 + + res = 0 + if not overlap(charSet, arr[i]): + res = len(arr[i]) + backtrack(i + 1) + for c in arr[i]: + charSet[getIdx(c)] = False + return max(res, backtrack(i + 1)) + + return backtrack(0) +``` + +```java +public class Solution { + public int maxLength(List arr) { + boolean[] charSet = new boolean[26]; + return backtrack(0, arr, charSet); + } + + private int getIdx(char c) { + return c - 'a'; + } + + private boolean overlap(boolean[] charSet, String s) { + for (int i = 0; i < s.length(); i++) { + int c = getIdx(s.charAt(i)); + if (charSet[c]) { + for (int j = 0; j < i; j++) { + charSet[getIdx(s.charAt(j))] = false; + } + return true; + } + charSet[c] = true; + } + return false; + } + + private int backtrack(int i, List arr, boolean[] charSet) { + if (i == arr.size()) { + return 0; + } + + int res = 0; + if (!overlap(charSet, arr.get(i))) { + res = arr.get(i).length() + backtrack(i + 1, arr, charSet); + for (char c : arr.get(i).toCharArray()) { + charSet[getIdx(c)] = false; + } + } + return Math.max(res, backtrack(i + 1, arr, charSet)); + } +} +``` + +```cpp +class Solution { +public: + int maxLength(vector& arr) { + bool charSet[26] = {false}; + return backtrack(0, arr, charSet); + } + +private: + int getIdx(char c) { + return c - 'a'; + } + + bool overlap(bool charSet[], const string& s) { + for (int i = 0; i < s.length(); i++) { + int c = getIdx(s[i]); + if (charSet[c]) { + for (int j = 0; j < i; j++) { + charSet[getIdx(s[j])] = false; + } + return true; + } + charSet[c] = true; + } + return false; + } + + int backtrack(int i, vector& arr, bool charSet[]) { + if (i == arr.size()) { + return 0; + } + + int res = 0; + if (!overlap(charSet, arr[i])) { + res = arr[i].length() + backtrack(i + 1, arr, charSet); + for (char c : arr[i]) { + charSet[getIdx(c)] = false; + } + } + return max(res, backtrack(i + 1, arr, charSet)); + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} arr + * @return {number} + */ + maxLength(arr) { + let charSet = new Array(26).fill(false); + + const getIdx = (c) => c.charCodeAt(0) - 'a'.charCodeAt(0); + + const overlap = (charSet, s) => { + for (let i = 0; i < s.length; i++) { + let c = getIdx(s[i]); + if (charSet[c]) { + for (let j = 0; j < i; j++) { + charSet[getIdx(s[j])] = false; + } + return true; + } + charSet[c] = true; + } + return false; + }; + + const backtrack = (i) => { + if (i === arr.length) { + return 0; + } + + let res = 0; + if (!overlap(charSet, arr[i])) { + res = arr[i].length + backtrack(i + 1); + for (const c of arr[i]) { + charSet[getIdx(c)] = false; + } + } + return Math.max(res, backtrack(i + 1)); + }; + + return backtrack(0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * 2 ^ n)$ +* Space complexity: $O(n)$ for recursion stack. + +> Where $n$ is the number of strings and $m$ is the maximum length of a string. + +--- + +## 3. Recursion (Bit Mask) - I + +::tabs-start + +```python +class Solution: + def maxLength(self, arr: List[str]) -> int: + def getIdx(c): + return ord(c) - ord('a') + + A = [] + for s in arr: + cur = 0 + valid = True + for c in s: + if cur & (1 << getIdx(c)): + valid = False + break + cur |= (1 << getIdx(c)) + + if valid: + A.append([cur, len(s)]) + + def dfs(i, subSeq): + if i == len(A): + return 0 + + res = dfs(i + 1, subSeq) + + curSeq, length = A[i][0], A[i][1] + if (subSeq & curSeq) == 0: + res = max(res, length + dfs(i + 1, subSeq | curSeq)) + return res + + return dfs(0, 0) +``` + +```java +public class Solution { + public int maxLength(List arr) { + List A = new ArrayList<>(); + + for (String s : arr) { + int cur = 0; + boolean valid = true; + + for (char c : s.toCharArray()) { + if ((cur & (1 << (c - 'a'))) != 0) { + valid = false; + break; + } + cur |= (1 << (c - 'a')); + } + + if (valid) { + A.add(new int[]{cur, s.length()}); + } + } + + return dfs(0, 0, A); + } + + private int dfs(int i, int subSeq, List A) { + if (i == A.size()) { + return 0; + } + + int res = dfs(i + 1, subSeq, A); + + int curSeq = A.get(i)[0], length = A.get(i)[1]; + if ((subSeq & curSeq) == 0) { + res = Math.max(res, length + dfs(i + 1, subSeq | curSeq, A)); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int maxLength(vector& arr) { + vector> A; + + for (const string& s : arr) { + int cur = 0; + bool valid = true; + + for (char c : s) { + if (cur & (1 << (c - 'a'))) { + valid = false; + break; + } + cur |= (1 << (c - 'a')); + } + + if (valid) { + A.emplace_back(cur, s.length()); + } + } + + return dfs(0, 0, A); + } + +private: + int dfs(int i, int subSeq, vector>& A) { + if (i == A.size()) { + return 0; + } + + int res = dfs(i + 1, subSeq, A); + + int curSeq = A[i].first, length = A[i].second; + if ((subSeq & curSeq) == 0) { + res = max(res, length + dfs(i + 1, subSeq | curSeq, A)); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} arr + * @return {number} + */ + maxLength(arr) { + let A = []; + + for (const s of arr) { + let cur = 0; + let valid = true; + + for (const c of s) { + if (cur & (1 << (c.charCodeAt(0) - 97))) { + valid = false; + break; + } + cur |= (1 << (c.charCodeAt(0) - 97)); + } + + if (valid) { + A.push([cur, s.length]); + } + } + + const dfs = (i, subSeq) => { + if (i === A.length) { + return 0; + } + + let res = dfs(i + 1, subSeq); + + let [curSeq, length] = A[i]; + if ((subSeq & curSeq) === 0) { + res = Math.max(res, length + dfs(i + 1, subSeq | curSeq)); + } + return res; + }; + + return dfs(0, 0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * n + 2 ^ n)$ +* Space complexity: $O(n)$ + +> Where $n$ is the number of strings and $m$ is the maximum length of a string. + +--- + +## 4. Recursion (Bit Mask) - II + +::tabs-start + +```python +class Solution: + def maxLength(self, arr: List[str]) -> int: + def getIdx(c): + return ord(c) - ord('a') + + A = [] + for s in arr: + cur = 0 + valid = True + for c in s: + if cur & (1 << getIdx(c)): + valid = False + break + cur |= (1 << getIdx(c)) + + if valid: + A.append([cur, len(s)]) + + def dfs(i, subSeq): + res = 0 + for j in range(i, len(A)): + curSeq, length = A[j][0], A[j][1] + if (subSeq & curSeq) == 0: + res = max(res, length + dfs(j + 1, subSeq | curSeq)) + return res + + return dfs(0, 0) +``` + +```java +public class Solution { + public int maxLength(List arr) { + List A = new ArrayList<>(); + + for (String s : arr) { + int cur = 0; + boolean valid = true; + + for (char c : s.toCharArray()) { + if ((cur & (1 << (c - 'a'))) != 0) { + valid = false; + break; + } + cur |= (1 << (c - 'a')); + } + + if (valid) { + A.add(new int[]{cur, s.length()}); + } + } + + return dfs(0, 0, A); + } + + private int dfs(int i, int subSeq, List A) { + int res = 0; + for (int j = i; j < A.size(); j++) { + int curSeq = A.get(j)[0], length = A.get(j)[1]; + if ((subSeq & curSeq) == 0) { + res = Math.max(res, length + dfs(j + 1, subSeq | curSeq, A)); + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int maxLength(vector& arr) { + vector> A; + + for (const string& s : arr) { + int cur = 0; + bool valid = true; + + for (char c : s) { + if (cur & (1 << (c - 'a'))) { + valid = false; + break; + } + cur |= (1 << (c - 'a')); + } + + if (valid) { + A.emplace_back(cur, s.length()); + } + } + + return dfs(0, 0, A); + } + +private: + int dfs(int i, int subSeq, vector>& A) { + int res = 0; + for (int j = i; j < A.size(); j++) { + int curSeq = A[j].first, length = A[j].second; + if ((subSeq & curSeq) == 0) { + res = max(res, length + dfs(j + 1, subSeq | curSeq, A)); + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} arr + * @return {number} + */ + maxLength(arr) { + let A = []; + + for (const s of arr) { + let cur = 0; + let valid = true; + + for (const c of s) { + if (cur & (1 << (c.charCodeAt(0) - 97))) { + valid = false; + break; + } + cur |= (1 << (c.charCodeAt(0) - 97)); + } + + if (valid) { + A.push([cur, s.length]); + } + } + + const dfs = (i, subSeq) => { + let res = 0; + for (let j = i; j < A.length; j++) { + let [curSeq, length] = A[j]; + if ((subSeq & curSeq) === 0) { + res = Math.max(res, length + dfs(j + 1, subSeq | curSeq)); + } + } + return res; + }; + + return dfs(0, 0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * (m + 2 ^ n))$ +* Space complexity: $O(n)$ + +> Where $n$ is the number of strings and $m$ is the maximum length of a string. + +--- + +## 5. Dynamic Programming + +::tabs-start + +```python +class Solution: + def maxLength(self, arr: List[str]) -> int: + dp = {0} + res = 0 + + for s in arr: + cur = 0 + valid = True + + for c in s: + bit = 1 << (ord(c) - ord('a')) + if cur & bit: + valid = False + break + cur |= bit + + if not valid: + continue + + next_dp = dp.copy() + for seq in dp: + if (seq & cur) or (seq | cur) in dp: + continue + next_dp.add(seq | cur) + res = max(res, bin(seq | cur).count('1')) + dp = next_dp + + return res +``` + +```java +public class Solution { + public int maxLength(List arr) { + Set dp = new HashSet<>(); + dp.add(0); + int res = 0; + + for (String s : arr) { + int cur = 0; + boolean valid = true; + + for (char c : s.toCharArray()) { + int bit = 1 << (c - 'a'); + if ((cur & bit) != 0) { + valid = false; + break; + } + cur |= bit; + } + + if (!valid) { + continue; + } + + Set next_dp = new HashSet<>(dp); + for (int seq : dp) { + if ((seq & cur) != 0 || next_dp.contains(seq | cur)) { + continue; + } + next_dp.add(seq | cur); + res = Math.max(res, Integer.bitCount(seq | cur)); + } + dp = next_dp; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int maxLength(vector& arr) { + unordered_set dp; + dp.insert(0); + int res = 0; + + for (const string& s : arr) { + int cur = 0; + bool valid = true; + + for (char c : s) { + int bit = 1 << (c - 'a'); + if (cur & bit) { + valid = false; + break; + } + cur |= bit; + } + + if (!valid) { + continue; + } + + unordered_set next_dp(dp); + for (int seq : dp) { + if ((seq & cur) || next_dp.count(seq | cur)) { + continue; + } + next_dp.insert(seq | cur); + res = max(res, __builtin_popcount(seq | cur)); + } + dp = next_dp; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} arr + * @return {number} + */ + maxLength(arr) { + let dp = new Set(); + dp.add(0); + let res = 0; + + for (const s of arr) { + let cur = 0; + let valid = true; + + for (const c of s) { + let bit = 1 << (c.charCodeAt(0) - 97); + if (cur & bit) { + valid = false; + break; + } + cur |= bit; + } + + if (!valid) { + continue; + } + + let next_dp = new Set(dp); + for (let seq of dp) { + if ((seq & cur) || next_dp.has(seq | cur)) { + continue; + } + next_dp.add(seq | cur); + res = Math.max(res, (seq | cur).toString(2).split('0').join('').length); + } + dp = next_dp; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * (m + 2 ^ n))$ +* Space complexity: $O(2 ^ n)$ + +> Where $n$ is the number of strings and $m$ is the maximum length of a string. \ No newline at end of file diff --git a/articles/maximum-length-of-pair-chain.md b/articles/maximum-length-of-pair-chain.md new file mode 100644 index 000000000..2855ede51 --- /dev/null +++ b/articles/maximum-length-of-pair-chain.md @@ -0,0 +1,556 @@ +## 1. Recursion + +::tabs-start + +```python +class Solution: + def findLongestChain(self, pairs: List[List[int]]) -> int: + n = len(pairs) + pairs.sort(key=lambda x: x[1]) + + def dfs(i, j): + if i == n: + return 0 + + res = dfs(i + 1, j) + if j == -1 or pairs[j][1] < pairs[i][0]: + res = max(res, 1 + dfs(i + 1, i)) + + return res + + return dfs(0, -1) +``` + +```java +public class Solution { + public int findLongestChain(int[][] pairs) { + int n = pairs.length; + Arrays.sort(pairs, (a, b) -> Integer.compare(a[1], b[1])); + return dfs(pairs, 0, -1, n); + } + + private int dfs(int[][] pairs, int i, int j, int n) { + if (i == n) { + return 0; + } + + int res = dfs(pairs, i + 1, j, n); + if (j == -1 || pairs[j][1] < pairs[i][0]) { + res = Math.max(res, 1 + dfs(pairs, i + 1, i, n)); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int findLongestChain(vector>& pairs) { + int n = pairs.size(); + sort(pairs.begin(), pairs.end(), [](const auto& a, const auto& b) { + return a[1] < b[1]; + }); + + return dfs(pairs, 0, -1, n); + } + +private: + int dfs(vector>& pairs, int i, int j, int n) { + if (i == n) { + return 0; + } + + int res = dfs(pairs, i + 1, j, n); + if (j == -1 || pairs[j][1] < pairs[i][0]) { + res = max(res, 1 + dfs(pairs, i + 1, i, n)); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} pairs + * @return {number} + */ + findLongestChain(pairs) { + pairs.sort((a, b) => a[1] - b[1]); + let n = pairs.length; + + const dfs = (i, j) => { + if (i === n) { + return 0; + } + + let res = dfs(i + 1, j); + if (j === -1 || pairs[j][1] < pairs[i][0]) { + res = Math.max(res, 1 + dfs(i + 1, i)); + } + + return res; + }; + + return dfs(0, -1); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(2 ^ n)$ +* Space complexity: $O(n)$ for recursion stack. + +--- + +## 2. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def findLongestChain(self, pairs: List[List[int]]) -> int: + n = len(pairs) + pairs.sort(key=lambda x: x[1]) + dp = [[-1] * (n + 1) for _ in range(n)] + + def dfs(i, j): + if i == n: + return 0 + if dp[i][j + 1] != -1: + return dp[i][j + 1] + + res = dfs(i + 1, j) + if j == -1 or pairs[j][1] < pairs[i][0]: + res = max(res, 1 + dfs(i + 1, i)) + + dp[i][j + 1] = res + return res + + return dfs(0, -1) +``` + +```java +public class Solution { + private int[][] dp; + + public int findLongestChain(int[][] pairs) { + int n = pairs.length; + Arrays.sort(pairs, (a, b) -> Integer.compare(a[1], b[1])); + dp = new int[n][n + 1]; + + for (int[] row : dp) { + Arrays.fill(row, -1); + } + + return dfs(pairs, 0, -1, n); + } + + private int dfs(int[][] pairs, int i, int j, int n) { + if (i == n) { + return 0; + } + if (dp[i][j + 1] != -1) { + return dp[i][j + 1]; + } + + int res = dfs(pairs, i + 1, j, n); + if (j == -1 || pairs[j][1] < pairs[i][0]) { + res = Math.max(res, 1 + dfs(pairs, i + 1, i, n)); + } + + dp[i][j + 1] = res; + return res; + } +} +``` + +```cpp +class Solution { +public: + vector> dp; + + int findLongestChain(vector>& pairs) { + int n = pairs.size(); + sort(pairs.begin(), pairs.end(), [](const auto& a, const auto& b) { + return a[1] < b[1]; + }); + + dp = vector>(n, vector(n + 1, -1)); + return dfs(pairs, 0, -1, n); + } + +private: + int dfs(vector>& pairs, int i, int j, int n) { + if (i == n) { + return 0; + } + if (dp[i][j + 1] != -1) { + return dp[i][j + 1]; + } + + int res = dfs(pairs, i + 1, j, n); + if (j == -1 || pairs[j][1] < pairs[i][0]) { + res = max(res, 1 + dfs(pairs, i + 1, i, n)); + } + + dp[i][j + 1] = res; + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} pairs + * @return {number} + */ + findLongestChain(pairs) { + pairs.sort((a, b) => a[1] - b[1]); + let n = pairs.length; + let dp = Array.from({ length: n }, () => new Array(n + 1).fill(-1)); + + const dfs = (i, j) => { + if (i === n) { + return 0; + } + if (dp[i][j + 1] !== -1) { + return dp[i][j + 1]; + } + + let res = dfs(i + 1, j); + if (j === -1 || pairs[j][1] < pairs[i][0]) { + res = Math.max(res, 1 + dfs(i + 1, i)); + } + + dp[i][j + 1] = res; + return res; + }; + + return dfs(0, -1); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n ^ 2)$ + +--- + +## 3. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def findLongestChain(self, pairs: List[List[int]]) -> int: + n = len(pairs) + pairs.sort(key=lambda x: x[1]) + dp = [1] * n + + for i in range(n): + for j in range(i): + if pairs[j][1] < pairs[i][0]: + dp[i] = max(dp[i], dp[j] + 1) + + return max(dp) +``` + +```java +public class Solution { + public int findLongestChain(int[][] pairs) { + int n = pairs.length; + Arrays.sort(pairs, (a, b) -> Integer.compare(a[1], b[1])); + int[] dp = new int[n]; + Arrays.fill(dp, 1); + + for (int i = 0; i < n; i++) { + for (int j = 0; j < i; j++) { + if (pairs[j][1] < pairs[i][0]) { + dp[i] = Math.max(dp[i], dp[j] + 1); + } + } + } + + return Arrays.stream(dp).max().getAsInt(); + } +} +``` + +```cpp +class Solution { +public: + int findLongestChain(vector>& pairs) { + int n = pairs.size(); + sort(pairs.begin(), pairs.end(), [](const auto& a, const auto& b) { + return a[1] < b[1]; + }); + + vector dp(n, 1); + + for (int i = 0; i < n; i++) { + for (int j = 0; j < i; j++) { + if (pairs[j][1] < pairs[i][0]) { + dp[i] = max(dp[i], dp[j] + 1); + } + } + } + + return *max_element(dp.begin(), dp.end()); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} pairs + * @return {number} + */ + findLongestChain(pairs) { + let n = pairs.length; + pairs.sort((a, b) => a[1] - b[1]); + let dp = new Array(n).fill(1); + + for (let i = 0; i < n; i++) { + for (let j = 0; j < i; j++) { + if (pairs[j][1] < pairs[i][0]) { + dp[i] = Math.max(dp[i], dp[j] + 1); + } + } + } + + return Math.max(...dp); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n)$ + +--- + +## 4. Dynamic Programming (Bianry Search) + +::tabs-start + +```python +class Solution: + def findLongestChain(self, pairs: List[List[int]]) -> int: + pairs.sort(key=lambda x: x[0]) + dp = [] + + for a, b in pairs: + pos = bisect_left(dp, a) + if pos == len(dp): + dp.append(b) + else: + dp[pos] = min(dp[pos], b) + + return len(dp) +``` + +```java +public class Solution { + public int findLongestChain(int[][] pairs) { + Arrays.sort(pairs, Comparator.comparingInt(a -> a[0])); + List dp = new ArrayList<>(); + + for (int[] pair : pairs) { + int pos = binarySearch(dp, pair[0]); + if (pos == dp.size()) { + dp.add(pair[1]); + } else { + dp.set(pos, Math.min(dp.get(pos), pair[1])); + } + } + + return dp.size(); + } + + private int binarySearch(List dp, int target) { + int left = 0, right = dp.size() - 1; + while (left <= right) { + int mid = left + (right - left) / 2; + if (dp.get(mid) < target) { + left = mid + 1; + } else { + right = mid - 1; + } + } + return left; + } +} +``` + +```cpp +class Solution { +public: + int findLongestChain(vector>& pairs) { + sort(pairs.begin(), pairs.end()); + vector dp; + + for (auto& pair : pairs) { + auto it = lower_bound(dp.begin(), dp.end(), pair[0]); + if (it == dp.end()) { + dp.push_back(pair[1]); + } else { + *it = min(*it, pair[1]); + } + } + + return dp.size(); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} pairs + * @return {number} + */ + findLongestChain(pairs) { + pairs.sort((a, b) => a[0] - b[0]); + let dp = []; + + const binarySearch = (target) => { + let left = 0, right = dp.length - 1; + while (left <= right) { + let mid = Math.floor((left + right) / 2); + if (dp[mid] < target) { + left = mid + 1; + } else { + right = mid - 1; + } + } + return left; + }; + + for (let i = 0; i < pairs.length; i++) { + let pos = binarySearch(pairs[i][0]); + if (pos === dp.length) { + dp.push(pairs[i][1]); + } else { + dp[pos] = Math.min(dp[pos], pairs[i][1]); + } + } + + return dp.length; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(n)$ + +--- + +## 5. Greedy + +::tabs-start + +```python +class Solution: + def findLongestChain(self, pairs: List[List[int]]) -> int: + pairs.sort(key=lambda p: p[1]) + length = 1 + end = pairs[0][1] + + for i in range(1, len(pairs)): + if end < pairs[i][0]: + length += 1 + end = pairs[i][1] + + return length +``` + +```java +public class Solution { + public int findLongestChain(int[][] pairs) { + Arrays.sort(pairs, (a, b) -> Integer.compare(a[1], b[1])); + int length = 1; + int end = pairs[0][1]; + + for (int i = 1; i < pairs.length; i++) { + if (end < pairs[i][0]) { + length++; + end = pairs[i][1]; + } + } + + return length; + } +} +``` + +```cpp +class Solution { +public: + int findLongestChain(vector>& pairs) { + sort(pairs.begin(), pairs.end(), [](const auto& a, const auto& b) { + return a[1] < b[1]; + }); + + int length = 1, end = pairs[0][1]; + + for (int i = 1; i < pairs.size(); i++) { + if (end < pairs[i][0]) { + length++; + end = pairs[i][1]; + } + } + + return length; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} pairs + * @return {number} + */ + findLongestChain(pairs) { + pairs.sort((a, b) => a[1] - b[1]); + let length = 1; + let end = pairs[0][1]; + + for (let i = 1; i < pairs.length; i++) { + if (end < pairs[i][0]) { + length++; + end = pairs[i][1]; + } + } + + return length; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n\log n)$ +* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. \ No newline at end of file diff --git a/articles/maximum-nesting-depth-of-the-parentheses.md b/articles/maximum-nesting-depth-of-the-parentheses.md new file mode 100644 index 000000000..f18d24a7f --- /dev/null +++ b/articles/maximum-nesting-depth-of-the-parentheses.md @@ -0,0 +1,305 @@ +## 1. Recursion + +::tabs-start + +```python +class Solution: + def maxDepth(self, s: str) -> int: + res = 0 + + def dfs(i): + nonlocal res + if i == len(s): + return 0 + + cur = dfs(i + 1) + if s[i] == '(': + cur += 1 + elif s[i] == ')': + cur -= 1 + + res = max(res, abs(cur)) + return cur + + dfs(0) + return res +``` + +```java +public class Solution { + private int res = 0; + + public int maxDepth(String s) { + dfs(s, 0); + return res; + } + + private int dfs(String s, int i) { + if (i == s.length()) { + return 0; + } + + int cur = dfs(s, i + 1); + if (s.charAt(i) == '(') { + cur += 1; + } else if (s.charAt(i) == ')') { + cur -= 1; + } + + res = Math.max(res, Math.abs(cur)); + return cur; + } +} +``` + +```cpp +class Solution { +private: + int res = 0; + + int dfs(const string& s, int i) { + if (i == s.length()) { + return 0; + } + + int cur = dfs(s, i + 1); + if (s[i] == '(') { + cur += 1; + } else if (s[i] == ')') { + cur -= 1; + } + + res = max(res, abs(cur)); + return cur; + } + +public: + int maxDepth(string s) { + dfs(s, 0); + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {number} + */ + maxDepth(s) { + let res = 0; + + const dfs = (i) => { + if (i === s.length) { + return 0; + } + + let cur = dfs(i + 1); + if (s[i] === '(') { + cur += 1; + } else if (s[i] === ')') { + cur -= 1; + } + + res = Math.max(res, Math.abs(cur)); + return cur; + }; + + dfs(0); + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ for recursion stack. + +--- + +## 2. Stack + +::tabs-start + +```python +class Solution: + def maxDepth(self, s: str) -> int: + res, stack = 0, [] + + for c in s: + if c == "(": + stack.append(c) + res = max(res, len(stack)) + elif c == ")": + stack.pop() + + return res +``` + +```java +public class Solution { + public int maxDepth(String s) { + int res = 0; + Stack stack = new Stack<>(); + + for (char c : s.toCharArray()) { + if (c == '(') { + stack.push(c); + res = Math.max(res, stack.size()); + } else if (c == ')') { + stack.pop(); + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int maxDepth(string s) { + int res = 0; + stack stack; + + for (char c : s) { + if (c == '(') { + stack.push(c); + res = max(res, (int)stack.size()); + } else if (c == ')') { + stack.pop(); + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {number} + */ + maxDepth(s) { + let res = 0; + let stack = []; + + for (let c of s) { + if (c === '(') { + stack.push(c); + res = Math.max(res, stack.length); + } else if (c === ')') { + stack.pop(); + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 3. Iteration + +::tabs-start + +```python +class Solution: + def maxDepth(self, s: str) -> int: + res = 0 + cur = 0 + + for c in s: + if c == "(": + cur += 1 + elif c == ")": + cur -= 1 + res = max(res, cur) + + return res +``` + +```java +public class Solution { + public int maxDepth(String s) { + int res = 0, cur = 0; + + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + if (c == '(') { + cur++; + } else if (c == ')') { + cur--; + } + res = Math.max(res, cur); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int maxDepth(string s) { + int res = 0, cur = 0; + + for (char c : s) { + if (c == '(') { + cur++; + } else if (c == ')') { + cur--; + } + res = max(res, cur); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {number} + */ + maxDepth(s) { + let res = 0, cur = 0; + + for (let c of s) { + if (c === '(') { + cur++; + } else if (c === ')') { + cur--; + } + res = Math.max(res, cur); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ extra space. \ No newline at end of file diff --git a/articles/maximum-points-you-can-obtain-from-cards.md b/articles/maximum-points-you-can-obtain-from-cards.md new file mode 100644 index 000000000..8d1b9294a --- /dev/null +++ b/articles/maximum-points-you-can-obtain-from-cards.md @@ -0,0 +1,462 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def maxScore(self, cardPoints: List[int], k: int) -> int: + n = len(cardPoints) + res = 0 + + for left in range(k + 1): + leftSum = sum(cardPoints[:left]) + rightSum = sum(cardPoints[n - (k - left):]) + res = max(res, leftSum + rightSum) + + return res +``` + +```java +public class Solution { + public int maxScore(int[] cardPoints, int k) { + int n = cardPoints.length; + int res = 0; + + for (int left = 0; left <= k; left++) { + int leftSum = 0; + for (int i = 0; i < left; i++) { + leftSum += cardPoints[i]; + } + + int rightSum = 0; + for (int i = n - (k - left); i < n; i++) { + rightSum += cardPoints[i]; + } + + res = Math.max(res, leftSum + rightSum); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int maxScore(vector& cardPoints, int k) { + int n = cardPoints.size(); + int res = 0; + + for (int left = 0; left <= k; left++) { + int leftSum = 0; + for (int i = 0; i < left; i++) { + leftSum += cardPoints[i]; + } + + int rightSum = 0; + for (int i = n - (k - left); i < n; i++) { + rightSum += cardPoints[i]; + } + + res = max(res, leftSum + rightSum); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} cardPoints + * @param {number} k + * @return {number} + */ + maxScore(cardPoints, k) { + let n = cardPoints.length; + let res = 0; + + for (let left = 0; left <= k; left++) { + let leftSum = 0; + for (let i = 0; i < left; i++) { + leftSum += cardPoints[i]; + } + + let rightSum = 0; + for (let i = n - (k - left); i < n; i++) { + rightSum += cardPoints[i]; + } + + res = Math.max(res, leftSum + rightSum); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(k ^ 2)$ +* Space complexity: $O(1)$ extra space. + +> Where $k$ is the number of cards to pick. + +--- + +## 2. Prefix & Suffix Sums + +::tabs-start + +```python +class Solution: + def maxScore(self, cardPoints: List[int], k: int) -> int: + n = len(cardPoints) + + prefix = [0] * (n + 1) + for i in range(n): + prefix[i + 1] = prefix[i] + cardPoints[i] + + suffix = [0] * (n + 1) + for i in range(n - 1, -1, -1): + suffix[i] = suffix[i + 1] + cardPoints[i] + + res = 0 + for left in range(k + 1): + right = k - left + res = max(res, prefix[left] + suffix[n - right]) + + return res +``` + +```java +public class Solution { + public int maxScore(int[] cardPoints, int k) { + int n = cardPoints.length; + + int[] prefix = new int[n + 1]; + for (int i = 0; i < n; i++) { + prefix[i + 1] = prefix[i] + cardPoints[i]; + } + + int[] suffix = new int[n + 1]; + for (int i = n - 1; i >= 0; i--) { + suffix[i] = suffix[i + 1] + cardPoints[i]; + } + + int res = 0; + for (int left = 0; left <= k; left++) { + int right = k - left; + res = Math.max(res, prefix[left] + suffix[n - right]); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int maxScore(vector& cardPoints, int k) { + int n = cardPoints.size(); + + vector prefix(n + 1, 0); + for (int i = 0; i < n; i++) { + prefix[i + 1] = prefix[i] + cardPoints[i]; + } + + vector suffix(n + 1, 0); + for (int i = n - 1; i >= 0; i--) { + suffix[i] = suffix[i + 1] + cardPoints[i]; + } + + int res = 0; + for (int left = 0; left <= k; left++) { + int right = k - left; + res = max(res, prefix[left] + suffix[n - right]); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} cardPoints + * @param {number} k + * @return {number} + */ + maxScore(cardPoints, k) { + let n = cardPoints.length; + + let prefix = new Array(n + 1).fill(0); + for (let i = 0; i < n; i++) { + prefix[i + 1] = prefix[i] + cardPoints[i]; + } + + let suffix = new Array(n + 1).fill(0); + for (let i = n - 1; i >= 0; i--) { + suffix[i] = suffix[i + 1] + cardPoints[i]; + } + + let res = 0; + for (let left = 0; left <= k; left++) { + let right = k - left; + res = Math.max(res, prefix[left] + suffix[n - right]); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 3. Sliding Window (Minimum Sum Window) + +::tabs-start + +```python +class Solution: + def maxScore(self, cardPoints: List[int], k: int) -> int: + n = len(cardPoints) + windowSize = n - k + + if windowSize == 0: + return sum(cardPoints) + + total = 0 + minWindowSum = float("inf") + curSum = 0 + + for i in range(n): + total += cardPoints[i] + curSum += cardPoints[i] + if i >= windowSize - 1: + minWindowSum = min(minWindowSum, curSum) + curSum -= cardPoints[i - windowSize + 1] + + return total - minWindowSum +``` + +```java +public class Solution { + public int maxScore(int[] cardPoints, int k) { + int n = cardPoints.length; + int windowSize = n - k; + + if (windowSize == 0) { + int sum = 0; + for (int num : cardPoints) sum += num; + return sum; + } + + int total = 0; + int minWindowSum = Integer.MAX_VALUE; + int curSum = 0; + + for (int i = 0; i < n; i++) { + total += cardPoints[i]; + curSum += cardPoints[i]; + if (i >= windowSize - 1) { + minWindowSum = Math.min(minWindowSum, curSum); + curSum -= cardPoints[i - windowSize + 1]; + } + } + + return total - minWindowSum; + } +} +``` + +```cpp +class Solution { +public: + int maxScore(vector& cardPoints, int k) { + int n = cardPoints.size(); + int windowSize = n - k; + + if (windowSize == 0) { + return accumulate(cardPoints.begin(), cardPoints.end(), 0); + } + + int total = 0; + int minWindowSum = INT_MAX; + int curSum = 0; + + for (int i = 0; i < n; i++) { + total += cardPoints[i]; + curSum += cardPoints[i]; + if (i >= windowSize - 1) { + minWindowSum = min(minWindowSum, curSum); + curSum -= cardPoints[i - windowSize + 1]; + } + } + + return total - minWindowSum; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} cardPoints + * @param {number} k + * @return {number} + */ + maxScore(cardPoints, k) { + let n = cardPoints.length; + let windowSize = n - k; + + if (windowSize === 0) { + return cardPoints.reduce((sum, num) => sum + num, 0); + } + + let total = 0; + let minWindowSum = Infinity; + let curSum = 0; + + for (let i = 0; i < n; i++) { + total += cardPoints[i]; + curSum += cardPoints[i]; + if (i >= windowSize - 1) { + minWindowSum = Math.min(minWindowSum, curSum); + curSum -= cardPoints[i - windowSize + 1]; + } + } + + return total - minWindowSum; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ extra space. + +--- + +## 4. Sliding Window + +::tabs-start + +```python +class Solution: + def maxScore(self, cardPoints: List[int], k: int) -> int: + l, r = 0, len(cardPoints) - k + total = sum(cardPoints[r:]) + res = total + + while r < len(cardPoints): + total += cardPoints[l] - cardPoints[r] + res = max(res, total) + l += 1 + r += 1 + + return res +``` + +```java +public class Solution { + public int maxScore(int[] cardPoints, int k) { + int l = 0, r = cardPoints.length - k; + int total = 0; + + for (int i = r; i < cardPoints.length; i++) { + total += cardPoints[i]; + } + + int res = total; + + while (r < cardPoints.length) { + total += cardPoints[l] - cardPoints[r]; + res = Math.max(res, total); + l++; + r++; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int maxScore(vector& cardPoints, int k) { + int l = 0, r = cardPoints.size() - k; + int total = 0; + + for (int i = r; i < cardPoints.size(); i++) { + total += cardPoints[i]; + } + + int res = total; + + while (r < cardPoints.size()) { + total += cardPoints[l] - cardPoints[r]; + res = max(res, total); + l++; + r++; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} cardPoints + * @param {number} k + * @return {number} + */ + maxScore(cardPoints, k) { + let l = 0, r = cardPoints.length - k; + let total = 0; + + for (let i = r; i < cardPoints.length; i++) { + total += cardPoints[i]; + } + + let res = total; + + while (r < cardPoints.length) { + total += cardPoints[l] - cardPoints[r]; + res = Math.max(res, total); + l++; + r++; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(k)$ +* Space complexity: $O(1)$ extra space. + +> Where $k$ is the number of cards to pick. \ No newline at end of file diff --git a/articles/maximum-score-of-a-good-subarray.md b/articles/maximum-score-of-a-good-subarray.md new file mode 100644 index 000000000..f8b6fbdc0 --- /dev/null +++ b/articles/maximum-score-of-a-good-subarray.md @@ -0,0 +1,729 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def maximumScore(self, nums: List[int], k: int) -> int: + n, res = len(nums), 0 + + for i in range(k + 1): + minEle = nums[i] + for j in range(i, n): + minEle = min(minEle, nums[j]) + if j >= k: + res = max(res, minEle * (j - i + 1)) + + return res +``` + +```java +public class Solution { + public int maximumScore(int[] nums, int k) { + int n = nums.length, res = 0; + + for (int i = 0; i <= k; i++) { + int minEle = nums[i]; + for (int j = i; j < n; j++) { + minEle = Math.min(minEle, nums[j]); + if (j >= k) { + res = Math.max(res, minEle * (j - i + 1)); + } + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int maximumScore(vector& nums, int k) { + int n = nums.size(), res = 0; + + for (int i = 0; i <= k; i++) { + int minEle = nums[i]; + for (int j = i; j < n; j++) { + minEle = min(minEle, nums[j]); + if (j >= k) { + res = max(res, minEle * (j - i + 1)); + } + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + maximumScore(nums, k) { + let n = nums.length, res = 0; + + for (let i = 0; i <= k; i++) { + let minEle = nums[i]; + for (let j = i; j < n; j++) { + minEle = Math.min(minEle, nums[j]); + if (j >= k) { + res = Math.max(res, minEle * (j - i + 1)); + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(1)$ extra space. + +--- + +## 2. Binary Search + +::tabs-start + +```python +class Solution: + def maximumScore(self, nums: List[int], k: int) -> int: + n, res = len(nums), 0 + arr = nums[:] + + for i in range(k - 1, -1, -1): + arr[i] = min(arr[i], arr[i + 1]) + for i in range(k + 1, n): + arr[i] = min(arr[i], arr[i - 1]) + + left_arr = arr[:k+1] + right_arr = arr[k:] + + def find_right(target): + lo, hi = 0, len(right_arr) - 1 + pos = 0 + while lo <= hi: + mid = (lo + hi) // 2 + if right_arr[mid] >= target: + pos = mid + lo = mid + 1 + else: + hi = mid - 1 + return pos + + for minVal in set(arr): + l = bisect_left(left_arr, minVal) + r = find_right(minVal) + res = max(res, minVal * (k - l + 1 + r)) + return res +``` + +```java +public class Solution { + public int maximumScore(int[] nums, int k) { + int n = nums.length, res = 0; + int[] arr = Arrays.copyOf(nums, n); + Set candidates = new HashSet<>(); + candidates.add(arr[k]); + + for (int i = k - 1; i >= 0; i--) { + arr[i] = Math.min(arr[i], arr[i + 1]); + candidates.add(arr[i]); + } + for (int i = k + 1; i < n; i++) { + arr[i] = Math.min(arr[i], arr[i - 1]); + candidates.add(arr[i]); + } + + int[] leftArr = Arrays.copyOfRange(arr, 0, k + 1); + int[] rightArr = Arrays.copyOfRange(arr, k, n); + + for (int minVal : candidates) { + int l = findLeft(leftArr, minVal); + int r = findRight(rightArr, minVal); + res = Math.max(res, minVal * (k - l + 1 + r)); + } + return res; + } + + private int findLeft(int[] arr, int target) { + int lo = 0, hi = arr.length - 1; + while (lo <= hi) { + int mid = (lo + hi) / 2; + if (arr[mid] < target) { + lo = mid + 1; + } else { + hi = mid - 1; + } + } + return lo; + } + + private int findRight(int[] arr, int target) { + int lo = 0, hi = arr.length - 1, pos = 0; + while (lo <= hi) { + int mid = (lo + hi) / 2; + if (arr[mid] >= target) { + pos = mid; + lo = mid + 1; + } else { + hi = mid - 1; + } + } + return pos; + } +} +``` + +```cpp +class Solution { +public: + int maximumScore(vector& nums, int k) { + int n = nums.size(), res = 0; + vector arr = nums; + + for (int i = k - 1; i >= 0; i--) { + arr[i] = min(arr[i], arr[i + 1]); + } + for (int i = k + 1; i < n; i++) { + arr[i] = min(arr[i], arr[i - 1]); + } + + vector leftArr(arr.begin(), arr.begin() + k + 1); + vector rightArr(arr.begin() + k, arr.end()); + + set candidates(arr.begin(), arr.end()); + for (int minVal : candidates) { + int l = lower_bound(leftArr.begin(), leftArr.end(), minVal) - leftArr.begin(); + int r = findRight(rightArr, minVal); + res = max(res, minVal * (k - l + 1 + r)); + } + return res; + } + +private: + int findRight(vector& arr, int target) { + int lo = 0, hi = arr.size() - 1, pos = 0; + while (lo <= hi) { + int mid = (lo + hi) / 2; + if (arr[mid] >= target) { + pos = mid; + lo = mid + 1; + } else { + hi = mid - 1; + } + } + return pos; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + maximumScore(nums, k) { + let n = nums.length, res = 0; + let arr = [...nums]; + + for (let i = k - 1; i >= 0; i--) { + arr[i] = Math.min(arr[i], arr[i + 1]); + } + for (let i = k + 1; i < n; i++) { + arr[i] = Math.min(arr[i], arr[i - 1]); + } + + let leftArr = arr.slice(0, k + 1); + let rightArr = arr.slice(k); + + const findLeft = (target) => { + let lo = 0, hi = leftArr.length - 1; + while (lo <= hi) { + let mid = Math.floor((lo + hi) / 2); + if (leftArr[mid] < target) { + lo = mid + 1; + } else { + hi = mid - 1; + } + } + return lo; + }; + + const findRight = (target) => { + let lo = 0, hi = rightArr.length - 1, pos = 0; + while (lo <= hi) { + let mid = Math.floor((lo + hi) / 2); + if (rightArr[mid] >= target) { + pos = mid; + lo = mid + 1; + } else { + hi = mid - 1; + } + } + return pos; + }; + + let candidates = [...new Set(arr)]; + for (let minVal of candidates) { + let l = findLeft(minVal); + let r = findRight(minVal); + res = Math.max(res, minVal * (k - l + 1 + r)); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(n)$ + +--- + +## 3. Binary Search (Overwriting the Input) + +::tabs-start + +```python +class Solution: + def maximumScore(self, nums: List[int], k: int) -> int: + n, res = len(nums), 0 + + for i in range(k - 1, -1, -1): + nums[i] = min(nums[i], nums[i + 1]) + for i in range(k + 1, n): + nums[i] = min(nums[i], nums[i - 1]) + + def find_left(target): + lo, hi = 0, k + while lo <= hi: + mid = (lo + hi) // 2 + if nums[mid] < target: + lo = mid + 1 + else: + hi = mid - 1 + return lo + + def find_right(target): + lo, hi = k, n - 1 + while lo <= hi: + mid = (lo + hi) // 2 + if nums[mid] >= target: + lo = mid + 1 + else: + hi = mid - 1 + return hi + + for minVal in set(nums): + i = find_left(minVal) + j = find_right(minVal) + res = max(res, minVal * (j - i + 1)) + return res +``` + +```java +public class Solution { + public int maximumScore(int[] nums, int k) { + int n = nums.length, res = 0; + + for (int i = k - 1; i >= 0; i--) { + nums[i] = Math.min(nums[i], nums[i + 1]); + } + for (int i = k + 1; i < n; i++) { + nums[i] = Math.min(nums[i], nums[i - 1]); + } + + Set candidates = new TreeSet<>(); + for (int num : nums) { + candidates.add(num); + } + + for (int minVal : candidates) { + int i = findLeft(nums, k, minVal); + int j = findRight(nums, k, minVal); + res = Math.max(res, minVal * (j - i + 1)); + } + return res; + } + + int findLeft(int[] nums, int k, int target) { + int lo = 0, hi = k; + while (lo <= hi) { + int mid = (lo + hi) / 2; + if (nums[mid] < target) { + lo = mid + 1; + } else { + hi = mid - 1; + } + } + return lo; + } + + int findRight(int[] nums, int k, int target) { + int lo = k, hi = nums.length - 1; + while (lo <= hi) { + int mid = (lo + hi) / 2; + if (nums[mid] >= target) { + lo = mid + 1; + } else { + hi = mid - 1; + } + } + return hi; + } +} +``` + +```cpp +class Solution { +public: + int maximumScore(vector& nums, int k) { + int n = nums.size(), res = 0; + + for (int i = k - 1; i >= 0; i--) { + nums[i] = min(nums[i], nums[i + 1]); + } + for (int i = k + 1; i < n; i++) { + nums[i] = min(nums[i], nums[i - 1]); + } + + auto findLeft = [&](int target) { + int lo = 0, hi = k; + while (lo <= hi) { + int mid = (lo + hi) / 2; + if (nums[mid] < target) { + lo = mid + 1; + } else { + hi = mid - 1; + } + } + return lo; + }; + + auto findRight = [&](int target) { + int lo = k, hi = n - 1; + while (lo <= hi) { + int mid = (lo + hi) / 2; + if (nums[mid] >= target) { + lo = mid + 1; + } else { + hi = mid - 1; + } + } + return hi; + }; + + set candidates(nums.begin(), nums.end()); + for (int minVal : candidates) { + int i = findLeft(minVal); + int j = findRight(minVal); + res = max(res, minVal * (j - i + 1)); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + maximumScore(nums, k) { + let n = nums.length, res = 0; + + for (let i = k - 1; i >= 0; i--) { + nums[i] = Math.min(nums[i], nums[i + 1]); + } + for (let i = k + 1; i < n; i++) { + nums[i] = Math.min(nums[i], nums[i - 1]); + } + + const findLeft = (target) => { + let lo = 0, hi = k; + while (lo <= hi) { + let mid = Math.floor((lo + hi) / 2); + if (nums[mid] < target) { + lo = mid + 1; + } else { + hi = mid - 1; + } + } + return lo; + }; + + const findRight = (target) => { + let lo = k, hi = n - 1; + while (lo <= hi) { + let mid = Math.floor((lo + hi) / 2); + if (nums[mid] >= target) { + lo = mid + 1; + } else { + hi = mid - 1; + } + } + return hi; + }; + + let candidates = new Set(nums); + for (let minVal of candidates) { + let i = findLeft(minVal); + let j = findRight(minVal); + res = Math.max(res, minVal * (j - i + 1)); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(n)$ + +--- + +## 4. Monotonic Stack + +::tabs-start + +```python +class Solution: + def maximumScore(self, nums: List[int], k: int) -> int: + n, res = len(nums), 0 + stack = [] + + for i in range(n + 1): + while stack and (i == n or nums[stack[-1]] >= nums[i]): + mini = nums[stack.pop()] + j = stack[-1] if stack else -1 + if j < k < i: + res = max(res, mini * (i - j - 1)) + stack.append(i) + + return res +``` + +```java +public class Solution { + public int maximumScore(int[] nums, int k) { + int n = nums.length, res = 0; + Stack stack = new Stack<>(); + + for (int i = 0; i <= n; i++) { + while (!stack.isEmpty() && (i == n || nums[stack.peek()] >= nums[i])) { + int mini = nums[stack.pop()]; + int j = stack.isEmpty() ? -1 : stack.peek(); + if (j < k && k < i) { + res = Math.max(res, mini * (i - j - 1)); + } + } + stack.push(i); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int maximumScore(vector& nums, int k) { + int n = nums.size(), res = 0; + stack stk; + + for (int i = 0; i <= n; i++) { + while (!stk.empty() && (i == n || nums[stk.top()] >= nums[i])) { + int mini = nums[stk.top()]; + stk.pop(); + int j = stk.empty() ? -1 : stk.top(); + if (j < k && k < i) { + res = max(res, mini * (i - j - 1)); + } + } + stk.push(i); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + maximumScore(nums, k) { + let n = nums.length, res = 0; + let stack = []; + + for (let i = 0; i <= n; i++) { + while (stack.length && (i === n || nums[stack[stack.length - 1]] >= nums[i])) { + let mini = nums[stack.pop()]; + let j = stack.length ? stack[stack.length - 1] : -1; + if (j < k && k < i) { + res = Math.max(res, mini * (i - j - 1)); + } + } + stack.push(i); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 5. Greedy + Two Pointers + +::tabs-start + +```python +class Solution: + def maximumScore(self, nums: List[int], k: int) -> int: + l = r = k + res = nums[k] + cur_min = nums[k] + + while l > 0 or r < len(nums) - 1: + left = nums[l - 1] if l > 0 else 0 + right = nums[r + 1] if r < len(nums) - 1 else 0 + + if left > right: + l -= 1 + cur_min = min(cur_min, left) + else: + r += 1 + cur_min = min(cur_min, right) + + res = max(res, cur_min * (r - l + 1)) + + return res +``` + +```java +public class Solution { + public int maximumScore(int[] nums, int k) { + int l = k, r = k; + int res = nums[k]; + int curMin = nums[k]; + int n = nums.length; + + while (l > 0 || r < n - 1) { + int left = (l > 0) ? nums[l - 1] : 0; + int right = (r < n - 1) ? nums[r + 1] : 0; + + if (left > right) { + l--; + curMin = Math.min(curMin, left); + } else { + r++; + curMin = Math.min(curMin, right); + } + + res = Math.max(res, curMin * (r - l + 1)); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int maximumScore(vector& nums, int k) { + int l = k, r = k; + int res = nums[k]; + int curMin = nums[k]; + int n = nums.size(); + + while (l > 0 || r < n - 1) { + int left = (l > 0) ? nums[l - 1] : 0; + int right = (r < n - 1) ? nums[r + 1] : 0; + + if (left > right) { + l--; + curMin = min(curMin, left); + } else { + r++; + curMin = min(curMin, right); + } + + res = max(res, curMin * (r - l + 1)); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + maximumScore(nums, k) { + let l = k, r = k; + let res = nums[k]; + let curMin = nums[k]; + let n = nums.length; + + while (l > 0 || r < n - 1) { + let left = (l > 0) ? nums[l - 1] : 0; + let right = (r < n - 1) ? nums[r + 1] : 0; + + if (left > right) { + l--; + curMin = Math.min(curMin, left); + } else { + r++; + curMin = Math.min(curMin, right); + } + + res = Math.max(res, curMin * (r - l + 1)); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ extra space. \ No newline at end of file diff --git a/articles/maximum-score-words-formed-by-letters.md b/articles/maximum-score-words-formed-by-letters.md new file mode 100644 index 000000000..f9b510481 --- /dev/null +++ b/articles/maximum-score-words-formed-by-letters.md @@ -0,0 +1,676 @@ +## 1. Backtracking + +::tabs-start + +```python +class Solution: + def maxScoreWords(self, words: List[str], letters: List[str], score: List[int]) -> int: + def can_form_word(w, letter_cnt): + word_cnt = Counter(w) + for c in word_cnt: + if word_cnt[c] > letter_cnt[c]: + return False + return True + + def get_score(w): + res = 0 + for c in w: + res += score[ord(c) - ord('a')] + return res + + letter_cnt = Counter(letters) + + def backtrack(i): + if i == len(words): + return 0 + + res = backtrack(i + 1) # skip + if can_form_word(words[i], letter_cnt): # include (when possible) + for c in words[i]: + letter_cnt[c] -= 1 + res = max(res, get_score(words[i]) + backtrack(i + 1)) + for c in words[i]: + letter_cnt[c] += 1 + + return res + + return backtrack(0) +``` + +```java +public class Solution { + int[] letterCnt; + int[] score; + + public int maxScoreWords(String[] words, char[] letters, int[] score) { + this.score = score; + this.letterCnt = new int[26]; + + for (char c : letters) { + letterCnt[c - 'a']++; + } + + return backtrack(0, words); + } + + private int canFormWord(String word) { + int[] wordCnt = new int[26]; + for (char c : word.toCharArray()) { + wordCnt[c - 'a']++; + if (wordCnt[c - 'a'] > letterCnt[c - 'a']) { + return 0; + } + } + return 1; + } + + private int getScore(String word) { + int res = 0; + for (char c : word.toCharArray()) { + res += score[c - 'a']; + } + return res; + } + + private int backtrack(int i, String[] words) { + if (i == words.length) { + return 0; + } + + int res = backtrack(i + 1, words); // skip + if (canFormWord(words[i]) == 1) { // include (when possible) + for (char c : words[i].toCharArray()) { + letterCnt[c - 'a']--; + } + res = Math.max(res, getScore(words[i]) + backtrack(i + 1, words)); + for (char c : words[i].toCharArray()) { + letterCnt[c - 'a']++; + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector letterCnt = vector(26, 0); + vector score; + vector words; + + int maxScoreWords(vector& words, vector& letters, vector& score) { + this->words = words; + this->score = score; + + for (char c : letters) { + letterCnt[c - 'a']++; + } + + return backtrack(0); + } + + bool canFormWord(string& word) { + vector wordCnt(26, 0); + for (char c : word) { + wordCnt[c - 'a']++; + if (wordCnt[c - 'a'] > letterCnt[c - 'a']) { + return false; + } + } + return true; + } + + int getScore(string& word) { + int res = 0; + for (char c : word) { + res += score[c - 'a']; + } + return res; + } + + int backtrack(int i) { + if (i == words.size()) { + return 0; + } + + int res = backtrack(i + 1); // skip + if (canFormWord(words[i])) { // include (when possible) + for (char c : words[i]) { + letterCnt[c - 'a']--; + } + res = max(res, getScore(words[i]) + backtrack(i + 1)); + for (char c : words[i]) { + letterCnt[c - 'a']++; + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} words + * @param {string[]} letters + * @param {number[]} score + * @return {number} + */ + maxScoreWords(words, letters, score) { + const canFormWord = (w, letterCnt) => { + let wordCnt = new Array(26).fill(0); + for (let c of w) { + let idx = c.charCodeAt(0) - 'a'.charCodeAt(0); + wordCnt[idx]++; + if (wordCnt[idx] > letterCnt[idx]) { + return false; + } + } + return true; + }; + + const getScore = (w) => { + let res = 0; + for (let c of w) { + res += score[c.charCodeAt(0) - 'a'.charCodeAt(0)]; + } + return res; + }; + + let letterCnt = new Array(26).fill(0); + for (let c of letters) { + letterCnt[c.charCodeAt(0) - 'a'.charCodeAt(0)]++; + } + + const backtrack = (i) => { + if (i === words.length) { + return 0; + } + + let res = backtrack(i + 1); // skip + + if (canFormWord(words[i], letterCnt)) { // include (when possible) + for (let c of words[i]) { + letterCnt[c.charCodeAt(0) - 'a'.charCodeAt(0)]--; + } + res = Math.max(res, getScore(words[i]) + backtrack(i + 1)); + for (let c of words[i]) { + letterCnt[c.charCodeAt(0) - 'a'.charCodeAt(0)]++; + } + } + + return res; + }; + + return backtrack(0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(2 ^ n * (w + m) + N)$ +* Space complexity: $O(n + w)$ + +> Where $n$ is the number of words, $w$ is the maximum length of a word, $m$ is the size of the array $scores$, and $N$ is the size of the array $letters$. + +--- + +## 2. Bactracking + Precomputation + +::tabs-start + +```python +class Solution: + def maxScoreWords(self, words: List[str], letters: List[str], score: List[int]) -> int: + letter_cnt = [0] * 26 + for c in letters: + letter_cnt[ord(c) - ord('a')] += 1 + + n = len(words) + word_scores = [0] * n + word_freqs = [[0] * 26 for _ in range(n)] + + for i, word in enumerate(words): + for c in word: + idx = ord(c) - ord('a') + word_freqs[i][idx] += 1 + word_scores[i] += score[idx] + + def backtrack(i): + if i == n: + return 0 + + res = backtrack(i + 1) # skip + can_include = all(word_freqs[i][j] <= letter_cnt[j] for j in range(26)) + + if can_include: # include (when possible) + for j in range(26): + letter_cnt[j] -= word_freqs[i][j] + res = max(res, word_scores[i] + backtrack(i + 1)) + for j in range(26): + letter_cnt[j] += word_freqs[i][j] + + return res + + return backtrack(0) +``` + +```java +public class Solution { + private int[] letterCnt = new int[26]; + private int[] wordScores; + private int[][] wordFreqs; + private int n; + + public int maxScoreWords(String[] words, char[] letters, int[] score) { + Arrays.fill(letterCnt, 0); + for (char c : letters) { + letterCnt[c - 'a']++; + } + + n = words.length; + wordScores = new int[n]; + wordFreqs = new int[n][26]; + + for (int i = 0; i < n; i++) { + for (char c : words[i].toCharArray()) { + int idx = c - 'a'; + wordFreqs[i][idx]++; + wordScores[i] += score[idx]; + } + } + + return backtrack(0, words); + } + + private int backtrack(int i, String[] words) { + if (i == n) { + return 0; + } + + int res = backtrack(i + 1, words); // skip + boolean canInclude = true; + + for (int j = 0; j < 26; j++) { + if (wordFreqs[i][j] > letterCnt[j]) { + canInclude = false; + break; + } + } + + if (canInclude) { // include (when possible) + for (int j = 0; j < 26; j++) { + letterCnt[j] -= wordFreqs[i][j]; + } + res = Math.max(res, wordScores[i] + backtrack(i + 1, words)); + for (int j = 0; j < 26; j++) { + letterCnt[j] += wordFreqs[i][j]; + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector letterCnt = vector(26, 0); + vector wordScores; + vector> wordFreqs; + int n; + + int maxScoreWords(vector& words, vector& letters, vector& score) { + fill(letterCnt.begin(), letterCnt.end(), 0); + for (char c : letters) { + letterCnt[c - 'a']++; + } + + n = words.size(); + wordScores = vector(n, 0); + wordFreqs = vector>(n, vector(26, 0)); + + for (int i = 0; i < n; i++) { + for (char c : words[i]) { + int idx = c - 'a'; + wordFreqs[i][idx]++; + wordScores[i] += score[idx]; + } + } + + return backtrack(0, words); + } + +private: + int backtrack(int i, vector& words) { + if (i == n) { + return 0; + } + + int res = backtrack(i + 1, words); // skip + bool canInclude = true; + + for (int j = 0; j < 26; j++) { + if (wordFreqs[i][j] > letterCnt[j]) { + canInclude = false; + break; + } + } + + if (canInclude) { // include (when possible) + for (int j = 0; j < 26; j++) { + letterCnt[j] -= wordFreqs[i][j]; + } + res = max(res, wordScores[i] + backtrack(i + 1, words)); + for (int j = 0; j < 26; j++) { + letterCnt[j] += wordFreqs[i][j]; + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} words + * @param {string[]} letters + * @param {number[]} score + * @return {number} + */ + maxScoreWords(words, letters, score) { + let letterCnt = new Array(26).fill(0); + for (let c of letters) { + letterCnt[c.charCodeAt(0) - 'a'.charCodeAt(0)]++; + } + + let n = words.length; + let wordScores = new Array(n).fill(0); + let wordFreqs = Array.from({ length: n }, () => new Array(26).fill(0)); + + for (let i = 0; i < n; i++) { + for (let c of words[i]) { + let idx = c.charCodeAt(0) - 'a'.charCodeAt(0); + wordFreqs[i][idx]++; + wordScores[i] += score[idx]; + } + } + + const backtrack = (i) => { + if (i === n) { + return 0; + } + + let res = backtrack(i + 1); // skip + let canInclude = true; + + for (let j = 0; j < 26; j++) { + if (wordFreqs[i][j] > letterCnt[j]) { + canInclude = false; + break; + } + } + + if (canInclude) { // include (when possible) + for (let j = 0; j < 26; j++) { + letterCnt[j] -= wordFreqs[i][j]; + } + res = Math.max(res, wordScores[i] + backtrack(i + 1)); + for (let j = 0; j < 26; j++) { + letterCnt[j] += wordFreqs[i][j]; + } + } + + return res; + }; + + return backtrack(0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * 2 ^ n + N)$ +* Space complexity: $O(n + w)$ + +> Where $n$ is the number of words, $w$ is the maximum length of a word, $m$ is the size of the array $scores$, and $N$ is the size of the array $letters$. + +--- + +## 3. Backtracking (Bit Mask) + +::tabs-start + +```python +class Solution: + def maxScoreWords(self, words: List[str], letters: List[str], score: List[int]) -> int: + letter_cnt = [0] * 26 + for c in letters: + letter_cnt[ord(c) - ord('a')] += 1 + + n = len(words) + word_scores = [0] * n + word_freqs = [[0] * 26 for _ in range(n)] + + for i, word in enumerate(words): + for c in word: + idx = ord(c) - ord('a') + word_freqs[i][idx] += 1 + word_scores[i] += score[idx] + + res = 0 + + for mask in range(1 << n): + cur_score = 0 + cur_letter_cnt = letter_cnt[:] + valid = True + + for i in range(n): + if mask & (1 << i): + for j in range(26): + if word_freqs[i][j] > cur_letter_cnt[j]: + valid = False + break + if not valid: + break + + for j in range(26): + cur_letter_cnt[j] -= word_freqs[i][j] + + cur_score += word_scores[i] + + if valid: + res = max(res, cur_score) + + return res +``` + +```java +public class Solution { + public int maxScoreWords(String[] words, char[] letters, int[] score) { + int[] letterCnt = new int[26]; + for (char c : letters) { + letterCnt[c - 'a']++; + } + + int n = words.length; + int[] wordScores = new int[n]; + int[][] wordFreqs = new int[n][26]; + + for (int i = 0; i < n; i++) { + for (char c : words[i].toCharArray()) { + int idx = c - 'a'; + wordFreqs[i][idx]++; + wordScores[i] += score[idx]; + } + } + + int res = 0; + for (int mask = 0; mask < (1 << n); mask++) { + int curScore = 0; + int[] curLetterCnt = Arrays.copyOf(letterCnt, 26); + boolean valid = true; + + for (int i = 0; i < n; i++) { + if ((mask & (1 << i)) != 0) { + for (int j = 0; j < 26; j++) { + if (wordFreqs[i][j] > curLetterCnt[j]) { + valid = false; + break; + } + } + if (!valid) break; + + for (int j = 0; j < 26; j++) { + curLetterCnt[j] -= wordFreqs[i][j]; + } + + curScore += wordScores[i]; + } + } + + if (valid) { + res = Math.max(res, curScore); + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int maxScoreWords(vector& words, vector& letters, vector& score) { + vector letterCnt(26, 0); + for (char c : letters) { + letterCnt[c - 'a']++; + } + + int n = words.size(); + vector wordScores(n, 0); + vector> wordFreqs(n, vector(26, 0)); + + for (int i = 0; i < n; i++) { + for (char c : words[i]) { + int idx = c - 'a'; + wordFreqs[i][idx]++; + wordScores[i] += score[idx]; + } + } + + int res = 0; + for (int mask = 0; mask < (1 << n); mask++) { + int curScore = 0; + vector curLetterCnt = letterCnt; + bool valid = true; + + for (int i = 0; i < n; i++) { + if (mask & (1 << i)) { + for (int j = 0; j < 26; j++) { + if (wordFreqs[i][j] > curLetterCnt[j]) { + valid = false; + break; + } + } + if (!valid) break; + + for (int j = 0; j < 26; j++) { + curLetterCnt[j] -= wordFreqs[i][j]; + } + + curScore += wordScores[i]; + } + } + + if (valid) { + res = max(res, curScore); + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} words + * @param {string[]} letters + * @param {number[]} score + * @return {number} + */ + maxScoreWords(words, letters, score) { + let letterCnt = new Array(26).fill(0); + for (let c of letters) { + letterCnt[c.charCodeAt(0) - 'a'.charCodeAt(0)]++; + } + + let n = words.length; + let wordScores = new Array(n).fill(0); + let wordFreqs = Array.from({ length: n }, () => new Array(26).fill(0)); + + for (let i = 0; i < n; i++) { + for (let c of words[i]) { + let idx = c.charCodeAt(0) - 'a'.charCodeAt(0); + wordFreqs[i][idx]++; + wordScores[i] += score[idx]; + } + } + + let res = 0; + for (let mask = 0; mask < (1 << n); mask++) { + let curScore = 0; + let curLetterCnt = [...letterCnt]; + let valid = true; + + for (let i = 0; i < n; i++) { + if ((mask & (1 << i)) !== 0) { + for (let j = 0; j < 26; j++) { + if (wordFreqs[i][j] > curLetterCnt[j]) { + valid = false; + break; + } + } + if (!valid) break; + + for (let j = 0; j < 26; j++) { + curLetterCnt[j] -= wordFreqs[i][j]; + } + + curScore += wordScores[i]; + } + } + + if (valid) { + res = Math.max(res, curScore); + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * n * 2 ^ n + N)$ +* Space complexity: $O(n + w)$ + +> Where $n$ is the number of words, $w$ is the maximum length of a word, $m$ is the size of the array $scores$, and $N$ is the size of the array $letters$. \ No newline at end of file diff --git a/articles/minimize-maximum-of-array.md b/articles/minimize-maximum-of-array.md new file mode 100644 index 000000000..b851e40b5 --- /dev/null +++ b/articles/minimize-maximum-of-array.md @@ -0,0 +1,210 @@ +## 1. Binary Search + +::tabs-start + +```python +class Solution: + def minimizeArrayValue(self, nums: List[int]) -> int: + def isValid(maxVal): + prefix_sum = 0 + for i in range(len(nums)): + prefix_sum += nums[i] + if prefix_sum > maxVal * (i + 1): + return False + return True + + left, right = 0, max(nums) + while left < right: + mid = left + (right - left) // 2 + if isValid(mid): + right = mid + else: + left = mid + 1 + + return left +``` + +```java +public class Solution { + public int minimizeArrayValue(int[] nums) { + int left = 0, right = 0; + for (int num : nums) { + right = Math.max(right, num); + } + + while (left < right) { + int mid = left + (right - left) / 2; + if (isValid(nums, mid)) { + right = mid; + } else { + left = mid + 1; + } + } + + return left; + } + + private boolean isValid(int[] nums, int maxVal) { + long prefixSum = 0; + for (int i = 0; i < nums.length; i++) { + prefixSum += nums[i]; + if (prefixSum > (long) maxVal * (i + 1)) { + return false; + } + } + return true; + } +} +``` + +```cpp +class Solution { +public: + int minimizeArrayValue(vector& nums) { + int left = 0, right = *max_element(nums.begin(), nums.end()); + + while (left < right) { + int mid = left + (right - left) / 2; + if (isValid(nums, mid)) { + right = mid; + } else { + left = mid + 1; + } + } + + return left; + } + +private: + bool isValid(vector& nums, int maxVal) { + long long prefixSum = 0; + for (int i = 0; i < nums.size(); i++) { + prefixSum += nums[i]; + if (prefixSum > (long long)maxVal * (i + 1)) { + return false; + } + } + return true; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + minimizeArrayValue(nums) { + const isValid = (maxVal) => { + let prefixSum = 0; + for (let i = 0; i < nums.length; i++) { + prefixSum += nums[i]; + if (prefixSum > maxVal * (i + 1)) { + return false; + } + } + return true; + }; + + let left = 0, right = Math.max(...nums); + while (left < right) { + let mid = left + Math.floor((right - left) / 2); + if (isValid(mid)) { + right = mid; + } else { + left = mid + 1; + } + } + + return left; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log m)$ +* Space complexity: $O(1)$ extra space. + +> Where $n$ is the size of the array $nums$ and $m$ is the maximum value in the array. + +--- + +## 2. Prefix Sum + Greedy + +::tabs-start + +```python +class Solution: + def minimizeArrayValue(self, nums: List[int]) -> int: + res = total = nums[0] + + for i in range(1, len(nums)): + total += nums[i] + res = max(res, math.ceil(total / (i + 1))) + + return res +``` + +```java +public class Solution { + public int minimizeArrayValue(int[] nums) { + int res = nums[0]; + long total = nums[0]; + + for (int i = 1; i < nums.length; i++) { + total += nums[i]; + res = Math.max(res, (int) Math.ceil((double) total / (i + 1))); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int minimizeArrayValue(vector& nums) { + int res = nums[0]; + long long total = nums[0]; + + for (int i = 1; i < nums.size(); i++) { + total += nums[i]; + res = max(res, (int)ceil((double)total / (i + 1))); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + minimizeArrayValue(nums) { + let res = nums[0]; + let total = nums[0]; + + for (let i = 1; i < nums.length; i++) { + total += nums[i]; + res = Math.max(res, Math.ceil(total / (i + 1))); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ extra space. \ No newline at end of file diff --git a/articles/minimum-deletions-to-make-character-frequencies-unique.md b/articles/minimum-deletions-to-make-character-frequencies-unique.md new file mode 100644 index 000000000..60c9564fa --- /dev/null +++ b/articles/minimum-deletions-to-make-character-frequencies-unique.md @@ -0,0 +1,348 @@ +## 1. Hash Set + +::tabs-start + +```python +class Solution: + def minDeletions(self, s: str) -> int: + count = [0] * 26 + for c in s: + count[ord(c) - ord('a')] += 1 + + used_freq = set() + res = 0 + for freq in count: + while freq > 0 and freq in used_freq: + freq -= 1 + res += 1 + used_freq.add(freq) + + return res +``` + +```java +class Solution { + public int minDeletions(String s) { + int[] count = new int[26]; + for (int i = 0; i < s.length(); i++) { + count[s.charAt(i) - 'a']++; + } + + Set usedFreq = new HashSet<>(); + int res = 0; + + for (int freq : count) { + while (freq > 0 && usedFreq.contains(freq)) { + freq--; + res++; + } + usedFreq.add(freq); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int minDeletions(string s) { + vector count(26, 0); + for (char& c : s) { + count[c - 'a']++; + } + + unordered_set usedFreq; + int res = 0; + + for (int& freq : count) { + while (freq > 0 && usedFreq.count(freq)) { + freq--; + res++; + } + usedFreq.insert(freq); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {number} + */ + minDeletions(s) { + let count = new Array(26).fill(0); + for (let c of s) { + count[c.charCodeAt(0) - 'a'.charCodeAt(0)]++; + } + + let usedFreq = new Set(); + let res = 0; + + for (let freq of count) { + while (freq > 0 && usedFreq.has(freq)) { + freq--; + res++; + } + usedFreq.add(freq); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n + m ^ 2)$ +* Space complexity: $O(m)$ + +> Where $n$ is the length of the string $s$ and $m$ is the total number of unique frequncies possible. + +--- + +## 2. Max-Heap + +::tabs-start + +```python +class Solution: + def minDeletions(self, s: str) -> int: + freq = Counter(s) + maxHeap = [-f for f in freq.values()] + heapq.heapify(maxHeap) + + res = 0 + while len(maxHeap) > 1: + top = -heapq.heappop(maxHeap) + if top == -maxHeap[0]: + if top - 1 > 0: + heapq.heappush(maxHeap, -(top - 1)) + res += 1 + + return res +``` + +```java +public class Solution { + public int minDeletions(String s) { + Map freq = new HashMap<>(); + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + freq.put(c, freq.getOrDefault(c, 0) + 1); + } + + PriorityQueue maxHeap = new PriorityQueue<>((a, b) -> b - a); + maxHeap.addAll(freq.values()); + + int res = 0; + while (maxHeap.size() > 1) { + int top = maxHeap.poll(); + if (top == maxHeap.peek()) { + if (top - 1 > 0) { + maxHeap.add(top - 1); + } + res++; + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int minDeletions(string s) { + unordered_map freq; + for (char& c : s) { + freq[c]++; + } + + priority_queue maxHeap; + for (auto& f : freq) { + maxHeap.push(f.second); + } + + int res = 0; + while (maxHeap.size() > 1) { + int top = maxHeap.top(); + maxHeap.pop(); + if (top == maxHeap.top()) { + if (top - 1 > 0) { + maxHeap.push(top - 1); + } + res++; + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {number} + */ + minDeletions(s) { + let freq = new Map(); + for (let c of s) { + freq.set(c, (freq.get(c) || 0) + 1); + } + + const maxHeap = new MaxPriorityQueue(); + for (let value of freq.values()) { + maxHeap.enqueue(value); + } + + let res = 0; + while (maxHeap.size() > 1) { + let top = maxHeap.dequeue().element; + if (maxHeap.front().element === top) { + if (top - 1 > 0) { + maxHeap.enqueue(top - 1); + } + res++; + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n + m ^ 2 \log m)$ +* Space complexity: $O(m)$ + +> Where $n$ is the length of the string $s$ and $m$ is the total number of unique frequncies possible. + +--- + +## 3. Sorting + +::tabs-start + +```python +class Solution: + def minDeletions(self, s: str) -> int: + count = [0] * 26 + for c in s: + count[ord(c) - ord('a')] += 1 + + count.sort(reverse=True) + res = 0 + maxAllowedFreq = count[0] + + for freq in count: + if freq > maxAllowedFreq: + res += freq - maxAllowedFreq + freq = maxAllowedFreq + maxAllowedFreq = max(0, freq - 1) + + return res +``` + +```java +public class Solution { + public int minDeletions(String s) { + int[] count = new int[26]; + for (int i = 0; i < s.length(); i++) { + count[s.charAt(i) - 'a']++; + } + + Arrays.sort(count); + int res = 0; + int maxAllowedFreq = count[25]; + + for (int i = 25; i >= 0; i--) { + if (count[i] > maxAllowedFreq) { + res += count[i] - maxAllowedFreq; + count[i] = maxAllowedFreq; + } + maxAllowedFreq = Math.max(0, count[i] - 1); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int minDeletions(string s) { + vector count(26, 0); + for (char& c : s) { + count[c - 'a']++; + } + + sort(count.begin(), count.end(), greater()); + int res = 0; + int maxAllowedFreq = count[0]; + + for (int& freq : count) { + if (freq > maxAllowedFreq) { + res += freq - maxAllowedFreq; + freq = maxAllowedFreq; + } + maxAllowedFreq = max(0, freq - 1); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {number} + */ + minDeletions(s) { + let count = new Array(26).fill(0); + for (let c of s) { + count[c.charCodeAt(0) - 'a'.charCodeAt(0)]++; + } + + count.sort((a, b) => b - a); + + let res = 0; + let maxAllowedFreq = count[0]; + + for (let i = 0; i < 26; i++) { + if (count[i] > maxAllowedFreq) { + res += count[i] - maxAllowedFreq; + count[i] = maxAllowedFreq; + } + maxAllowedFreq = Math.max(0, count[i] - 1); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n + m \log m)$ +* Space complexity: $O(m)$ + +> Where $n$ is the length of the string $s$ and $m$ is the total number of unique frequncies possible. \ No newline at end of file diff --git a/articles/minimum-number-of-arrows-to-burst-balloons.md b/articles/minimum-number-of-arrows-to-burst-balloons.md new file mode 100644 index 000000000..195e1e3e0 --- /dev/null +++ b/articles/minimum-number-of-arrows-to-burst-balloons.md @@ -0,0 +1,183 @@ +## 1. Greedy (Sort By Start Value) + +::tabs-start + +```python +class Solution: + def findMinArrowShots(self, points: List[List[int]]) -> int: + points.sort() + res, prevEnd = len(points), points[0][1] + + for i in range(1, len(points)): + curr = points[i] + if curr[0] <= prevEnd: + res -= 1 + prevEnd = min(curr[1], prevEnd) + else: + prevEnd = curr[1] + + return res +``` + +```java +public class Solution { + public int findMinArrowShots(int[][] points) { + Arrays.sort(points, (a, b) -> Integer.compare(a[0], b[0])); + int res = points.length, prevEnd = points[0][1]; + + for (int i = 1; i < points.length; i++) { + int[] curr = points[i]; + if (curr[0] <= prevEnd) { + res--; + prevEnd = Math.min(curr[1], prevEnd); + } else { + prevEnd = curr[1]; + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int findMinArrowShots(vector>& points) { + sort(points.begin(), points.end()); + int res = points.size(), prevEnd = points[0][1]; + + for (int i = 1; i < points.size(); i++) { + vector& curr = points[i]; + if (curr[0] <= prevEnd) { + res--; + prevEnd = min(curr[1], prevEnd); + } else { + prevEnd = curr[1]; + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} points + * @return {number} + */ + findMinArrowShots(points) { + points.sort((a, b) => a[0] - b[0]); + let res = points.length, prevEnd = points[0][1]; + + for (let i = 1; i < points.length; i++) { + let curr = points[i]; + if (curr[0] <= prevEnd) { + res--; + prevEnd = Math.min(curr[1], prevEnd); + } else { + prevEnd = curr[1]; + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. + +--- + +## 2. Greedy (Sort By End Value) + +::tabs-start + +```python +class Solution: + def findMinArrowShots(self, points: List[List[int]]) -> int: + points.sort(key=lambda x: x[1]) + res, prevEnd = 1, points[0][1] + + for i in range(1, len(points)): + if points[i][0] > prevEnd: + prevEnd = points[i][1] + res += 1 + + return res +``` + +```java +public class Solution { + public int findMinArrowShots(int[][] points) { + Arrays.sort(points, (a, b) -> Integer.compare(a[1], b[1])); + int res = 1, prevEnd = points[0][1]; + + for (int i = 1; i < points.length; i++) { + if (points[i][0] > prevEnd) { + prevEnd = points[i][1]; + res++; + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int findMinArrowShots(vector>& points) { + sort(points.begin(), points.end(), [](const auto& a, const auto& b) { + return a[1] < b[1]; + }); + int res = 1, prevEnd = points[0][1]; + + for (int i = 1; i < points.size(); i++) { + if (points[i][0] > prevEnd) { + prevEnd = points[i][1]; + res++; + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} points + * @return {number} + */ + findMinArrowShots(points) { + points.sort((a, b) => a[1] - b[1]); + let res = 1, prevEnd = points[0][1]; + + for (let i = 1; i < points.length; i++) { + if (points[i][0] > prevEnd) { + prevEnd = points[i][1]; + res++; + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. \ No newline at end of file diff --git a/articles/minimum-number-of-days-to-eat-n-oranges.md b/articles/minimum-number-of-days-to-eat-n-oranges.md new file mode 100644 index 000000000..115da181e --- /dev/null +++ b/articles/minimum-number-of-days-to-eat-n-oranges.md @@ -0,0 +1,354 @@ +## 1. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def minDays(self, n: int) -> int: + dp = {} + + def dfs(n): + if n == 0: + return 0 + if n in dp: + return dp[n] + + res = 1 + dfs(n - 1) + if n % 3 == 0: + res = min(res, 1 + dfs(n // 3)) + if n % 2 == 0: + res = min(res, 1 + dfs(n // 2)) + + dp[n] = res + return res + + return dfs(n) +``` + +```java +public class Solution { + private Map dp = new HashMap<>(); + + public int minDays(int n) { + return dfs(n); + } + + private int dfs(int n) { + if (n == 0) return 0; + if (dp.containsKey(n)) return dp.get(n); + + int res = 1 + dfs(n - 1); + if (n % 3 == 0) res = Math.min(res, 1 + dfs(n / 3)); + if (n % 2 == 0) res = Math.min(res, 1 + dfs(n / 2)); + + dp.put(n, res); + return res; + } +} +``` + +```cpp +class Solution { +public: + unordered_map dp; + + int minDays(int n) { + return dfs(n); + } + + int dfs(int n) { + if (n == 0) return 0; + if (dp.count(n)) return dp[n]; + + int res = 1 + dfs(n - 1); + if (n % 3 == 0) res = min(res, 1 + dfs(n / 3)); + if (n % 2 == 0) res = min(res, 1 + dfs(n / 2)); + + return dp[n] = res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + minDays(n) { + const dp = new Map(); + + const dfs = (n) => { + if (n === 0) return 0; + if (dp.has(n)) return dp.get(n); + + let res = 1 + dfs(n - 1); + if (n % 3 === 0) res = Math.min(res, 1 + dfs(n / 3)); + if (n % 2 === 0) res = Math.min(res, 1 + dfs(n / 2)); + + dp.set(n, res); + return res; + }; + + return dfs(n); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 2. Greedy + Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def minDays(self, n: int) -> int: + dp = {0: 0, 1: 1} + + def dfs(n): + if n in dp: + return dp[n] + + res = 1 + (n % 2) + dfs(n // 2) + res = min(res, 1 + (n % 3) + dfs(n // 3)) + dp[n] = res + return res + + return dfs(n) +``` + +```java +public class Solution { + private Map dp = new HashMap<>(); + + public int minDays(int n) { + dp.put(0, 0); + dp.put(1, 1); + return dfs(n); + } + + private int dfs(int n) { + if (dp.containsKey(n)) return dp.get(n); + + int res = 1 + (n % 2) + dfs(n / 2); + res = Math.min(res, 1 + (n % 3) + dfs(n / 3)); + + dp.put(n, res); + return res; + } +} +``` + +```cpp +class Solution { +public: + unordered_map dp; + + int minDays(int n) { + dp[0] = 0; + dp[1] = 1; + return dfs(n); + } + +private: + int dfs(int n) { + if (dp.count(n)) return dp[n]; + + int res = 1 + (n % 2) + dfs(n / 2); + res = min(res, 1 + (n % 3) + dfs(n / 3)); + + return dp[n] = res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + minDays(n) { + const dp = new Map(); + dp.set(0, 0); + dp.set(1, 1); + + const dfs = (n) => { + if (dp.has(n)) return dp.get(n); + + let res = 1 + (n % 2) + dfs(Math.floor(n / 2)); + res = Math.min(res, 1 + (n % 3) + dfs(Math.floor(n / 3))); + + dp.set(n, res); + return res; + }; + + return dfs(n); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(\log n)$ +* Space complexity: $O(\log n)$ + +--- + +## 3. Breadth First Search + +::tabs-start + +```python +class Solution: + def minDays(self, n: int) -> int: + q = deque([n]) + visit = set() + res = 0 + + while q: + res += 1 + for _ in range(len(q)): + node = q.popleft() + nei = node - 1 + if nei == 0: + return res + if nei not in visit: + visit.add(nei) + q.append(nei) + for d in range(2, 4): + if node % d == 0: + nei = node // d + if nei == 0: + return res + if nei not in visit: + visit.add(nei) + q.append(nei) + return res +``` + +```java +public class Solution { + public int minDays(int n) { + Queue q = new LinkedList<>(); + Set visit = new HashSet<>(); + q.offer(n); + int res = 0; + + while (!q.isEmpty()) { + res++; + for (int i = q.size(); i > 0; i--) { + int node = q.poll(); + int nei = node - 1; + if (nei == 0) return res; + if (!visit.contains(nei)) { + visit.add(nei); + q.offer(nei); + } + for (int d = 2; d <= 3; d++) { + if (node % d == 0) { + nei = node / d; + if (nei == 0) return res; + if (!visit.contains(nei)) { + visit.add(nei); + q.offer(nei); + } + } + } + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int minDays(int n) { + queue q; + unordered_set visit; + q.push(n); + int res = 0; + + while (!q.empty()) { + res++; + for (int i = q.size(); i > 0; i--) { + int node = q.front(); q.pop(); + int nei = node - 1; + if (nei == 0) return res; + if (visit.find(nei) == visit.end()) { + visit.insert(nei); + q.push(nei); + } + for (int d = 2; d <= 3; d++) { + if (node % d == 0) { + nei = node / d; + if (nei == 0) return res; + if (visit.find(nei) == visit.end()) { + visit.insert(nei); + q.push(nei); + } + } + } + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + minDays(n) { + const q = new Queue([n]); + const visit = new Set(); + let res = 0; + + while (!q.isEmpty()) { + res++; + for (let i = q.size(); i > 0; i--) { + let node = q.pop(); + let nei = node - 1; + if (nei === 0) return res; + if (!visit.has(nei)) { + visit.add(nei); + q.push(nei); + } + for (let d = 2; d <= 3; d++) { + if (node % d === 0) { + nei = Math.floor(node / d); + if (nei === 0) return res; + if (!visit.has(nei)) { + visit.add(nei); + q.push(nei); + } + } + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(\log n)$ +* Space complexity: $O(\log n)$ \ No newline at end of file diff --git a/articles/minimum-number-of-vertices-to-reach-all-nodes.md b/articles/minimum-number-of-vertices-to-reach-all-nodes.md new file mode 100644 index 000000000..aa09f1c80 --- /dev/null +++ b/articles/minimum-number-of-vertices-to-reach-all-nodes.md @@ -0,0 +1,465 @@ +## 1. Depth First Search + +::tabs-start + +```python +class Solution: + def findSmallestSetOfVertices(self, n: int, edges: List[List[int]]) -> List[int]: + adj = [[] for _ in range(n)] + for u, v in edges: + adj[u].append(v) + + res = set(range(n)) + visited = [False] * n + + def dfs(node): + visited[node] = True + for nei in adj[node]: + if not visited[nei]: + dfs(nei) + res.discard(nei) + + for i in range(n): + if not visited[i]: + dfs(i) + return list(res) +``` + +```java +public class Solution { + public List findSmallestSetOfVertices(int n, List> edges) { + List[] adj = new ArrayList[n]; + for (int i = 0; i < n; i++) adj[i] = new ArrayList<>(); + for (List edge : edges) { + adj[edge.get(0)].add(edge.get(1)); + } + + Set res = new HashSet<>(); + for (int i = 0; i < n; i++) { + res.add(i); + } + + boolean[] visited = new boolean[n]; + for (int i = 0; i < n; i++) { + dfs(i, adj, visited, res); + } + return new ArrayList<>(res); + } + + private void dfs(int node, List[] adj, boolean[] visited, Set res) { + visited[node] = true; + for (int nei : adj[node]) { + if (!visited[nei]) dfs(nei, adj, visited, res); + res.remove(nei); + } + } +} +``` + +```cpp +class Solution { +public: + vector findSmallestSetOfVertices(int n, vector>& edges) { + vector> adj(n); + for (auto& edge : edges) { + adj[edge[0]].push_back(edge[1]); + } + + unordered_set res; + vector visited(n, false); + for (int i = 0; i < n; i++) res.insert(i); + + function dfs = [&](int node) { + visited[node] = true; + for (int& nei : adj[node]) { + if (!visited[nei]) dfs(nei); + res.erase(nei); + } + }; + + for (int i = 0; i < n; i++) { + if (!visited[i]) dfs(i); + } + return vector(res.begin(), res.end()); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number[][]} edges + * @return {number[]} + */ + findSmallestSetOfVertices(n, edges) { + const adj = Array.from({ length: n }, () => []); + for (const [u, v] of edges) { + adj[u].push(v); + } + + const res = new Set(Array.from({ length: n }, (_, i) => i)); + const visited = new Array(n).fill(false); + + const dfs = (node) => { + visited[node] = true; + for (const nei of adj[node]) { + if (!visited[nei]) dfs(nei); + res.delete(nei); + } + }; + + for (let i = 0; i < n; i++) { + if (!visited[i]) dfs(i); + } + + return Array.from(res); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(V + E)$ +* Space complexity: $O(V + E)$ + +> Where $V$ is the number of vertices and $E$ is the number of edges. + +--- + +## 2. Iterative DFS + +::tabs-start + +```python +class Solution: + def findSmallestSetOfVertices(self, n: int, edges: List[List[int]]) -> List[int]: + adj = [[] for _ in range(n)] + for u, v in edges: + adj[u].append(v) + + res = [True] * n + visited = [False] * n + stack = [] + + for i in range(n): + if not visited[i]: + stack.append(i) + while stack: + node = stack.pop() + if visited[node]: + continue + visited[node] = True + for nei in adj[node]: + if not visited[nei]: + stack.append(nei) + res[nei] = False + + return [i for i in range(n) if res[i]] +``` + +```java +public class Solution { + public List findSmallestSetOfVertices(int n, List> edges) { + List[] adj = new ArrayList[n]; + for (int i = 0; i < n; i++) { + adj[i] = new ArrayList<>(); + } + for (List edge : edges) { + adj[edge.get(0)].add(edge.get(1)); + } + + boolean[] res = new boolean[n]; + Arrays.fill(res, true); + boolean[] visited = new boolean[n]; + Stack stack = new Stack<>(); + + for (int i = 0; i < n; i++) { + if (!visited[i]) { + stack.push(i); + while (!stack.isEmpty()) { + int node = stack.pop(); + if (visited[node]) continue; + visited[node] = true; + for (int nei : adj[node]) { + if (!visited[nei]) stack.push(nei); + res[nei] = false; + } + } + } + } + + List result = new ArrayList<>(); + for (int i = 0; i < n; i++) { + if (res[i]) result.add(i); + } + return result; + } +} +``` + +```cpp +class Solution { +public: + vector findSmallestSetOfVertices(int n, vector>& edges) { + vector> adj(n); + for (auto& edge : edges) { + adj[edge[0]].push_back(edge[1]); + } + + vector res(n, true), visited(n, false); + stack stack; + + for (int i = 0; i < n; i++) { + if (!visited[i]) { + stack.push(i); + while (!stack.empty()) { + int node = stack.top(); + stack.pop(); + if (visited[node]) continue; + visited[node] = true; + for (int nei : adj[node]) { + if (!visited[nei]) stack.push(nei); + res[nei] = false; + } + } + } + } + + vector result; + for (int i = 0; i < n; i++) { + if (res[i]) result.push_back(i); + } + return result; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number[][]} edges + * @return {number[]} + */ + findSmallestSetOfVertices(n, edges) { + const adj = Array.from({ length: n }, () => []); + for (const [u, v] of edges) { + adj[u].push(v); + } + + const res = Array(n).fill(true); + const visited = Array(n).fill(false); + const stack = []; + + for (let i = 0; i < n; i++) { + if (!visited[i]) { + stack.push(i); + while (stack.length) { + const node = stack.pop(); + if (visited[node]) continue; + visited[node] = true; + for (const nei of adj[node]) { + if (!visited[nei]) stack.push(nei); + res[nei] = false; + } + } + } + } + + return res.map((val, i) => val ? i : -1).filter(i => i !== -1); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(V + E)$ +* Space complexity: $O(V + E)$ + +> Where $V$ is the number of vertices and $E$ is the number of edges. + +--- + +## 3. Indegree Count + +::tabs-start + +```python +class Solution: + def findSmallestSetOfVertices(self, n: int, edges: List[List[int]]) -> List[int]: + incoming = collections.defaultdict(list) + for src, dst in edges: + incoming[dst].append(src) + + res = [] + for i in range(n): + if not incoming[i]: + res.append(i) + return res +``` + +```java +public class Solution { + public List findSmallestSetOfVertices(int n, List> edges) { + List[] incoming = new ArrayList[n]; + for (int i = 0; i < n; i++) { + incoming[i] = new ArrayList<>(); + } + for (List edge : edges) { + incoming[edge.get(1)].add(edge.get(0)); + } + + List res = new ArrayList<>(); + for (int i = 0; i < n; i++) { + if (incoming[i].isEmpty()) { + res.add(i); + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + vector findSmallestSetOfVertices(int n, vector>& edges) { + vector> incoming(n); + for (auto& edge : edges) { + incoming[edge[1]].push_back(edge[0]); + } + + vector res; + for (int i = 0; i < n; i++) { + if (incoming[i].empty()) { + res.push_back(i); + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number[][]} edges + * @return {number[]} + */ + findSmallestSetOfVertices(n, edges) { + const incoming = Array.from({ length: n }, () => []); + + for (const [src, dst] of edges) { + incoming[dst].push(src); + } + + const res = []; + for (let i = 0; i < n; i++) { + if (incoming[i].length === 0) { + res.push(i); + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(V + E)$ +* Space complexity: $O(V)$ + +> Where $V$ is the number of vertices and $E$ is the number of edges. + +--- + +## 4. Indegree Count + +::tabs-start + +```python +class Solution: + def findSmallestSetOfVertices(self, n: int, edges: List[List[int]]) -> List[int]: + indegree = [False] * n + for src, dst in edges: + indegree[dst] = True + return [i for i in range(n) if not indegree[i]] +``` + +```java +public class Solution { + public List findSmallestSetOfVertices(int n, List> edges) { + boolean[] indegree = new boolean[n]; + for (List edge : edges) { + indegree[edge.get(1)] = true; + } + + List res = new ArrayList<>(); + for (int i = 0; i < n; i++) { + if (!indegree[i]) { + res.add(i); + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + vector findSmallestSetOfVertices(int n, vector>& edges) { + vector indegree(n, false); + for (const auto& edge : edges) { + indegree[edge[1]] = true; + } + + vector res; + for (int i = 0; i < n; i++) { + if (!indegree[i]) { + res.push_back(i); + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number[][]} edges + * @return {number[]} + */ + findSmallestSetOfVertices(n, edges) { + const indegree = new Array(n).fill(false); + for (const [src, dst] of edges) { + indegree[dst] = true; + } + + let res = []; + for (let i = 0; i < n; i++) { + if (!indegree[i]) res.push(i); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(V + E)$ +* Space complexity: $O(V)$ + +> Where $V$ is the number of vertices and $E$ is the number of edges. \ No newline at end of file diff --git a/articles/minimum-one-bit-operations-to-make-integers-zero.md b/articles/minimum-one-bit-operations-to-make-integers-zero.md new file mode 100644 index 000000000..7e4071ce6 --- /dev/null +++ b/articles/minimum-one-bit-operations-to-make-integers-zero.md @@ -0,0 +1,313 @@ +## 1. Math (Recursion) + +::tabs-start + +```python +class Solution: + def minimumOneBitOperations(self, n: int) -> int: + if n == 0: + return 0 + + k = 1 + while (k << 1) <= n: + k <<= 1 + + return (k << 1) - 1 - self.minimumOneBitOperations(k ^ n) +``` + +```java +public class Solution { + public int minimumOneBitOperations(int n) { + if (n == 0) { + return 0; + } + + int k = 1; + while ((k << 1) <= n) { + k <<= 1; + } + + return (k << 1) - 1 - minimumOneBitOperations(k ^ n); + } +} +``` + +```cpp +class Solution { +public: + int minimumOneBitOperations(int n) { + if (n == 0) { + return 0; + } + + int k = 1; + while ((k << 1) <= n) { + k <<= 1; + } + + return (k << 1) - 1 - minimumOneBitOperations(k ^ n); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + minimumOneBitOperations(n) { + if (n === 0) { + return 0; + } + + let k = 1; + while ((k << 1) <= n) { + k <<= 1; + } + + return (k << 1) - 1 - this.minimumOneBitOperations(k ^ n); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(\log n)$ +* Space complexity: $O(\log n)$ for recursion stack. + +--- + +## 2. Math (Iteration) - I + +::tabs-start + +```python +class Solution: + def minimumOneBitOperations(self, n: int) -> int: + res = 0 + k = 1 << 30 + sign = 1 + + while n: + while k > n: + k >>= 1 + + res += (sign * ((k << 1) - 1)) + sign *= -1 + n ^= k + + return res +``` + +```java +public class Solution { + public int minimumOneBitOperations(int n) { + int res = 0, k = 1 << 30, sign = 1; + + while (n != 0) { + while (k > n) { + k >>= 1; + } + + res += (sign * ((k << 1) - 1)); + sign *= -1; + n ^= k; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int minimumOneBitOperations(int n) { + int res = 0, k = 1 << 30, sign = 1; + + while (n != 0) { + while (k > n) { + k >>= 1; + } + + res += sign * ((k << 1) - 1); + sign *= -1; + n ^= k; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + minimumOneBitOperations(n) { + let res = 0, k = 1 << 30, sign = 1; + + while (n !== 0) { + while (k > n) { + k >>= 1; + } + + res += sign * ((k << 1) - 1); + sign *= -1; + n ^= k; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(\log n)$ +* Space complexity: $O(1)$ + +--- + +## 3. Math (Iteration) - II + +::tabs-start + +```python +class Solution: + def minimumOneBitOperations(self, n: int) -> int: + res, sign = 0, 1 + while n: + res += sign * (n ^ (n - 1)) + n &= (n - 1) + sign *= -1 + return abs(res) +``` + +```java +public class Solution { + public int minimumOneBitOperations(int n) { + int res = 0, sign = 1; + while (n != 0) { + res += sign * (n ^ (n - 1)); + n &= (n - 1); + sign *= -1; + } + return Math.abs(res); + } +} +``` + +```cpp +class Solution { +public: + int minimumOneBitOperations(int n) { + int res = 0, sign = 1; + while (n != 0) { + res += sign * (n ^ (n - 1)); + n &= (n - 1); + sign *= -1; + } + return abs(res); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + minimumOneBitOperations(n) { + let res = 0, sign = 1; + while (n !== 0) { + res += sign * (n ^ (n - 1)); + n &= (n - 1); + sign *= -1; + } + return Math.abs(res); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(\log n)$ +* Space complexity: $O(1)$ + +--- + +## 4. Math (Grey Code) + +::tabs-start + +```python +class Solution: + def minimumOneBitOperations(self, n: int) -> int: + res = n + while n: + n >>= 1 + res ^= n + return res +``` + +```java +public class Solution { + public int minimumOneBitOperations(int n) { + int res = n; + while (n != 0) { + n >>= 1; + res ^= n; + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int minimumOneBitOperations(int n) { + int res = n; + while (n != 0) { + n >>= 1; + res ^= n; + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + minimumOneBitOperations(n) { + let res = n; + while (n !== 0) { + n >>= 1; + res ^= n; + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(\log n)$ +* Space complexity: $O(1)$ \ No newline at end of file diff --git a/articles/number-of-good-paths.md b/articles/number-of-good-paths.md new file mode 100644 index 000000000..f0e16529f --- /dev/null +++ b/articles/number-of-good-paths.md @@ -0,0 +1,861 @@ +## 1. Brute Force (DFS) + +::tabs-start + +```python +class Solution: + def numberOfGoodPaths(self, vals: List[int], edges: List[List[int]]) -> int: + n = len(vals) + adj = [[] for _ in range(n)] + for u, v in edges: + adj[u].append(v) + adj[v].append(u) + + def dfs(node, startNode, parent): + if vals[node] > vals[startNode]: + return 0 + + res = 0 + if vals[node] == vals[startNode] and node >= startNode: + res += 1 + + for child in adj[node]: + if child == parent: + continue + res += dfs(child, startNode, node) + + return res + + + res = 0 + for node in range(n): + res += dfs(node, node, -1) + return res +``` + +```java +public class Solution { + public int numberOfGoodPaths(int[] vals, int[][] edges) { + int n = vals.length; + List[] adj = new ArrayList[n]; + for (int i = 0; i < n; i++) { + adj[i] = new ArrayList<>(); + } + for (int[] edge : edges) { + adj[edge[0]].add(edge[1]); + adj[edge[1]].add(edge[0]); + } + + int res = 0; + for (int node = 0; node < n; node++) { + res += dfs(node, node, -1, vals, adj); + } + return res; + } + + private int dfs(int node, int startNode, int parent, int[] vals, List[] adj) { + if (vals[node] > vals[startNode]) { + return 0; + } + + int res = 0; + if (vals[node] == vals[startNode] && node >= startNode) { + res += 1; + } + + for (int child : adj[node]) { + if (child == parent) { + continue; + } + res += dfs(child, startNode, node, vals, adj); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int numberOfGoodPaths(vector& vals, vector>& edges) { + int n = vals.size(); + vector> adj(n); + for (auto& edge : edges) { + adj[edge[0]].push_back(edge[1]); + adj[edge[1]].push_back(edge[0]); + } + + int res = 0; + for (int node = 0; node < n; node++) { + res += dfs(node, node, -1, vals, adj); + } + return res; + } + +private: + int dfs(int node, int startNode, int parent, vector& vals, vector>& adj) { + if (vals[node] > vals[startNode]) { + return 0; + } + + int res = 0; + if (vals[node] == vals[startNode] && node >= startNode) { + res += 1; + } + + for (int child : adj[node]) { + if (child == parent) { + continue; + } + res += dfs(child, startNode, node, vals, adj); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} vals + * @param {number[][]} edges + * @return {number} + */ + numberOfGoodPaths(vals, edges) { + const n = vals.length; + const adj = Array.from({ length: n }, () => []); + + for (const [u, v] of edges) { + adj[u].push(v); + adj[v].push(u); + } + + const dfs = (node, startNode, parent) => { + if (vals[node] > vals[startNode]) { + return 0; + } + + let res = 0; + if (vals[node] === vals[startNode] && node >= startNode) { + res += 1; + } + + for (const child of adj[node]) { + if (child === parent) continue; + res += dfs(child, startNode, node); + } + return res; + }; + + let res = 0; + for (let node = 0; node < n; node++) { + res += dfs(node, node, -1); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n)$ for recursion stack. + +--- + +## 2. Brute Force (BFS) + +::tabs-start + +```python +class Solution: + def numberOfGoodPaths(self, vals, edges): + n = len(vals) + adj = [[] for _ in range(n)] + for u, v in edges: + adj[u].append(v) + adj[v].append(u) + + res = 0 + for startNode in range(n): + q = deque([startNode]) + visited = set([startNode]) + count = 0 + + while q: + node = q.popleft() + if vals[node] == vals[startNode] and node >= startNode: + count += 1 + + for child in adj[node]: + if child not in visited and vals[child] <= vals[startNode]: + visited.add(child) + q.append(child) + + res += count + + return res +``` + +```java +public class Solution { + public int numberOfGoodPaths(int[] vals, int[][] edges) { + int n = vals.length; + List[] adj = new ArrayList[n]; + for (int i = 0; i < n; i++) { + adj[i] = new ArrayList<>(); + } + for (int[] edge : edges) { + adj[edge[0]].add(edge[1]); + adj[edge[1]].add(edge[0]); + } + + int res = 0; + for (int startNode = 0; startNode < n; startNode++) { + Queue q = new LinkedList<>(); + Set visited = new HashSet<>(); + q.offer(startNode); + visited.add(startNode); + int count = 0; + + while (!q.isEmpty()) { + int node = q.poll(); + if (vals[node] == vals[startNode] && node >= startNode) { + count++; + } + + for (int child : adj[node]) { + if (!visited.contains(child) && vals[child] <= vals[startNode]) { + visited.add(child); + q.offer(child); + } + } + } + + res += count; + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int numberOfGoodPaths(vector& vals, vector>& edges) { + int n = vals.size(); + vector> adj(n); + for (auto& edge : edges) { + adj[edge[0]].push_back(edge[1]); + adj[edge[1]].push_back(edge[0]); + } + + int res = 0; + for (int startNode = 0; startNode < n; startNode++) { + queue q; + unordered_set visited; + q.push(startNode); + visited.insert(startNode); + int count = 0; + + while (!q.empty()) { + int node = q.front(); + q.pop(); + if (vals[node] == vals[startNode] && node >= startNode) { + count++; + } + + for (int child : adj[node]) { + if (visited.find(child) == visited.end() && vals[child] <= vals[startNode]) { + visited.insert(child); + q.push(child); + } + } + } + + res += count; + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} vals + * @param {number[][]} edges + * @return {number} + */ + numberOfGoodPaths(vals, edges) { + const n = vals.length; + const adj = Array.from({ length: n }, () => []); + + for (const [u, v] of edges) { + adj[u].push(v); + adj[v].push(u); + } + + let res = 0; + for (let startNode = 0; startNode < n; startNode++) { + const q = new Queue([startNode]); + const visited = new Set([startNode]); + let count = 0; + + while (q.length) { + let node = q.shift(); + if (vals[node] === vals[startNode] && node >= startNode) { + count++; + } + + for (const child of adj[node]) { + if (!visited.has(child) && vals[child] <= vals[startNode]) { + visited.add(child); + q.push(child); + } + } + } + + res += count; + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n)$ + +--- + +## 3. Disjoint Set Union + +::tabs-start + +```python +class DSU: + def __init__(self, n): + self.Parent = list(range(n + 1)) + self.Size = [1] * (n + 1) + + def find(self, node): + if self.Parent[node] != node: + self.Parent[node] = self.find(self.Parent[node]) + return self.Parent[node] + + def union(self, u, v): + pu, pv = self.find(u), self.find(v) + if pu == pv: + return False + if self.Size[pu] >= self.Size[pv]: + self.Size[pu] += self.Size[pv] + self.Parent[pv] = pu + else: + self.Size[pv] += self.Size[pu] + self.Parent[pu] = pv + return True + +class Solution: + def numberOfGoodPaths(self, vals: List[int], edges: List[List[int]]) -> int: + adj = collections.defaultdict(list) + for a, b in edges: + adj[a].append(b) + adj[b].append(a) + + valToIndex = collections.defaultdict(list) + for i, val in enumerate(vals): + valToIndex[val].append(i) + + res = 0 + uf = DSU(len(vals)) + + for val in sorted(valToIndex.keys()): + for i in valToIndex[val]: + for nei in adj[i]: + if vals[nei] <= vals[i]: + uf.union(nei, i) + + count = collections.defaultdict(int) + for i in valToIndex[val]: + count[uf.find(i)] += 1 + res += count[uf.find(i)] + + return res +``` + +```java +class DSU { + private int[] parent, size; + + public DSU(int n) { + parent = new int[n + 1]; + size = new int[n + 1]; + for (int i = 0; i <= n; i++) { + parent[i] = i; + size[i] = 1; + } + } + + public int find(int node) { + if (parent[node] != node) { + parent[node] = find(parent[node]); + } + return parent[node]; + } + + public boolean union(int u, int v) { + int pu = find(u), pv = find(v); + if (pu == pv) return false; + if (size[pu] >= size[pv]) { + size[pu] += size[pv]; + parent[pv] = pu; + } else { + size[pv] += size[pu]; + parent[pu] = pv; + } + return true; + } +} + +public class Solution { + public int numberOfGoodPaths(int[] vals, int[][] edges) { + int n = vals.length; + List[] adj = new ArrayList[n]; + for (int i = 0; i < n; i++) adj[i] = new ArrayList<>(); + + for (int[] edge : edges) { + adj[edge[0]].add(edge[1]); + adj[edge[1]].add(edge[0]); + } + + TreeMap> valToIndex = new TreeMap<>(); + for (int i = 0; i < n; i++) { + valToIndex.putIfAbsent(vals[i], new ArrayList<>()); + valToIndex.get(vals[i]).add(i); + } + + DSU dsu = new DSU(n); + int res = 0; + + for (int val : valToIndex.keySet()) { + for (int i : valToIndex.get(val)) { + for (int nei : adj[i]) { + if (vals[nei] <= vals[i]) dsu.union(nei, i); + } + } + + Map count = new HashMap<>(); + for (int i : valToIndex.get(val)) { + int root = dsu.find(i); + count.put(root, count.getOrDefault(root, 0) + 1); + res += count.get(root); + } + } + return res; + } +} +``` + +```cpp +class DSU { +public: + vector parent, size; + + DSU(int n) { + parent.resize(n + 1); + size.resize(n + 1, 1); + for (int i = 0; i <= n; i++) parent[i] = i; + } + + int find(int node) { + if (parent[node] != node) parent[node] = find(parent[node]); + return parent[node]; + } + + bool unite(int u, int v) { + int pu = find(u), pv = find(v); + if (pu == pv) return false; + if (size[pu] >= size[pv]) { + size[pu] += size[pv]; + parent[pv] = pu; + } else { + size[pv] += size[pu]; + parent[pu] = pv; + } + return true; + } +}; + +class Solution { +public: + int numberOfGoodPaths(vector& vals, vector>& edges) { + int n = vals.size(); + vector> adj(n); + for (auto& edge : edges) { + adj[edge[0]].push_back(edge[1]); + adj[edge[1]].push_back(edge[0]); + } + + map> valToIndex; + for (int i = 0; i < n; i++) valToIndex[vals[i]].push_back(i); + + DSU dsu(n); + int res = 0; + + for (auto& [val, nodes] : valToIndex) { + for (int& i : nodes) { + for (int& nei : adj[i]) { + if (vals[nei] <= vals[i]) dsu.unite(nei, i); + } + } + + unordered_map count; + for (int& i : nodes) { + int root = dsu.find(i); + count[root]++; + res += count[root]; + } + } + return res; + } +}; +``` + +```javascript +class DSU { + /** + * @constructor + * @param {number} n + */ + constructor(n) { + this.parent = Array.from({ length: n + 1 }, (_, i) => i); + this.size = new Array(n + 1).fill(1); + } + + /** + * @param {number} node + * @return {number} + */ + find(node) { + if (this.parent[node] !== node) { + this.parent[node] = this.find(this.parent[node]); + } + return this.parent[node]; + } + + /** + * @param {number} u + * @param {number} u=v + * @return {boolean} + */ + union(u, v) { + let pu = this.find(u), pv = this.find(v); + if (pu === pv) return false; + if (this.size[pu] >= this.size[pv]) { + this.size[pu] += this.size[pv]; + this.parent[pv] = pu; + } else { + this.size[pv] += this.size[pu]; + this.parent[pu] = pv; + } + return true; + } +} + +class Solution { + /** + * @param {number[]} vals + * @param {number[][]} edges + * @return {number} + */ + numberOfGoodPaths(vals, edges) { + const n = vals.length; + const adj = Array.from({ length: n }, () => []); + + for (const [u, v] of edges) { + adj[u].push(v); + adj[v].push(u); + } + + const valToIndex = new Map(); + for (let i = 0; i < n; i++) { + if (!valToIndex.has(vals[i])) valToIndex.set(vals[i], []); + valToIndex.get(vals[i]).push(i); + } + + const dsu = new DSU(n); + let res = 0; + + for (const [val, nodes] of [...valToIndex.entries()].sort((a, b) => a[0] - b[0])) { + for (const i of nodes) { + for (const nei of adj[i]) { + if (vals[nei] <= vals[i]) dsu.union(nei, i); + } + } + + const count = new Map(); + for (const i of nodes) { + const root = dsu.find(i); + count.set(root, (count.get(root) || 0) + 1); + res += count.get(root); + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(n)$ + +--- + +## 4. Disjoint Set Union (Union By Value) + +::tabs-start + +```python +class DSU: + def __init__(self, n, vals): + self.parent = list(range(n)) + self.vals = vals + self.count = [1] * n # count of nodes with max value of the component + + def find(self, node): + if self.parent[node] != node: + self.parent[node] = self.find(self.parent[node]) + return self.parent[node] + + def union(self, u, v): + pu, pv = self.find(u), self.find(v) + if pu == pv: + return 0 + if self.vals[pu] < self.vals[pv]: + self.parent[pu] = pv + elif self.vals[pu] > self.vals[pv]: + self.parent[pv] = pu + else: + self.parent[pv] = pu + result = self.count[pu] * self.count[pv] + self.count[pu] += self.count[pv] + return result + + return 0 + + +class Solution: + def numberOfGoodPaths(self, vals: List[int], edges: List[List[int]]) -> int: + n = len(vals) + dsu = DSU(n, vals) + + # Sort edges based on max value of the two nodes + edges.sort(key=lambda edge: max(vals[edge[0]], vals[edge[1]])) + + res = n # Each node alone is a good path + for u, v in edges: + res += dsu.union(u, v) + return res +``` + +```java +class DSU { + private int[] parent, count, vals; + + public DSU(int n, int[] vals) { + this.parent = new int[n]; + this.vals = vals; + this.count = new int[n]; // count of nodes with max value of the component + Arrays.fill(count, 1); + + for (int i = 0; i < n; i++) { + parent[i] = i; + } + } + + public int find(int node) { + if (parent[node] != node) { + parent[node] = find(parent[node]); + } + return parent[node]; + } + + public int union(int u, int v) { + int pu = find(u), pv = find(v); + if (pu == pv) { + return 0; + } + if (vals[pu] < vals[pv]) { + parent[pu] = pv; + } else if (vals[pu] > vals[pv]) { + parent[pv] = pu; + } else { + parent[pv] = pu; + int result = count[pu] * count[pv]; + count[pu] += count[pv]; + return result; + } + return 0; + } +} + +public class Solution { + public int numberOfGoodPaths(int[] vals, int[][] edges) { + int n = vals.length; + DSU dsu = new DSU(n, vals); + + // Sort edges based on max value of the two nodes + Arrays.sort(edges, + Comparator.comparingInt(edge -> Math.max(vals[edge[0]], vals[edge[1]])) + ); + + int res = n; // Each node alone is a good path + for (int[] edge : edges) { + res += dsu.union(edge[0], edge[1]); + } + return res; + } +} +``` + +```cpp +class DSU { + vector parent, count, vals; + +public: + DSU(int n, vector& vals) : vals(vals), parent(n), count(n, 1) { + for (int i = 0; i < n; i++) parent[i] = i; + } + + int find(int node) { + if (parent[node] != node) { + parent[node] = find(parent[node]); + } + return parent[node]; + } + + int unionNodes(int u, int v) { + int pu = find(u), pv = find(v); + if (pu == pv) { + return 0; + } + if (vals[pu] < vals[pv]) { + parent[pu] = pv; + } else if (vals[pu] > vals[pv]) { + parent[pv] = pu; + } else { + parent[pv] = pu; + int result = count[pu] * count[pv]; + count[pu] += count[pv]; + return result; + } + return 0; + } +}; + +class Solution { +public: + int numberOfGoodPaths(vector& vals, vector>& edges) { + int n = vals.size(); + DSU dsu(n, vals); + + // Sort edges based on max value of the two nodes + sort(edges.begin(), edges.end(), [&](auto& a, auto& b) { + return max(vals[a[0]], vals[a[1]]) < max(vals[b[0]], vals[b[1]]); + }); + + int res = n; // Each node alone is a good path + for (auto& edge : edges) { + res += dsu.unionNodes(edge[0], edge[1]); + } + return res; + } +}; +``` + +```javascript +class DSU { + /** + * @param {number} n + * @param {number[]} vals + */ + constructor(n, vals) { + this.parent = Array(n).fill(0).map((_, i) => i); + this.vals = vals; + this.count = Array(n).fill(1); // count of nodes with max value of the component + } + + /** + * @param {number} node + * @return {number} + */ + find(node) { + if (this.parent[node] !== node) { + this.parent[node] = this.find(this.parent[node]); + } + return this.parent[node]; + } + + /** + * @param {number} u + * @param {number} v + * @return {number} + */ + union(u, v) { + let pu = this.find(u), pv = this.find(v); + if (pu === pv) { + return 0; + } + if (this.vals[pu] < this.vals[pv]) { + this.parent[pu] = pv; + } else if (this.vals[pu] > this.vals[pv]) { + this.parent[pv] = pu; + } else { + this.parent[pv] = pu; + let result = this.count[pu] * this.count[pv]; + this.count[pu] += this.count[pv]; + return result; + } + return 0; + } +} + +class Solution { + /** + * @param {number[]} vals + * @param {number[][]} edges + * @return {number} + */ + numberOfGoodPaths(vals, edges) { + let n = vals.length; + let dsu = new DSU(n, vals); + + // Sort edges based on max value of the two nodes + edges.sort((a, b) => + Math.max(vals[a[0]], vals[a[1]]) - Math.max(vals[b[0]], vals[b[1]]) + ); + + let res = n; // Each node alone is a good path + for (let [u, v] of edges) { + res += dsu.union(u, v); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n\log n)$ +* Space complexity: $O(n)$ \ No newline at end of file diff --git a/articles/number-of-laser-beams-in-a-bank.md b/articles/number-of-laser-beams-in-a-bank.md new file mode 100644 index 000000000..598d7fbb2 --- /dev/null +++ b/articles/number-of-laser-beams-in-a-bank.md @@ -0,0 +1,110 @@ +## 1. Counting + +::tabs-start + +```python +class Solution: + def numberOfBeams(self, bank: List[str]) -> int: + prev = bank[0].count("1") + res = 0 + + for i in range(1, len(bank)): + curr = bank[i].count("1") + if curr: + res += prev * curr + prev = curr + + return res +``` + +```java +public class Solution { + public int numberOfBeams(String[] bank) { + int prev = countOnes(bank[0]); + int res = 0; + + for (int i = 1; i < bank.length; i++) { + int curr = countOnes(bank[i]); + if (curr > 0) { + res += prev * curr; + prev = curr; + } + } + + return res; + } + + private int countOnes(String s) { + int count = 0; + for (int i = 0; i < s.length(); i++) { + if (s.charAt(i) == '1') count++; + } + return count; + } +} +``` + +```cpp +class Solution { +public: + int numberOfBeams(vector& bank) { + int prev = countOnes(bank[0]); + int res = 0; + + for (int i = 1; i < bank.size(); i++) { + int curr = countOnes(bank[i]); + if (curr > 0) { + res += prev * curr; + prev = curr; + } + } + + return res; + } + +private: + int countOnes(const string& s) { + return count(s.begin(), s.end(), '1'); + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} bank + * @return {number} + */ + numberOfBeams(bank) { + const countOnes = (s) => { + let cnt = 0; + for (let c of s) { + if (c === '1') cnt += 1; + } + return cnt; + }; + + let prev = countOnes(bank[0]); + let res = 0; + + for (let i = 1; i < bank.length; i++) { + let curr = countOnes(bank[i]); + if (curr > 0) { + res += prev * curr; + prev = curr; + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * n)$ +* Space complexity: $O(1)$ extra space. + +> Where $m$ is the number of rows and $n$ is the number of columns. \ No newline at end of file diff --git a/articles/number-of-ways-to-divide-a-long-corridor.md b/articles/number-of-ways-to-divide-a-long-corridor.md new file mode 100644 index 000000000..cda191a27 --- /dev/null +++ b/articles/number-of-ways-to-divide-a-long-corridor.md @@ -0,0 +1,608 @@ +## 1. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def numberOfWays(self, corridor: str) -> int: + mod = 10**9 + 7 + cache = [[-1] * 3 for i in range(len(corridor))] # (i, seats) -> count + + def dfs(i, seats): + if i == len(corridor): + return 1 if seats == 2 else 0 + if cache[i][seats] != -1: + return cache[i][seats] + + res = 0 + if seats == 2: + if corridor[i] == "S": + res = dfs(i + 1, 1) + else: + res = (dfs(i + 1, 0) + dfs(i + 1, 2)) % mod + else: + if corridor[i] == "S": + res = dfs(i + 1, seats + 1) + else: + res = dfs(i + 1, seats) + + cache[i][seats] = res + return res + + return dfs(0, 0) +``` + +```java +public class Solution { + private static final int MOD = 1_000_000_007; + private int[][] dp; + + public int numberOfWays(String corridor) { + int n = corridor.length(); + dp = new int[n][3]; + for (int i = 0; i < n; i++) { + Arrays.fill(dp[i], -1); + } + return dfs(0, 0, corridor); + } + + private int dfs(int i, int seats, String corridor) { + if (i == corridor.length()) { + return seats == 2 ? 1 : 0; + } + if (dp[i][seats] != -1) { + return dp[i][seats]; + } + + int res = 0; + if (seats == 2) { + if (corridor.charAt(i) == 'S') { + res = dfs(i + 1, 1, corridor); + } else { + res = (dfs(i + 1, 0, corridor) + dfs(i + 1, 2, corridor)) % MOD; + } + } else { + if (corridor.charAt(i) == 'S') { + res = dfs(i + 1, seats + 1, corridor); + } else { + res = dfs(i + 1, seats, corridor); + } + } + + return dp[i][seats] = res; + } +} +``` + +```cpp +class Solution { +public: + static constexpr int MOD = 1'000'000'007; + vector> dp; + + int numberOfWays(string corridor) { + int n = corridor.size(); + dp.assign(n, vector(3, -1)); + return dfs(0, 0, corridor); + } + + int dfs(int i, int seats, string& corridor) { + if (i == corridor.size()) { + return seats == 2 ? 1 : 0; + } + if (dp[i][seats] != -1) { + return dp[i][seats]; + } + + int res = 0; + if (seats == 2) { + if (corridor[i] == 'S') { + res = dfs(i + 1, 1, corridor); + } else { + res = (dfs(i + 1, 0, corridor) + dfs(i + 1, 2, corridor)) % MOD; + } + } else { + if (corridor[i] == 'S') { + res = dfs(i + 1, seats + 1, corridor); + } else { + res = dfs(i + 1, seats, corridor); + } + } + + return dp[i][seats] = res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} corridor + * @return {number} + */ + numberOfWays(corridor) { + const MOD = 1_000_000_007; + const n = corridor.length; + const dp = Array.from({ length: n }, () => Array(3).fill(-1)); + + const dfs = (i, seats) => { + if (i === n) return seats === 2 ? 1 : 0; + if (dp[i][seats] !== -1) return dp[i][seats]; + + let res = 0; + if (seats === 2) { + if (corridor[i] === 'S') { + res = dfs(i + 1, 1); + } else { + res = (dfs(i + 1, 0) + dfs(i + 1, 2)) % MOD; + } + } else { + if (corridor[i] === 'S') { + res = dfs(i + 1, seats + 1); + } else { + res = dfs(i + 1, seats); + } + } + + return (dp[i][seats] = res); + }; + + return dfs(0, 0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 2. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def numberOfWays(self, corridor: str) -> int: + MOD = 1000000007 + n = len(corridor) + dp = [[0] * 3 for _ in range(n + 1)] + dp[n][2] = 1 + + for i in range(n - 1, -1, -1): + for seats in range(3): + if seats == 2: + if corridor[i] == 'S': + dp[i][seats] = dp[i + 1][1] + else: + dp[i][seats] = (dp[i + 1][0] + dp[i + 1][2]) % MOD + else: + if corridor[i] == 'S': + dp[i][seats] = dp[i + 1][seats + 1] + else: + dp[i][seats] = dp[i + 1][seats] + + return dp[0][0] +``` + +```java +public class Solution { + public int numberOfWays(String corridor) { + int MOD = 1000000007; + int n = corridor.length(); + int[][] dp = new int[n + 1][3]; + dp[n][2] = 1; + + for (int i = n - 1; i >= 0; i--) { + for (int seats = 0; seats < 3; seats++) { + if (seats == 2) { + if (corridor.charAt(i) == 'S') { + dp[i][seats] = dp[i + 1][1]; + } else { + dp[i][seats] = (dp[i + 1][0] + dp[i + 1][2]) % MOD; + } + } else { + if (corridor.charAt(i) == 'S') { + dp[i][seats] = dp[i + 1][seats + 1]; + } else { + dp[i][seats] = dp[i + 1][seats]; + } + } + } + } + return dp[0][0]; + } +} +``` + +```cpp +class Solution { +public: + int numberOfWays(string corridor) { + int MOD = 1000000007; + int n = corridor.size(); + vector> dp(n + 1, vector(3, 0)); + dp[n][2] = 1; + + for (int i = n - 1; i >= 0; i--) { + for (int seats = 0; seats < 3; seats++) { + if (seats == 2) { + if (corridor[i] == 'S') { + dp[i][seats] = dp[i + 1][1]; + } else { + dp[i][seats] = (dp[i + 1][0] + dp[i + 1][2]) % MOD; + } + } else { + if (corridor[i] == 'S') { + dp[i][seats] = dp[i + 1][seats + 1]; + } else { + dp[i][seats] = dp[i + 1][seats]; + } + } + } + } + return dp[0][0]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} corridor + * @return {number} + */ + numberOfWays(corridor) { + const MOD = 1000000007; + const n = corridor.length; + let dp = Array.from({ length: n + 1 }, () => Array(3).fill(0)); + dp[n][2] = 1; + + for (let i = n - 1; i >= 0; i--) { + for (let seats = 0; seats < 3; seats++) { + if (seats === 2) { + if (corridor[i] === 'S') { + dp[i][seats] = dp[i + 1][1]; + } else { + dp[i][seats] = (dp[i + 1][0] + dp[i + 1][2]) % MOD; + } + } else { + if (corridor[i] === 'S') { + dp[i][seats] = dp[i + 1][seats + 1]; + } else { + dp[i][seats] = dp[i + 1][seats]; + } + } + } + } + return dp[0][0]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 3. Dynamic Programming (Space Optimized) + +::tabs-start + +```python +class Solution: + def numberOfWays(self, corridor: str) -> int: + MOD = 1000000007 + dp = [0, 0, 1] + + for i in reversed(corridor): + new_dp = [0] * 3 + for seats in range(3): + if seats == 2: + new_dp[seats] = dp[1] if i == 'S' else (dp[0] + dp[2]) % MOD + else: + new_dp[seats] = dp[seats + 1] if i == 'S' else dp[seats] + dp = new_dp + + return dp[0] +``` + +```java +public class Solution { + public int numberOfWays(String corridor) { + int MOD = 1000000007; + int[] dp = {0, 0, 1}; + + for (int i = corridor.length() - 1; i >= 0; i--) { + int[] new_dp = new int[3]; + for (int seats = 0; seats < 3; seats++) { + if (seats == 2) { + new_dp[seats] = corridor.charAt(i) == 'S' ? dp[1] : (dp[0] + dp[2]) % MOD; + } else { + new_dp[seats] = corridor.charAt(i) == 'S' ? dp[seats + 1] : dp[seats]; + } + } + dp = new_dp; + } + return dp[0]; + } +} +``` + +```cpp +class Solution { +public: + int numberOfWays(string corridor) { + const int MOD = 1000000007; + vector dp = {0, 0, 1}; + + for (int i = corridor.length() - 1; i >= 0; i--) { + vector new_dp(3, 0); + for (int seats = 0; seats < 3; seats++) { + if (seats == 2) { + new_dp[seats] = (corridor[i] == 'S') ? dp[1] : (dp[0] + dp[2]) % MOD; + } else { + new_dp[seats] = (corridor[i] == 'S') ? dp[seats + 1] : dp[seats]; + } + } + dp = new_dp; + } + return dp[0]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} corridor + * @return {number} + */ + numberOfWays(corridor) { + const MOD = 1000000007; + let dp = [0, 0, 1]; + + for (let i = corridor.length - 1; i >= 0; i--) { + let new_dp = [0, 0, 0]; + for (let seats = 0; seats < 3; seats++) { + if (seats === 2) { + new_dp[seats] = corridor[i] === 'S' ? dp[1] : (dp[0] + dp[2]) % MOD; + } else { + new_dp[seats] = corridor[i] === 'S' ? dp[seats + 1] : dp[seats]; + } + } + dp = new_dp; + } + return dp[0]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ + +--- + +## 4. Combinatorics + +::tabs-start + +```python +class Solution: + def numberOfWays(self, corridor: str) -> int: + mod = 10**9 + 7 + seats = [i for i, c in enumerate(corridor) if c == "S"] + + length = len(seats) + if length < 2 or length % 2 == 1: + return 0 + + res = 1 + for i in range(1, length - 1, 2): + res = (res * (seats[i + 1] - seats[i])) % mod + + return res +``` + +```java +public class Solution { + public int numberOfWays(String corridor) { + int mod = 1_000_000_007; + List seats = new ArrayList<>(); + + for (int i = 0; i < corridor.length(); i++) { + if (corridor.charAt(i) == 'S') { + seats.add(i); + } + } + + int length = seats.size(); + if (length < 2 || length % 2 == 1) { + return 0; + } + + long res = 1; + for (int i = 1; i < length - 1; i += 2) { + res = (res * (seats.get(i + 1) - seats.get(i))) % mod; + } + + return (int) res; + } +} +``` + +```cpp +class Solution { +public: + int numberOfWays(string corridor) { + int mod = 1'000'000'007; + vector seats; + + for (int i = 0; i < corridor.size(); i++) { + if (corridor[i] == 'S') { + seats.push_back(i); + } + } + + int length = seats.size(); + if (length < 2 || length % 2 == 1) { + return 0; + } + + long long res = 1; + for (int i = 1; i < length - 1; i += 2) { + res = (res * (seats[i + 1] - seats[i])) % mod; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} corridor + * @return {number} + */ + numberOfWays(corridor) { + const mod = 1_000_000_007; + const seats = []; + + for (let i = 0; i < corridor.length; i++) { + if (corridor[i] === 'S') { + seats.push(i); + } + } + + const length = seats.length; + if (length < 2 || length % 2 === 1) { + return 0; + } + + let res = 1; + for (let i = 1; i < length - 1; i += 2) { + res = (res * (seats[i + 1] - seats[i])) % mod; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 5. Combinatorics (Optimal) + +::tabs-start + +```python +class Solution: + def numberOfWays(self, corridor: str) -> int: + mod = 1_000_000_007 + count = 0 + res = 1 + prev = -1 + + for i, c in enumerate(corridor): + if c == 'S': + count += 1 + if count > 2 and count % 2 == 1: + res = (res * (i - prev)) % mod + prev = i + + return res if count >= 2 and count % 2 == 0 else 0 +``` + +```java +public class Solution { + public int numberOfWays(String corridor) { + int mod = 1_000_000_007; + int count = 0, res = 1, prev = -1; + + for (int i = 0; i < corridor.length(); i++) { + if (corridor.charAt(i) == 'S') { + count++; + if (count > 2 && count % 2 == 1) { + res = (int)((res * (long)(i - prev)) % mod); + } + prev = i; + } + } + + return (count >= 2 && count % 2 == 0) ? res : 0; + } +} +``` + +```cpp +class Solution { +public: + int numberOfWays(string corridor) { + int mod = 1'000'000'007, count = 0, res = 1, prev = -1; + + for (int i = 0; i < corridor.size(); i++) { + if (corridor[i] == 'S') { + count++; + if (count > 2 && count % 2 == 1) { + res = (1LL * res * (i - prev)) % mod; + } + prev = i; + } + } + + return (count >= 2 && count % 2 == 0) ? res : 0; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} corridor + * @return {number} + */ + numberOfWays(corridor) { + const mod = 1_000_000_007; + let count = 0, res = 1, prev = -1; + + for (let i = 0; i < corridor.length; i++) { + if (corridor[i] === 'S') { + count++; + if (count > 2 && count % 2 === 1) { + res = (res * (i - prev)) % mod; + } + prev = i; + } + } + + return count >= 2 && count % 2 === 0 ? res : 0; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ \ No newline at end of file diff --git a/articles/operations-on-tree.md b/articles/operations-on-tree.md new file mode 100644 index 000000000..682f18874 --- /dev/null +++ b/articles/operations-on-tree.md @@ -0,0 +1,806 @@ +## 1. Depth First Search + +::tabs-start + +```python +class LockingTree: + + def __init__(self, parent: List[int]): + self.parent = parent + self.child = [[] for _ in range(len(parent))] + self.locked = [0] * len(parent) + for node in range(1, len(parent)): + self.child[parent[node]].append(node) + + def lock(self, num: int, user: int) -> bool: + if self.locked[num]: + return False + self.locked[num] = user + return True + + def unlock(self, num: int, user: int) -> bool: + if self.locked[num] != user: + return False + self.locked[num] = 0 + return True + + def upgrade(self, num: int, user: int) -> bool: + node = num + while node != -1: + if self.locked[node]: + return False + node = self.parent[node] + + def dfs(node): + lockedCount = 0 + if self.locked[node]: + lockedCount += 1 + self.locked[node] = 0 + + for nei in self.child[node]: + lockedCount += dfs(nei) + return lockedCount + + if dfs(num) > 0: + self.locked[num] = user + return True + return False +``` + +```java +public class LockingTree { + private int[] parent; + private List[] child; + private int[] locked; + + public LockingTree(int[] parent) { + this.parent = parent; + int n = parent.length; + child = new ArrayList[n]; + locked = new int[n]; + + for (int i = 0; i < n; i++) { + child[i] = new ArrayList<>(); + } + for (int node = 1; node < n; node++) { + child[parent[node]].add(node); + } + } + + public boolean lock(int num, int user) { + if (locked[num] != 0) { + return false; + } + locked[num] = user; + return true; + } + + public boolean unlock(int num, int user) { + if (locked[num] != user) { + return false; + } + locked[num] = 0; + return true; + } + + public boolean upgrade(int num, int user) { + int node = num; + while (node != -1) { + if (locked[node] != 0) { + return false; + } + node = parent[node]; + } + + int lockedCount = dfs(num); + if (lockedCount > 0) { + locked[num] = user; + return true; + } + return false; + } + + private int dfs(int node) { + int lockedCount = 0; + if (locked[node] != 0) { + lockedCount++; + locked[node] = 0; + } + for (int nei : child[node]) { + lockedCount += dfs(nei); + } + return lockedCount; + } +} +``` + +```cpp +class LockingTree { +private: + vector parent; + vector> child; + vector locked; + +public: + LockingTree(vector& parent) : parent(parent), locked(parent.size()) { + int n = parent.size(); + child.resize(n); + for (int node = 1; node < n; node++) { + child[parent[node]].push_back(node); + } + } + + bool lock(int num, int user) { + if (locked[num]) { + return false; + } + locked[num] = user; + return true; + } + + bool unlock(int num, int user) { + if (locked[num] != user) { + return false; + } + locked[num] = 0; + return true; + } + + bool upgrade(int num, int user) { + int node = num; + while (node != -1) { + if (locked[node]) { + return false; + } + node = parent[node]; + } + + int lockedCount = dfs(num); + if (lockedCount > 0) { + locked[num] = user; + return true; + } + return false; + } + +private: + int dfs(int node) { + int lockedCount = 0; + if (locked[node]) { + lockedCount++; + locked[node] = 0; + } + for (int& nei : child[node]) { + lockedCount += dfs(nei); + } + return lockedCount; + } +}; +``` + +```javascript +class LockingTree { + /** + * @constructor + * @param {number[]} parent + */ + constructor(parent) { + this.parent = parent; + this.child = Array.from({ length: parent.length }, () => []); + this.locked = new Array(parent.length).fill(0); + + for (let node = 1; node < parent.length; node++) { + this.child[parent[node]].push(node); + } + } + + /** + * @param {number} num + * @param {number} user + * @return {boolean} + */ + lock(num, user) { + if (this.locked[num] !== 0) { + return false; + } + this.locked[num] = user; + return true; + } + + /** + * @param {number} num + * @param {number} user + * @return {boolean} + */ + unlock(num, user) { + if (this.locked[num] !== user) { + return false; + } + this.locked[num] = 0; + return true; + } + + /** + * @param {number} num + * @param {number} user + * @return {boolean} + */ + upgrade(num, user) { + let node = num; + while (node !== -1) { + if (this.locked[node] !== 0) { + return false; + } + node = this.parent[node]; + } + + const dfs = (node) => { + let lockedCount = 0; + if (this.locked[node] !== 0) { + lockedCount++; + this.locked[node] = 0; + } + for (let nei of this.child[node]) { + lockedCount += dfs(nei); + } + return lockedCount; + }; + + if (dfs(num) > 0) { + this.locked[num] = user; + return true; + } + return false; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: + * $O(n)$ time for initialization. + * $O(1)$ time for each $lock()$ and $unlock()$ function call. + * $O(n)$ time for each $upgrade()$ function call. +* Space complexity: $O(n)$ + +--- + +## 2. Breadth First Search + +::tabs-start + +```python +class LockingTree: + + def __init__(self, parent: List[int]): + self.parent = parent + self.child = [[] for _ in range(len(parent))] + self.locked = [0] * len(parent) + for node in range(1, len(parent)): + self.child[parent[node]].append(node) + + def lock(self, num: int, user: int) -> bool: + if self.locked[num]: + return False + self.locked[num] = user + return True + + def unlock(self, num: int, user: int) -> bool: + if self.locked[num] != user: + return False + self.locked[num] = 0 + return True + + def upgrade(self, num: int, user: int) -> bool: + node = num + while node != -1: + if self.locked[node]: + return False + node = self.parent[node] + + lockedCount, q = 0, deque([num]) + while q: + node = q.popleft() + if self.locked[node]: + self.locked[node] = 0 + lockedCount += 1 + q.extend(self.child[node]) + + if lockedCount: + self.locked[num] = user + return True + return False +``` + +```java +public class LockingTree { + private int[] parent; + private List[] child; + private int[] locked; + + public LockingTree(int[] parent) { + this.parent = parent; + int n = parent.length; + child = new ArrayList[n]; + locked = new int[n]; + + for (int i = 0; i < n; i++) { + child[i] = new ArrayList<>(); + } + for (int node = 1; node < n; node++) { + child[parent[node]].add(node); + } + } + + public boolean lock(int num, int user) { + if (locked[num] != 0) { + return false; + } + locked[num] = user; + return true; + } + + public boolean unlock(int num, int user) { + if (locked[num] != user) { + return false; + } + locked[num] = 0; + return true; + } + + public boolean upgrade(int num, int user) { + int node = num; + while (node != -1) { + if (locked[node] != 0) { + return false; + } + node = parent[node]; + } + + int lockedCount = 0; + Queue q = new LinkedList<>(); + q.offer(num); + + while (!q.isEmpty()) { + node = q.poll(); + if (locked[node] != 0) { + locked[node] = 0; + lockedCount++; + } + q.addAll(child[node]); + } + + if (lockedCount > 0) { + locked[num] = user; + return true; + } + return false; + } +} +``` + +```cpp +class LockingTree { +private: + vector parent; + vector> child; + vector locked; + +public: + LockingTree(vector& parent) : parent(parent), locked(parent.size()) { + int n = parent.size(); + child.resize(n); + for (int node = 1; node < n; node++) { + child[parent[node]].push_back(node); + } + } + + bool lock(int num, int user) { + if (locked[num]) { + return false; + } + locked[num] = user; + return true; + } + + bool unlock(int num, int user) { + if (locked[num] != user) { + return false; + } + locked[num] = 0; + return true; + } + + bool upgrade(int num, int user) { + int node = num; + while (node != -1) { + if (locked[node]) { + return false; + } + node = parent[node]; + } + + int lockedCount = 0; + queue q; + q.push(num); + + while (!q.empty()) { + node = q.front(); q.pop(); + if (locked[node]) { + locked[node] = 0; + lockedCount++; + } + for (int nei : child[node]) { + q.push(nei); + } + } + + if (lockedCount > 0) { + locked[num] = user; + return true; + } + return false; + } +}; +``` + +```javascript +class LockingTree { + /** + * @constructor + * @param {number[]} parent + */ + constructor(parent) { + this.parent = parent; + this.child = Array.from({ length: parent.length }, () => []); + this.locked = new Array(parent.length).fill(0); + + for (let node = 1; node < parent.length; node++) { + this.child[parent[node]].push(node); + } + } + + /** + * @param {number} num + * @param {number} user + * @return {boolean} + */ + lock(num, user) { + if (this.locked[num] !== 0) { + return false; + } + this.locked[num] = user; + return true; + } + + /** + * @param {number} num + * @param {number} user + * @return {boolean} + */ + unlock(num, user) { + if (this.locked[num] !== user) { + return false; + } + this.locked[num] = 0; + return true; + } + + /** + * @param {number} num + * @param {number} user + * @return {boolean} + */ + upgrade(num, user) { + let node = num; + while (node !== -1) { + if (this.locked[node] !== 0) { + return false; + } + node = this.parent[node]; + } + + let lockedCount = 0; + const q = new Queue([num]); + + while (!q.isEmpty()) { + node = q.pop(); + if (this.locked[node]) { + this.locked[node] = 0; + lockedCount++; + } + for (let nei of this.child[node]) { + q.push(nei); + } + } + + if (lockedCount > 0) { + this.locked[num] = user; + return true; + } + return false; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: + * $O(n)$ time for initialization. + * $O(1)$ time for each $lock()$ and $unlock()$ function call. + * $O(n)$ time for each $upgrade()$ function call. +* Space complexity: $O(n)$ + +--- + +## 3. Iterative DFS + +::tabs-start + +```python +class LockingTree: + + def __init__(self, parent: List[int]): + self.parent = parent + self.child = [[] for _ in range(len(parent))] + self.locked = [0] * len(parent) + for node in range(1, len(parent)): + self.child[parent[node]].append(node) + + def lock(self, num: int, user: int) -> bool: + if self.locked[num]: + return False + self.locked[num] = user + return True + + def unlock(self, num: int, user: int) -> bool: + if self.locked[num] != user: + return False + self.locked[num] = 0 + return True + + def upgrade(self, num: int, user: int) -> bool: + node = num + while node != -1: + if self.locked[node]: + return False + node = self.parent[node] + + lockedCount, stack = 0, [num] + while stack: + node = stack.pop() + if self.locked[node]: + self.locked[node] = 0 + lockedCount += 1 + stack.extend(self.child[node]) + + if lockedCount: + self.locked[num] = user + return True + return False +``` + +```java +public class LockingTree { + private int[] parent; + private List[] child; + private int[] locked; + + public LockingTree(int[] parent) { + this.parent = parent; + int n = parent.length; + child = new ArrayList[n]; + locked = new int[n]; + + for (int i = 0; i < n; i++) { + child[i] = new ArrayList<>(); + } + for (int node = 1; node < n; node++) { + child[parent[node]].add(node); + } + } + + public boolean lock(int num, int user) { + if (locked[num] != 0) { + return false; + } + locked[num] = user; + return true; + } + + public boolean unlock(int num, int user) { + if (locked[num] != user) { + return false; + } + locked[num] = 0; + return true; + } + + public boolean upgrade(int num, int user) { + int node = num; + while (node != -1) { + if (locked[node] != 0) { + return false; + } + node = parent[node]; + } + + int lockedCount = 0; + Stack stack = new Stack<>(); + stack.push(num); + + while (!stack.isEmpty()) { + node = stack.pop(); + if (locked[node] != 0) { + locked[node] = 0; + lockedCount++; + } + for (int nei : child[node]) { + stack.push(nei); + } + } + + if (lockedCount > 0) { + locked[num] = user; + return true; + } + return false; + } +} +``` + +```cpp +class LockingTree { +private: + vector parent; + vector> child; + vector locked; + +public: + LockingTree(vector& parent) : parent(parent), locked(parent.size()) { + int n = parent.size(); + child.resize(n); + for (int node = 1; node < n; node++) { + child[parent[node]].push_back(node); + } + } + + bool lock(int num, int user) { + if (locked[num]) { + return false; + } + locked[num] = user; + return true; + } + + bool unlock(int num, int user) { + if (locked[num] != user) { + return false; + } + locked[num] = 0; + return true; + } + + bool upgrade(int num, int user) { + int node = num; + while (node != -1) { + if (locked[node]) { + return false; + } + node = parent[node]; + } + + int lockedCount = 0; + stack stk; + stk.push(num); + + while (!stk.empty()) { + node = stk.top(); stk.pop(); + if (locked[node]) { + locked[node] = 0; + lockedCount++; + } + for (int& nei : child[node]) { + stk.push(nei); + } + } + + if (lockedCount > 0) { + locked[num] = user; + return true; + } + return false; + } +}; +``` + +```javascript +class LockingTree { + /** + * @constructor + * @param {number[]} parent + */ + constructor(parent) { + this.parent = parent; + this.child = Array.from({ length: parent.length }, () => []); + this.locked = new Array(parent.length).fill(0); + + for (let node = 1; node < parent.length; node++) { + this.child[parent[node]].push(node); + } + } + + /** + * @param {number} num + * @param {number} user + * @return {boolean} + */ + lock(num, user) { + if (this.locked[num] !== 0) { + return false; + } + this.locked[num] = user; + return true; + } + + /** + * @param {number} num + * @param {number} user + * @return {boolean} + */ + unlock(num, user) { + if (this.locked[num] !== user) { + return false; + } + this.locked[num] = 0; + return true; + } + + /** + * @param {number} num + * @param {number} user + * @return {boolean} + */ + upgrade(num, user) { + let node = num; + while (node !== -1) { + if (this.locked[node] !== 0) { + return false; + } + node = this.parent[node]; + } + + let lockedCount = 0; + let stack = [num]; + + while (stack.length) { + node = stack.pop(); + if (this.locked[node]) { + this.locked[node] = 0; + lockedCount++; + } + stack.push(...this.child[node]); + } + + if (lockedCount > 0) { + this.locked[num] = user; + return true; + } + return false; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: + * $O(n)$ time for initialization. + * $O(1)$ time for each $lock()$ and $unlock()$ function call. + * $O(n)$ time for each $upgrade()$ function call. +* Space complexity: $O(n)$ \ No newline at end of file diff --git a/articles/parallel-courses-iii.md b/articles/parallel-courses-iii.md new file mode 100644 index 000000000..ca66a0769 --- /dev/null +++ b/articles/parallel-courses-iii.md @@ -0,0 +1,481 @@ +## 1. Depth First Search + +::tabs-start + +```python +class Solution: + def minimumTime(self, n: int, relations: list[list[int]], time: list[int]) -> int: + adj = defaultdict(list) + for src, dst in relations: + adj[src].append(dst) + + max_time = {} + + def dfs(src): + if src in max_time: + return max_time[src] + res = time[src - 1] + for nei in adj[src]: + res = max(res, time[src - 1] + dfs(nei)) + max_time[src] = res + return res + + for i in range(1, n + 1): + dfs(i) + + return max(max_time.values()) +``` + +```java +public class Solution { + private Map maxTime; + private List[] adj; + private int[] time; + + public int minimumTime(int n, int[][] relations, int[] time) { + this.time = time; + this.maxTime = new HashMap<>(); + this.adj = new ArrayList[n + 1]; + + for (int i = 1; i <= n; i++) { + adj[i] = new ArrayList<>(); + } + for (int[] relation : relations) { + adj[relation[0]].add(relation[1]); + } + + for (int i = 1; i <= n; i++) { + dfs(i); + } + + return Collections.max(maxTime.values()); + } + + private int dfs(int src) { + if (maxTime.containsKey(src)) { + return maxTime.get(src); + } + + int res = time[src - 1]; + for (int nei : adj[src]) { + res = Math.max(res, time[src - 1] + dfs(nei)); + } + maxTime.put(src, res); + return res; + } +} +``` + +```cpp +class Solution { +public: + unordered_map maxTime; + vector> adj; + vector time; + + int minimumTime(int n, vector>& relations, vector& time) { + this->time = time; + adj.resize(n + 1); + + for (auto& relation : relations) { + adj[relation[0]].push_back(relation[1]); + } + + for (int i = 1; i <= n; i++) { + dfs(i); + } + + int res = 0; + for (auto& [key, value] : maxTime) { + res = max(res, value); + } + return res; + } + +private: + int dfs(int src) { + if (maxTime.count(src)) { + return maxTime[src]; + } + + int res = time[src - 1]; + for (int nei : adj[src]) { + res = max(res, time[src - 1] + dfs(nei)); + } + maxTime[src] = res; + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number[][]} relations + * @param {number[]} time + * @return {number} + */ + minimumTime(n, relations, time) { + let adj = Array.from({ length: n + 1 }, () => []); + let maxTime = new Map(); + + for (let [src, dst] of relations) { + adj[src].push(dst); + } + + const dfs = (src) => { + if (maxTime.has(src)) { + return maxTime.get(src); + } + + let res = time[src - 1]; + for (let nei of adj[src]) { + res = Math.max(res, time[src - 1] + dfs(nei)); + } + maxTime.set(src, res); + return res; + }; + + for (let i = 1; i <= n; i++) { + dfs(i); + } + + return Math.max(...maxTime.values()); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(V + E)$ +* Space complexity: $O(V + E)$ + +> Where $V$ is the number of courses and $E$ is the number of prerequisites. + +--- + +## 2. Iterative DFS + +::tabs-start + +```python +class Solution: + def minimumTime(self, n: int, relations: list[list[int]], time: list[int]) -> int: + adj = [[] for _ in range(n)] + for src, dst in relations: + adj[src - 1].append(dst - 1) + + maxTime = [-1] * n + processed = [False] * n + + for i in range(n): + if maxTime[i] == -1: + stack = [i] + while stack: + node = stack.pop() + if processed[node]: + best = 0 + for nei in adj[node]: + best = max(best, maxTime[nei]) + maxTime[node] = time[node] + best + else: + processed[node] = True + stack.append(node) + for nei in adj[node]: + if maxTime[nei] == -1: + stack.append(nei) + return max(maxTime) +``` + +```java +public class Solution { + public int minimumTime(int n, int[][] relations, int[] time) { + List[] adj = new ArrayList[n]; + for (int i = 0; i < n; i++) adj[i] = new ArrayList<>(); + for (int[] rel : relations) { + adj[rel[0] - 1].add(rel[1] - 1); + } + + int[] maxTime = new int[n]; + Arrays.fill(maxTime, -1); + boolean[] processed = new boolean[n]; + + for (int i = 0; i < n; i++) { + if (maxTime[i] == -1) { + Stack stack = new Stack<>(); + stack.push(i); + while (!stack.isEmpty()) { + int node = stack.pop(); + if (processed[node]) { + int best = 0; + for (int nei : adj[node]) { + best = Math.max(best, maxTime[nei]); + } + maxTime[node] = time[node] + best; + } else { + processed[node] = true; + stack.push(node); + for (int nei : adj[node]) { + if (maxTime[nei] == -1) { + stack.push(nei); + } + } + } + } + } + } + return Arrays.stream(maxTime).max().getAsInt(); + } +} +``` + +```cpp +class Solution { +public: + int minimumTime(int n, vector>& relations, vector& time) { + vector> adj(n); + for (auto& rel : relations) { + adj[rel[0] - 1].push_back(rel[1] - 1); + } + + vector maxTime(n, -1); + vector processed(n, false); + + for (int i = 0; i < n; i++) { + if (maxTime[i] == -1) { + stack stk; + stk.push(i); + while (!stk.empty()) { + int node = stk.top(); stk.pop(); + if (processed[node]) { + int best = 0; + for (int nei : adj[node]) { + best = max(best, maxTime[nei]); + } + maxTime[node] = time[node] + best; + } else { + processed[node] = true; + stk.push(node); + for (int nei : adj[node]) { + if (maxTime[nei] == -1) { + stk.push(nei); + } + } + } + } + } + } + return *max_element(maxTime.begin(), maxTime.end()); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number[][]} relations + * @param {number[]} time + * @return {number} + */ + minimumTime(n, relations, time) { + let adj = Array.from({ length: n }, () => []); + for (let [src, dst] of relations) { + adj[src - 1].push(dst - 1); + } + + let maxTime = Array(n).fill(-1); + let processed = Array(n).fill(false); + + for (let i = 0; i < n; i++) { + if (maxTime[i] === -1) { + let stack = [i]; + while (stack.length > 0) { + let node = stack.pop(); + if (processed[node]) { + let best = 0; + for (let nei of adj[node]) { + best = Math.max(best, maxTime[nei]); + } + maxTime[node] = time[node] + best; + } else { + processed[node] = true; + stack.push(node); + for (let nei of adj[node]) { + if (maxTime[nei] === -1) { + stack.push(nei); + } + } + } + } + } + } + return Math.max(...maxTime); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(V + E)$ +* Space complexity: $O(V + E)$ + +> Where $V$ is the number of courses and $E$ is the number of prerequisites. + +--- + +## 3. Topological Sort (Kahn's Algorithm) + +::tabs-start + +```python +class Solution: + def minimumTime(self, n: int, relations: list[list[int]], time: list[int]) -> int: + adj = [[] for _ in range(n)] + indegree = [0] * n + maxTime = time[:] + + for src, dst in relations: + adj[src - 1].append(dst - 1) + indegree[dst - 1] += 1 + + queue = deque([i for i in range(n) if indegree[i] == 0]) + while queue: + node = queue.popleft() + for nei in adj[node]: + maxTime[nei] = max(maxTime[nei], maxTime[node] + time[nei]) + indegree[nei] -= 1 + if indegree[nei] == 0: + queue.append(nei) + + return max(maxTime) +``` + +```java +public class Solution { + public int minimumTime(int n, int[][] relations, int[] time) { + List> adj = new ArrayList<>(); + int[] indegree = new int[n]; + int[] maxTime = Arrays.copyOf(time, n); + + for (int i = 0; i < n; i++) { + adj.add(new ArrayList<>()); + } + + for (int[] relation : relations) { + int src = relation[0] - 1, dst = relation[1] - 1; + adj.get(src).add(dst); + indegree[dst]++; + } + + Queue queue = new LinkedList<>(); + for (int i = 0; i < n; i++) { + if (indegree[i] == 0) { + queue.add(i); + } + } + + while (!queue.isEmpty()) { + int node = queue.poll(); + for (int nei : adj.get(node)) { + maxTime[nei] = Math.max(maxTime[nei], maxTime[node] + time[nei]); + if (--indegree[nei] == 0) { + queue.add(nei); + } + } + } + + return Arrays.stream(maxTime).max().getAsInt(); + } +} +``` + +```cpp +class Solution { +public: + int minimumTime(int n, vector>& relations, vector& time) { + vector> adj(n); + vector indegree(n, 0); + vector maxTime(time.begin(), time.end()); + + for (auto& relation : relations) { + int src = relation[0] - 1, dst = relation[1] - 1; + adj[src].push_back(dst); + indegree[dst]++; + } + + queue queue; + for (int i = 0; i < n; i++) { + if (indegree[i] == 0) { + queue.push(i); + } + } + + while (!queue.empty()) { + int node = queue.front(); queue.pop(); + for (int nei : adj[node]) { + maxTime[nei] = max(maxTime[nei], maxTime[node] + time[nei]); + if (--indegree[nei] == 0) { + queue.push(nei); + } + } + } + + return *max_element(maxTime.begin(), maxTime.end()); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number[][]} relations + * @param {number[]} time + * @return {number} + */ + minimumTime(n, relations, time) { + let adj = Array.from({ length: n }, () => []); + let indegree = Array(n).fill(0); + let maxTime = [...time]; + + for (let [src, dst] of relations) { + adj[src - 1].push(dst - 1); + indegree[dst - 1]++; + } + + let queue = new Queue(); + for (let i = 0; i < n; i++) { + if (indegree[i] === 0) { + queue.push(i); + } + } + + while (!queue.isEmpty()) { + let node = queue.pop(); + for (let nei of adj[node]) { + maxTime[nei] = Math.max(maxTime[nei], maxTime[node] + time[nei]); + if (--indegree[nei] === 0) { + queue.push(nei); + } + } + } + + return Math.max(...maxTime); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(V + E)$ +* Space complexity: $O(V + E)$ + +> Where $V$ is the number of courses and $E$ is the number of prerequisites. \ No newline at end of file diff --git a/articles/partition-array-for-maximum-sum.md b/articles/partition-array-for-maximum-sum.md new file mode 100644 index 000000000..a2fb52393 --- /dev/null +++ b/articles/partition-array-for-maximum-sum.md @@ -0,0 +1,446 @@ +## 1. Recursion + +::tabs-start + +```python +class Solution: + def maxSumAfterPartitioning(self, arr: List[int], k: int) -> int: + def dfs(i): + if i >= len(arr): + return 0 + + cur_max = 0 + res = 0 + for j in range(i, min(len(arr), i + k)): + cur_max = max(cur_max, arr[j]) + window_size = j - i + 1 + res = max(res, dfs(j + 1) + cur_max * window_size) + + return res + + return dfs(0) +``` + +```java +public class Solution { + public int maxSumAfterPartitioning(int[] arr, int k) { + return dfs(0, arr, k); + } + + private int dfs(int i, int[] arr, int k) { + if (i >= arr.length) { + return 0; + } + + int cur_max = 0; + int res = 0; + for (int j = i; j < Math.min(arr.length, i + k); j++) { + cur_max = Math.max(cur_max, arr[j]); + int window_size = j - i + 1; + res = Math.max(res, dfs(j + 1, arr, k) + cur_max * window_size); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int maxSumAfterPartitioning(vector& arr, int k) { + return dfs(0, arr, k); + } + +private: + int dfs(int i, vector& arr, int k) { + if (i >= arr.size()) { + return 0; + } + + int cur_max = 0, res = 0; + for (int j = i; j < min((int)arr.size(), i + k); j++) { + cur_max = max(cur_max, arr[j]); + int window_size = j - i + 1; + res = max(res, dfs(j + 1, arr, k) + cur_max * window_size); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr + * @param {number} k + * @return {number} + */ + maxSumAfterPartitioning(arr, k) { + const dfs = (i) => { + if (i >= arr.length) { + return 0; + } + + let cur_max = 0, res = 0; + for (let j = i; j < Math.min(arr.length, i + k); j++) { + cur_max = Math.max(cur_max, arr[j]); + let window_size = j - i + 1; + res = Math.max(res, dfs(j + 1) + cur_max * window_size); + } + + return res; + }; + + return dfs(0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(k ^ n)$ +* Space complexity: $O(n)$ for recursion stack. + +> Where $k$ is the maximum length of the subarray and $n$ is the size of the array $arr$. + +--- + +## 2. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def maxSumAfterPartitioning(self, arr: List[int], k: int) -> int: + cache = { len(arr) : 0 } + + def dfs(i): + if i in cache: + return cache[i] + + cur_max = 0 + res = 0 + for j in range(i, min(len(arr), i + k)): + cur_max = max(cur_max, arr[j]) + window_size = j - i + 1 + res = max(res, dfs(j + 1) + cur_max * window_size) + + cache[i] = res + return res + + return dfs(0) +``` + +```java +public class Solution { + public int maxSumAfterPartitioning(int[] arr, int k) { + int[] cache = new int[arr.length + 1]; + Arrays.fill(cache, -1); + cache[arr.length] = 0; + return dfs(0, arr, k, cache); + } + + private int dfs(int i, int[] arr, int k, int[] cache) { + if (cache[i] != -1) { + return cache[i]; + } + + int cur_max = 0, res = 0; + for (int j = i; j < Math.min(arr.length, i + k); j++) { + cur_max = Math.max(cur_max, arr[j]); + int window_size = j - i + 1; + res = Math.max(res, dfs(j + 1, arr, k, cache) + cur_max * window_size); + } + + cache[i] = res; + return res; + } +} +``` + +```cpp +class Solution { +public: + int maxSumAfterPartitioning(vector& arr, int k) { + vector cache(arr.size() + 1, -1); + cache[arr.size()] = 0; + return dfs(0, arr, k, cache); + } + +private: + int dfs(int i, vector& arr, int k, vector& cache) { + if (cache[i] != -1) { + return cache[i]; + } + + int cur_max = 0, res = 0; + for (int j = i; j < min((int)arr.size(), i + k); j++) { + cur_max = max(cur_max, arr[j]); + int window_size = j - i + 1; + res = max(res, dfs(j + 1, arr, k, cache) + cur_max * window_size); + } + + return cache[i] = res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr + * @param {number} k + * @return {number} + */ + maxSumAfterPartitioning(arr, k) { + const cache = new Array(arr.length + 1).fill(-1); + cache[arr.length] = 0; + + const dfs = (i) => { + if (cache[i] !== -1) { + return cache[i]; + } + + let cur_max = 0, res = 0; + for (let j = i; j < Math.min(arr.length, i + k); j++) { + cur_max = Math.max(cur_max, arr[j]); + let window_size = j - i + 1; + res = Math.max(res, dfs(j + 1) + cur_max * window_size); + } + + return (cache[i] = res); + }; + + return dfs(0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * k)$ +* Space complexity: $O(n)$ + +> Where $k$ is the maximum length of the subarray and $n$ is the size of the array $arr$. + +--- + +## 3. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def maxSumAfterPartitioning(self, arr: List[int], k: int) -> int: + n = len(arr) + dp = [0] * (n + 1) + + for i in range(n - 1, -1, -1): + cur_max = 0 + for j in range(i, min(n, i + k)): + cur_max = max(cur_max, arr[j]) + window_size = j - i + 1 + dp[i] = max(dp[i], dp[j + 1] + cur_max * window_size) + + return dp[0] +``` + +```java +public class Solution { + public int maxSumAfterPartitioning(int[] arr, int k) { + int n = arr.length; + int[] dp = new int[n + 1]; + + for (int i = n - 1; i >= 0; i--) { + int cur_max = 0; + for (int j = i; j < Math.min(n, i + k); j++) { + cur_max = Math.max(cur_max, arr[j]); + int window_size = j - i + 1; + dp[i] = Math.max(dp[i], dp[j + 1] + cur_max * window_size); + } + } + + return dp[0]; + } +} +``` + +```cpp +class Solution { +public: + int maxSumAfterPartitioning(vector& arr, int k) { + int n = arr.size(); + vector dp(n + 1, 0); + + for (int i = n - 1; i >= 0; i--) { + int cur_max = 0; + for (int j = i; j < min(n, i + k); j++) { + cur_max = max(cur_max, arr[j]); + int window_size = j - i + 1; + dp[i] = max(dp[i], dp[j + 1] + cur_max * window_size); + } + } + + return dp[0]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr + * @param {number} k + * @return {number} + */ + maxSumAfterPartitioning(arr, k) { + let n = arr.length; + let dp = new Array(n + 1).fill(0); + + for (let i = n - 1; i >= 0; i--) { + let cur_max = 0; + for (let j = i; j < Math.min(n, i + k); j++) { + cur_max = Math.max(cur_max, arr[j]); + let window_size = j - i + 1; + dp[i] = Math.max(dp[i], dp[j + 1] + cur_max * window_size); + } + } + + return dp[0]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * k)$ +* Space complexity: $O(n)$ + +> Where $k$ is the maximum length of the subarray and $n$ is the size of the array $arr$. + +--- + +## 4. Dynamic Programming (Space Optimized) + +::tabs-start + +```python +class Solution: + def maxSumAfterPartitioning(self, arr: List[int], k: int) -> int: + dp = [0] * k + dp[0] = arr[0] + + for i in range(1, len(arr)): + cur_max = 0 + max_at_i = 0 + for j in range(i, i - k, -1): + if j < 0: + break + cur_max = max(cur_max, arr[j]) + window_size = i - j + 1 + cur_sum = cur_max * window_size + sub_sum = dp[(j - 1) % k] if j > 0 else 0 + max_at_i = max(max_at_i, cur_sum + sub_sum) + + dp[i % k] = max_at_i + + return dp[(len(arr) - 1) % k] +``` + +```java +public class Solution { + public int maxSumAfterPartitioning(int[] arr, int k) { + int n = arr.length; + int[] dp = new int[k]; + dp[0] = arr[0]; + + for (int i = 1; i < n; i++) { + int cur_max = 0, max_at_i = 0; + for (int j = i; j > i - k; j--) { + if (j < 0) break; + cur_max = Math.max(cur_max, arr[j]); + int window_size = i - j + 1; + int cur_sum = cur_max * window_size; + int sub_sum = (j > 0) ? dp[(j - 1) % k] : 0; + max_at_i = Math.max(max_at_i, cur_sum + sub_sum); + } + dp[i % k] = max_at_i; + } + + return dp[(n - 1) % k]; + } +} +``` + +```cpp +class Solution { +public: + int maxSumAfterPartitioning(vector& arr, int k) { + int n = arr.size(); + vector dp(k); + dp[0] = arr[0]; + + for (int i = 1; i < n; i++) { + int cur_max = 0, max_at_i = 0; + for (int j = i; j > i - k; j--) { + if (j < 0) break; + cur_max = max(cur_max, arr[j]); + int window_size = i - j + 1; + int cur_sum = cur_max * window_size; + int sub_sum = (j > 0) ? dp[(j - 1) % k] : 0; + max_at_i = max(max_at_i, cur_sum + sub_sum); + } + dp[i % k] = max_at_i; + } + + return dp[(n - 1) % k]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr + * @param {number} k + * @return {number} + */ + maxSumAfterPartitioning(arr, k) { + const n = arr.length; + const dp = new Array(k).fill(0); + dp[0] = arr[0]; + + for (let i = 1; i < n; i++) { + let cur_max = 0, max_at_i = 0; + for (let j = i; j > i - k; j--) { + if (j < 0) break; + cur_max = Math.max(cur_max, arr[j]); + let window_size = i - j + 1; + let cur_sum = cur_max * window_size; + let sub_sum = (j > 0) ? dp[(j - 1) % k] : 0; + max_at_i = Math.max(max_at_i, cur_sum + sub_sum); + } + dp[i % k] = max_at_i; + } + + return dp[(n - 1) % k]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * k)$ +* Space complexity: $O(k)$ + +> Where $k$ is the maximum length of the subarray and $n$ is the size of the array $arr$. \ No newline at end of file diff --git a/articles/path-with-maximum-gold.md b/articles/path-with-maximum-gold.md new file mode 100644 index 000000000..81c3d201d --- /dev/null +++ b/articles/path-with-maximum-gold.md @@ -0,0 +1,508 @@ +## 1. Backtracking (DFS) - I + +::tabs-start + +```python +class Solution: + def getMaximumGold(self, grid: list[list[int]]) -> int: + ROWS, COLS = len(grid), len(grid[0]) + directions = [(1, 0), (-1, 0), (0, 1), (0, -1)] + + def dfs(r, c, visit): + if min(r, c) < 0 or r == ROWS or c == COLS or grid[r][c] == 0 or (r, c) in visit: + return 0 + + visit.add((r, c)) + res = grid[r][c] + + for dr, dc in directions: + res = max(res, grid[r][c] + dfs(r + dr, c + dc, visit)) + + visit.remove((r, c)) + return res + + res = 0 + for r in range(ROWS): + for c in range(COLS): + if grid[r][c] != 0: + res = max(res, dfs(r, c, set())) + return res +``` + +```java +public class Solution { + private int ROWS, COLS; + private int[][] directions = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; + + public int getMaximumGold(int[][] grid) { + ROWS = grid.length; + COLS = grid[0].length; + int res = 0; + + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + if (grid[r][c] != 0) { + res = Math.max(res, dfs(grid, r, c, new boolean[ROWS][COLS])); + } + } + } + return res; + } + + private int dfs(int[][] grid, int r, int c, boolean[][] visit) { + if (r < 0 || c < 0 || r >= ROWS || c >= COLS || + grid[r][c] == 0 || visit[r][c]) { + return 0; + } + + visit[r][c] = true; + int res = grid[r][c]; + + for (int[] d : directions) { + res = Math.max(res, grid[r][c] + dfs(grid, r + d[0], c + d[1], visit)); + } + + visit[r][c] = false; + return res; + } +} +``` + +```cpp +class Solution { +public: + int ROWS, COLS; + vector> directions = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; + + int getMaximumGold(vector>& grid) { + ROWS = grid.size(); + COLS = grid[0].size(); + int res = 0; + + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + if (grid[r][c] != 0) { + vector> visit(ROWS, vector(COLS, false)); + res = max(res, dfs(grid, r, c, visit)); + } + } + } + return res; + } + +private: + int dfs(vector>& grid, int r, int c, vector>& visit) { + if (r < 0 || c < 0 || r >= ROWS || c >= COLS || grid[r][c] == 0 || visit[r][c]) { + return 0; + } + + visit[r][c] = true; + int res = grid[r][c]; + + for (auto& d : directions) { + res = max(res, grid[r][c] + dfs(grid, r + d[0], c + d[1], visit)); + } + + visit[r][c] = false; + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + getMaximumGold(grid) { + const ROWS = grid.length, COLS = grid[0].length; + const directions = [[1, 0], [-1, 0], [0, 1], [0, -1]]; + + const dfs = (r, c, visit) => { + if (r < 0 || c < 0 || r >= ROWS || c >= COLS || grid[r][c] === 0 || visit[r][c]) { + return 0; + } + + visit[r][c] = true; + let res = grid[r][c]; + + for (const [dr, dc] of directions) { + res = Math.max(res, grid[r][c] + dfs(r + dr, c + dc, visit)); + } + + visit[r][c] = false; + return res; + }; + + let res = 0; + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (grid[r][c] !== 0) { + let visit = Array.from({ length: ROWS }, () => Array(COLS).fill(false)); + res = Math.max(res, dfs(r, c, visit)); + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(N * 3 ^ N)$ +* Space complexity: $O(N)$ + +> Where $N$ is the number of cells which contain gold. + +--- + +## 2. Backtracking (DFS) - II + +::tabs-start + +```python +class Solution: + def getMaximumGold(self, grid: list[list[int]]) -> int: + ROWS, COLS = len(grid), len(grid[0]) + directions = [(1, 0), (-1, 0), (0, 1), (0, -1)] + + def dfs(r, c): + if min(r, c) < 0 or r == ROWS or c == COLS or grid[r][c] == 0: + return 0 + + gold = grid[r][c] + grid[r][c] = 0 + res = 0 + + for dr, dc in directions: + res = max(res, dfs(r + dr, c + dc)) + + grid[r][c] = gold + return gold + res + + res = 0 + for r in range(ROWS): + for c in range(COLS): + if grid[r][c] != 0: + res = max(res, dfs(r, c)) + return res +``` + +```java +public class Solution { + private int ROWS, COLS; + private int[][] directions = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; + + public int getMaximumGold(int[][] grid) { + ROWS = grid.length; + COLS = grid[0].length; + int res = 0; + + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + if (grid[r][c] != 0) { + res = Math.max(res, dfs(grid, r, c)); + } + } + } + return res; + } + + private int dfs(int[][] grid, int r, int c) { + if (r < 0 || c < 0 || r >= ROWS || c >= COLS || grid[r][c] == 0) { + return 0; + } + + int gold = grid[r][c]; + grid[r][c] = 0; + int res = 0; + + for (int[] d : directions) { + res = Math.max(res, dfs(grid, r + d[0], c + d[1])); + } + + grid[r][c] = gold; + return gold + res; + } +} +``` + +```cpp +class Solution { +public: + int ROWS, COLS; + vector> directions = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; + + int getMaximumGold(vector>& grid) { + ROWS = grid.size(); + COLS = grid[0].size(); + int res = 0; + + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + if (grid[r][c] != 0) { + res = max(res, dfs(grid, r, c)); + } + } + } + return res; + } + +private: + int dfs(vector>& grid, int r, int c) { + if (r < 0 || c < 0 || r >= ROWS || c >= COLS || grid[r][c] == 0) { + return 0; + } + + int gold = grid[r][c]; + grid[r][c] = 0; + int res = 0; + + for (auto& d : directions) { + res = max(res, dfs(grid, r + d[0], c + d[1])); + } + + grid[r][c] = gold; + return gold + res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + getMaximumGold(grid) { + const ROWS = grid.length, COLS = grid[0].length; + const directions = [[1, 0], [-1, 0], [0, 1], [0, -1]]; + + const dfs = (r, c) => { + if (r < 0 || c < 0 || r >= ROWS || c >= COLS || grid[r][c] === 0) { + return 0; + } + + let gold = grid[r][c]; + grid[r][c] = 0; + let res = 0; + + for (const [dr, dc] of directions) { + res = Math.max(res, dfs(r + dr, c + dc)); + } + + grid[r][c] = gold; + return gold + res; + }; + + let res = 0; + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (grid[r][c] !== 0) { + res = Math.max(res, dfs(r, c)); + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(N * 3 ^ N)$ +* Space complexity: $O(N)$ for recursion stack. + +> Where $N$ is the number of cells which contain gold. + +--- + +## 3. Backtracking (BFS) + +::tabs-start + +```python +class Solution: + def getMaximumGold(self, grid: list[list[int]]) -> int: + ROWS, COLS = len(grid), len(grid[0]) + directions = [1, 0, -1, 0, 1] + index = [[0] * COLS for _ in range(ROWS)] + idx = 0 + + for r in range(ROWS): + for c in range(COLS): + if grid[r][c] != 0: + index[r][c] = idx + idx += 1 + + res = 0 + for r in range(ROWS): + for c in range(COLS): + if grid[r][c] > 0: + q = deque([(r, c, grid[r][c], 1 << index[r][c])]) + while q: + row, col, gold, mask = q.popleft() + res = max(res, gold) + + for i in range(4): + nr, nc = row + directions[i], col + directions[i + 1] + if 0 <= nr < ROWS and 0 <= nc < COLS and grid[nr][nc] > 0: + idx = index[nr][nc] + if not (mask & (1 << idx)): + q.append((nr, nc, gold + grid[nr][nc], mask | (1 << idx))) + + return res +``` + +```java +public class Solution { + public int getMaximumGold(int[][] grid) { + int ROWS = grid.length, COLS = grid[0].length; + int[][] index = new int[ROWS][COLS]; + int idx = 0; + int[] directions = {1, 0, -1, 0, 1}; + + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + if (grid[r][c] != 0) { + index[r][c] = idx++; + } + } + } + + int res = 0; + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + if (grid[r][c] > 0) { + Queue q = new LinkedList<>(); + q.offer(new int[]{r, c, grid[r][c], 1 << index[r][c]}); + + while (!q.isEmpty()) { + int[] cur = q.poll(); + int row = cur[0], col = cur[1], gold = cur[2], mask = cur[3]; + res = Math.max(res, gold); + + for (int i = 0; i < 4; i++) { + int nr = row + directions[i], nc = col + directions[i + 1]; + if (nr >= 0 && nr < ROWS && nc >= 0 && nc < COLS && grid[nr][nc] > 0) { + int newIdx = index[nr][nc]; + if ((mask & (1 << newIdx)) == 0) { + q.offer(new int[]{nr, nc, gold + grid[nr][nc], mask | (1 << newIdx)}); + } + } + } + } + } + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int getMaximumGold(vector>& grid) { + int ROWS = grid.size(), COLS = grid[0].size(); + vector> index(ROWS, vector(COLS, 0)); + int idx = 0; + int directions[] = {1, 0, -1, 0, 1}; + + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + if (grid[r][c] != 0) { + index[r][c] = idx++; + } + } + } + + int res = 0; + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + if (grid[r][c] > 0) { + queue> q; + q.push({r, c, grid[r][c], 1 << index[r][c]}); + + while (!q.empty()) { + auto [row, col, gold, mask] = q.front();q.pop(); + res = max(res, gold); + for (int i = 0; i < 4; i++) { + int nr = row + directions[i], nc = col + directions[i + 1]; + if (nr >= 0 && nr < ROWS && nc >= 0 && nc < COLS && grid[nr][nc] > 0) { + int newIdx = index[nr][nc]; + if ((mask & (1 << newIdx)) == 0) { + q.push({nr, nc, gold + grid[nr][nc], mask | (1 << newIdx)}); + } + } + } + } + } + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + getMaximumGold(grid) { + const ROWS = grid.length, COLS = grid[0].length; + const index = Array.from({ length: ROWS }, () => Array(COLS).fill(0)); + let idx = 0; + const directions = [1, 0, -1, 0, 1]; + + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (grid[r][c] !== 0) { + index[r][c] = idx++; + } + } + } + + let res = 0; + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (grid[r][c] > 0) { + const q = new Queue([[r, c, grid[r][c], 1 << index[r][c]]]); + + while (!q.isEmpty()) { + const [row, col, gold, mask] = q.pop(); + res = Math.max(res, gold); + for (let i = 0; i < 4; i++) { + const nr = row + directions[i], nc = col + directions[i + 1]; + if (nr >= 0 && nr < ROWS && nc >= 0 && nc < COLS && grid[nr][nc] > 0) { + const newIdx = index[nr][nc]; + if (!(mask & (1 << newIdx))) { + q.push([nr, nc, gold + grid[nr][nc], mask | (1 << newIdx)]); + } + } + } + } + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(N * 3 ^ N)$ +* Space complexity: $O(N)$ + +> Where $N$ is the number of cells which contain gold. \ No newline at end of file diff --git a/articles/path-with-maximum-probability.md b/articles/path-with-maximum-probability.md new file mode 100644 index 000000000..b16d1e43b --- /dev/null +++ b/articles/path-with-maximum-probability.md @@ -0,0 +1,632 @@ +## 1. Dijkstra's Algorithm - I + +::tabs-start + +```python +class Solution: + def maxProbability(self, n: int, edges: List[List[int]], succProb: List[float], start_node: int, end_node: int) -> float: + adj = collections.defaultdict(list) + for i in range(len(edges)): + src, dst = edges[i] + adj[src].append((dst, succProb[i])) + adj[dst].append((src, succProb[i])) + + pq = [(-1, start_node)] + visit = set() + + while pq: + prob, cur = heapq.heappop(pq) + visit.add(cur) + + if cur == end_node: + return -prob + + for nei, edgeProb in adj[cur]: + if nei not in visit: + heapq.heappush(pq, (prob * edgeProb, nei)) + + return 0.0 +``` + +```java +public class Solution { + public double maxProbability(int n, int[][] edges, double[] succProb, int start_node, int end_node) { + List[] adj = new ArrayList[n]; + for (int i = 0; i < n; i++) adj[i] = new ArrayList<>(); + + for (int i = 0; i < edges.length; i++) { + int src = edges[i][0], dst = edges[i][1]; + adj[src].add(new Pair(dst, succProb[i])); + adj[dst].add(new Pair(src, succProb[i])); + } + + double[] maxProb = new double[n]; + maxProb[start_node] = 1.0; + PriorityQueue pq = new PriorityQueue<>((a, b) -> Double.compare(b.prob, a.prob)); + pq.offer(new Pair(start_node, 1.0)); + + while (!pq.isEmpty()) { + Pair top = pq.poll(); + int node = top.node; + double curr_prob = top.prob; + + if (node == end_node) return curr_prob; + if (curr_prob > maxProb[node]) continue; + + for (Pair nei : adj[node]) { + double new_prob = curr_prob * nei.prob; + if (new_prob > maxProb[nei.node]) { + maxProb[nei.node] = new_prob; + pq.offer(new Pair(nei.node, new_prob)); + } + } + } + + return 0.0; + } + + static class Pair { + int node; + double prob; + + Pair(int node, double prob) { + this.node = node; + this.prob = prob; + } + } +} +``` + +```cpp +class Solution { +public: + double maxProbability(int n, vector>& edges, vector& succProb, int start_node, int end_node) { + vector>> adj(n); + for (int i = 0; i < edges.size(); i++) { + int src = edges[i][0], dst = edges[i][1]; + adj[src].emplace_back(dst, succProb[i]); + adj[dst].emplace_back(src, succProb[i]); + } + + vector maxProb(n, 0.0); + maxProb[start_node] = 1.0; + priority_queue> pq; + pq.emplace(1.0, start_node); + + while (!pq.empty()) { + auto [curr_prob, node] = pq.top(); pq.pop(); + + if (node == end_node) return curr_prob; + if (curr_prob > maxProb[node]) continue; + + for (auto& [nei, edge_prob] : adj[node]) { + double new_prob = curr_prob * edge_prob; + if (new_prob > maxProb[nei]) { + maxProb[nei] = new_prob; + pq.emplace(new_prob, nei); + } + } + } + + return 0.0; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number[][]} edges + * @param {number[]} succProb + * @param {number} start_node + * @param {number} end_node + * @return {number} + */ + maxProbability(n, edges, succProb, start_node, end_node) { + let adj = new Map(); + for (let i = 0; i < n; i++) adj.set(i, []); + + for (let i = 0; i < edges.length; i++) { + let [src, dst] = edges[i]; + adj.get(src).push([dst, succProb[i]]); + adj.get(dst).push([src, succProb[i]]); + } + + let pq = new MaxPriorityQueue({ priority: x => x[0] }); + pq.enqueue([1.0, start_node]); + let visited = new Set(); + + while (!pq.isEmpty()) { + let [prob, cur] = pq.dequeue().element; + visited.add(cur); + + if (cur === end_node) return prob; + + for (let [nei, edgeProb] of adj.get(cur)) { + if (!visited.has(nei)) { + pq.enqueue([prob * edgeProb, nei]); + } + } + } + + return 0.0; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O((V + E) \log V)$ +* Space complexity: $O(V + E)$ + +> Where $V$ is the number nodes and $E$ is the number of edges. + +--- + +## 2. Dijkstra's Algorithm - II + +::tabs-start + +```python +class Solution: + def maxProbability(self, n: int, edges: List[List[int]], succProb: List[float], start_node: int, end_node: int) -> float: + adj = [[] for _ in range(n)] + for i in range(len(edges)): + src, dst = edges[i] + adj[src].append((dst, succProb[i])) + adj[dst].append((src, succProb[i])) + + maxProb = [0] * n + maxProb[start_node] = 1.0 + pq = [(-1.0, start_node)] + + while pq: + curr_prob, node = heapq.heappop(pq) + curr_prob *= -1 + + if node == end_node: + return curr_prob + if curr_prob > maxProb[node]: + continue + + for nei, edge_prob in adj[node]: + new_prob = curr_prob * edge_prob + if new_prob > maxProb[nei]: + maxProb[nei] = new_prob + heapq.heappush(pq, (-new_prob, nei)) + + return 0.0 +``` + +```java +public class Solution { + public double maxProbability(int n, int[][] edges, double[] succProb, int start_node, int end_node) { + List[] adj = new ArrayList[n]; + for (int i = 0; i < n; i++) adj[i] = new ArrayList<>(); + + for (int i = 0; i < edges.length; i++) { + int src = edges[i][0], dst = edges[i][1]; + adj[src].add(new Pair(dst, succProb[i])); + adj[dst].add(new Pair(src, succProb[i])); + } + + double[] maxProb = new double[n]; + maxProb[start_node] = 1.0; + PriorityQueue pq = new PriorityQueue<>((a, b) -> Double.compare(b.prob, a.prob)); + pq.offer(new Pair(start_node, 1.0)); + + while (!pq.isEmpty()) { + Pair top = pq.poll(); + int node = top.node; + double curr_prob = top.prob; + + if (node == end_node) return curr_prob; + if (curr_prob > maxProb[node]) continue; + + for (Pair nei : adj[node]) { + double new_prob = curr_prob * nei.prob; + if (new_prob > maxProb[nei.node]) { + maxProb[nei.node] = new_prob; + pq.offer(new Pair(nei.node, new_prob)); + } + } + } + + return 0.0; + } + + static class Pair { + int node; + double prob; + + Pair(int node, double prob) { + this.node = node; + this.prob = prob; + } + } +} +``` + +```cpp +class Solution { +public: + double maxProbability(int n, vector>& edges, vector& succProb, int start_node, int end_node) { + vector>> adj(n); + for (int i = 0; i < edges.size(); i++) { + int src = edges[i][0], dst = edges[i][1]; + adj[src].emplace_back(dst, succProb[i]); + adj[dst].emplace_back(src, succProb[i]); + } + + vector maxProb(n, 0.0); + maxProb[start_node] = 1.0; + priority_queue> pq; + pq.emplace(1.0, start_node); + + while (!pq.empty()) { + auto [curr_prob, node] = pq.top(); pq.pop(); + + if (node == end_node) return curr_prob; + if (curr_prob > maxProb[node]) continue; + + for (auto& [nei, edge_prob] : adj[node]) { + double new_prob = curr_prob * edge_prob; + if (new_prob > maxProb[nei]) { + maxProb[nei] = new_prob; + pq.emplace(new_prob, nei); + } + } + } + + return 0.0; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number[][]} edges + * @param {number[]} succProb + * @param {number} start_node + * @param {number} end_node + * @return {number} + */ + maxProbability(n, edges, succProb, start_node, end_node) { + let adj = Array.from({ length: n }, () => []); + for (let i = 0; i < edges.length; i++) { + let [src, dst] = edges[i]; + adj[src].push([dst, succProb[i]]); + adj[dst].push([src, succProb[i]]); + } + + let maxProb = Array(n).fill(0); + maxProb[start_node] = 1.0; + let pq = new MaxPriorityQueue({ priority: x => x[1] }); + pq.enqueue([start_node, 1.0]); + + while (!pq.isEmpty()) { + let [node, curr_prob] = pq.dequeue().element; + + if (node === end_node) return curr_prob; + if (curr_prob > maxProb[node]) continue; + + for (let [nei, edge_prob] of adj[node]) { + let new_prob = curr_prob * edge_prob; + if (new_prob > maxProb[nei]) { + maxProb[nei] = new_prob; + pq.enqueue([nei, new_prob]); + } + } + } + + return 0.0; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O((V + E) \log V)$ +* Space complexity: $O(V + E)$ + +> Where $V$ is the number nodes and $E$ is the number of edges. + +--- + +## 3. Bellman Ford Algorithm + +::tabs-start + +```python +class Solution: + def maxProbability(self, n: int, edges: List[List[int]], succProb: List[float], start_node: int, end_node: int) -> float: + maxProb = [0.0] * n + maxProb[start_node] = 1.0 + + for i in range(n): + updated = False + for j in range(len(edges)): + src, dst = edges[j] + if maxProb[src] * succProb[j] > maxProb[dst]: + maxProb[dst] = maxProb[src] * succProb[j] + updated = True + + if maxProb[dst] * succProb[j] > maxProb[src]: + maxProb[src] = maxProb[dst] * succProb[j] + updated = True + + if not updated: + break + + return maxProb[end_node] +``` + +```java +public class Solution { + public double maxProbability(int n, int[][] edges, double[] succProb, int start_node, int end_node) { + double[] maxProb = new double[n]; + maxProb[start_node] = 1.0; + + for (int i = 0; i < n; i++) { + boolean updated = false; + for (int j = 0; j < edges.length; j++) { + int src = edges[j][0], dst = edges[j][1]; + + if (maxProb[src] * succProb[j] > maxProb[dst]) { + maxProb[dst] = maxProb[src] * succProb[j]; + updated = true; + } + + if (maxProb[dst] * succProb[j] > maxProb[src]) { + maxProb[src] = maxProb[dst] * succProb[j]; + updated = true; + } + } + if (!updated) break; + } + + return maxProb[end_node]; + } +} +``` + +```cpp +class Solution { +public: + double maxProbability(int n, vector>& edges, vector& succProb, int start_node, int end_node) { + vector maxProb(n, 0.0); + maxProb[start_node] = 1.0; + + for (int i = 0; i < n; i++) { + bool updated = false; + for (int j = 0; j < edges.size(); j++) { + int src = edges[j][0], dst = edges[j][1]; + + if (maxProb[src] * succProb[j] > maxProb[dst]) { + maxProb[dst] = maxProb[src] * succProb[j]; + updated = true; + } + + if (maxProb[dst] * succProb[j] > maxProb[src]) { + maxProb[src] = maxProb[dst] * succProb[j]; + updated = true; + } + } + if (!updated) break; + } + + return maxProb[end_node]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number[][]} edges + * @param {number[]} succProb + * @param {number} start_node + * @param {number} end_node + * @return {number} + */ + maxProbability(n, edges, succProb, start_node, end_node) { + let maxProb = new Array(n).fill(0.0); + maxProb[start_node] = 1.0; + + for (let i = 0; i < n; i++) { + let updated = false; + for (let j = 0; j < edges.length; j++) { + let [src, dst] = edges[j]; + + if (maxProb[src] * succProb[j] > maxProb[dst]) { + maxProb[dst] = maxProb[src] * succProb[j]; + updated = true; + } + + if (maxProb[dst] * succProb[j] > maxProb[src]) { + maxProb[src] = maxProb[dst] * succProb[j]; + updated = true; + } + } + if (!updated) break; + } + + return maxProb[end_node]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(V * E)$ +* Space complexity: $O(V)$ + +> Where $V$ is the number nodes and $E$ is the number of edges. + +--- + +## 4. Shortest Path Faster Algorithm + +::tabs-start + +```python +class Solution: + def maxProbability(self, n: int, edges: List[List[int]], succProb: List[float], start_node: int, end_node: int) -> float: + adj = [[] for _ in range(n)] + for i in range(len(edges)): + src, dst = edges[i] + adj[src].append((dst, succProb[i])) + adj[dst].append((src, succProb[i])) + + maxProb = [0.0] * n + maxProb[start_node] = 1.0 + q = deque([start_node]) + + while q: + node = q.popleft() + + for nei, edge_prob in adj[node]: + new_prob = maxProb[node] * edge_prob + if new_prob > maxProb[nei]: + maxProb[nei] = new_prob + q.append(nei) + + return maxProb[end_node] +``` + +```java +public class Solution { + public double maxProbability(int n, int[][] edges, double[] succProb, int start_node, int end_node) { + List[] adj = new ArrayList[n]; + for (int i = 0; i < n; i++) adj[i] = new ArrayList<>(); + + for (int i = 0; i < edges.length; i++) { + int src = edges[i][0], dst = edges[i][1]; + adj[src].add(new Pair(dst, succProb[i])); + adj[dst].add(new Pair(src, succProb[i])); + } + + double[] maxProb = new double[n]; + maxProb[start_node] = 1.0; + Queue q = new LinkedList<>(); + q.offer(start_node); + + while (!q.isEmpty()) { + int node = q.poll(); + + for (Pair nei : adj[node]) { + double newProb = maxProb[node] * nei.prob; + if (newProb > maxProb[nei.node]) { + maxProb[nei.node] = newProb; + q.offer(nei.node); + } + } + } + + return maxProb[end_node]; + } + + static class Pair { + int node; + double prob; + + Pair(int node, double prob) { + this.node = node; + this.prob = prob; + } + } +} +``` + +```cpp +class Solution { +public: + double maxProbability(int n, vector>& edges, vector& succProb, int start_node, int end_node) { + vector>> adj(n); + + for (int i = 0; i < edges.size(); i++) { + int src = edges[i][0], dst = edges[i][1]; + adj[src].emplace_back(dst, succProb[i]); + adj[dst].emplace_back(src, succProb[i]); + } + + vector maxProb(n, 0.0); + maxProb[start_node] = 1.0; + queue q; + q.push(start_node); + + while (!q.empty()) { + int node = q.front(); + q.pop(); + + for (auto& [nei, edgeProb] : adj[node]) { + double newProb = maxProb[node] * edgeProb; + if (newProb > maxProb[nei]) { + maxProb[nei] = newProb; + q.push(nei); + } + } + } + + return maxProb[end_node]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number[][]} edges + * @param {number[]} succProb + * @param {number} start_node + * @param {number} end_node + * @return {number} + */ + maxProbability(n, edges, succProb, start_node, end_node) { + let adj = Array.from({ length: n }, () => []); + for (let i = 0; i < edges.length; i++) { + let [src, dst] = edges[i]; + adj[src].push([dst, succProb[i]]); + adj[dst].push([src, succProb[i]]); + } + + let maxProb = new Array(n).fill(0.0); + maxProb[start_node] = 1.0; + const q = new Queue([start_node]); + + while (!q.isEmpty()) { + let node = q.pop(); + + for (let [nei, edgeProb] of adj[node]) { + let newProb = maxProb[node] * edgeProb; + if (newProb > maxProb[nei]) { + maxProb[nei] = newProb; + q.push(nei); + } + } + } + + return maxProb[end_node]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(V * E)$ +* Space complexity: $O(V + E)$ + +> Where $V$ is the number nodes and $E$ is the number of edges. \ No newline at end of file diff --git a/articles/remove-colored-pieces-if-both-neighbors-are-the-same-color.md b/articles/remove-colored-pieces-if-both-neighbors-are-the-same-color.md new file mode 100644 index 000000000..156cbb636 --- /dev/null +++ b/articles/remove-colored-pieces-if-both-neighbors-are-the-same-color.md @@ -0,0 +1,322 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def winnerOfGame(self, colors: str) -> bool: + s = list(colors) + + def removeChar(c): + for i in range(1, len(s) - 1): + if s[i] != c: + continue + + if s[i] == s[i + 1] == s[i - 1]: + s.pop(i) + return True + return False + + while True: + if not removeChar('A'): + return False + if not removeChar('B'): + return True + + return False +``` + +```java +public class Solution { + public boolean winnerOfGame(String colors) { + StringBuilder s = new StringBuilder(colors); + + while (true) { + if (!removeChar(s, 'A')) return false; + if (!removeChar(s, 'B')) return true; + } + } + + private boolean removeChar(StringBuilder s, char c) { + for (int i = 1; i < s.length() - 1; i++) { + if (s.charAt(i) != c) continue; + + if (s.charAt(i - 1) == c && s.charAt(i + 1) == c) { + s.deleteCharAt(i); + return true; + } + } + return false; + } +} +``` + +```cpp +class Solution { +public: + bool winnerOfGame(string colors) { + while (true) { + if (!removeChar(colors, 'A')) return false; + if (!removeChar(colors, 'B')) return true; + } + } + +private: + bool removeChar(string& s, char c) { + for (int i = 1; i < s.size() - 1; i++) { + if (s[i] != c) continue; + + if (s[i - 1] == c && s[i + 1] == c) { + s.erase(i, 1); + return true; + } + } + return false; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} colors + * @return {boolean} + */ + winnerOfGame(colors) { + let s = colors.split(""); + + const removeChar = (c) => { + for (let i = 1; i < s.length - 1; i++) { + if (s[i] !== c) continue; + + if (s[i - 1] === c && s[i + 1] === c) { + s.splice(i, 1); + return true; + } + } + return false; + }; + + while (true) { + if (!removeChar('A')) return false; + if (!removeChar('B')) return true; + } + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n)$ + +--- + +## 2. Greedy + Two Pointers + +::tabs-start + +```python +class Solution: + def winnerOfGame(self, colors: str) -> bool: + alice = bob = l = 0 + + for r in range(len(colors)): + if colors[l] != colors[r]: + l = r + + extra = r - l - 1 + if extra > 0: + if colors[l] == 'A': + alice += 1 + else: + bob += 1 + + return alice > bob +``` + +```java +public class Solution { + public boolean winnerOfGame(String colors) { + int alice = 0, bob = 0, l = 0; + + for (int r = 0; r < colors.length(); r++) { + if (colors.charAt(l) != colors.charAt(r)) { + l = r; + } + + int extra = r - l - 1; + if (extra > 0) { + if (colors.charAt(l) == 'A') { + alice++; + } else { + bob++; + } + } + } + + return alice > bob; + } +} +``` + +```cpp +class Solution { +public: + bool winnerOfGame(string colors) { + int alice = 0, bob = 0, l = 0; + + for (int r = 0; r < colors.size(); r++) { + if (colors[l] != colors[r]) { + l = r; + } + + int extra = r - l - 1; + if (extra > 0) { + if (colors[l] == 'A') { + alice++; + } else { + bob++; + } + } + } + + return alice > bob; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} colors + * @return {boolean} + */ + winnerOfGame(colors) { + let alice = 0, bob = 0, l = 0; + + for (let r = 0; r < colors.length; r++) { + if (colors[l] !== colors[r]) { + l = r; + } + + let extra = r - l - 1; + if (extra > 0) { + if (colors[l] === 'A') { + alice++; + } else { + bob++; + } + } + } + + return alice > bob; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ extra space. + +--- + +## 3. Greedy + +::tabs-start + +```python +class Solution: + def winnerOfGame(self, colors: str) -> bool: + alice, bob = 0, 0 + + for i in range(1, len(colors) - 1): + if colors[i - 1] == colors[i] == colors[i + 1]: + if colors[i] == 'A': + alice += 1 + if colors[i] == 'B': + bob += 1 + + return alice > bob +``` + +```java +public class Solution { + public boolean winnerOfGame(String colors) { + int alice = 0, bob = 0; + + for (int i = 1; i < colors.length() - 1; i++) { + if (colors.charAt(i - 1) == colors.charAt(i) && + colors.charAt(i) == colors.charAt(i + 1)) { + if (colors.charAt(i) == 'A') { + alice++; + } + if (colors.charAt(i) == 'B') { + bob++; + } + } + } + + return alice > bob; + } +} +``` + +```cpp +class Solution { +public: + bool winnerOfGame(string colors) { + int alice = 0, bob = 0; + + for (int i = 1; i < colors.size() - 1; i++) { + if (colors[i - 1] == colors[i] && colors[i] == colors[i + 1]) { + if (colors[i] == 'A') { + alice++; + } + if (colors[i] == 'B') { + bob++; + } + } + } + + return alice > bob; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} colors + * @return {boolean} + */ + winnerOfGame(colors) { + let alice = 0, bob = 0; + + for (let i = 1; i < colors.length - 1; i++) { + if (colors[i - 1] === colors[i] && colors[i] === colors[i + 1]) { + if (colors[i] === 'A') { + alice++; + } + if (colors[i] === 'B') { + bob++; + } + } + } + + return alice > bob; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ extra space. \ No newline at end of file diff --git a/articles/remove-covered-intervals.md b/articles/remove-covered-intervals.md new file mode 100644 index 000000000..f71a0cfcc --- /dev/null +++ b/articles/remove-covered-intervals.md @@ -0,0 +1,275 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def removeCoveredIntervals(self, intervals: List[List[int]]) -> int: + n = len(intervals) + res = n + + for i in range(n): + for j in range(n): + if (i != j and intervals[j][0] <= intervals[i][0] and + intervals[j][1] >= intervals[i][1] + ): + res -= 1 + break + + return res +``` + +```java +public class Solution { + public int removeCoveredIntervals(int[][] intervals) { + int n = intervals.length; + int res = n; + + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + if (i != j && intervals[j][0] <= intervals[i][0] && + intervals[j][1] >= intervals[i][1]) { + res--; + break; + } + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int removeCoveredIntervals(vector>& intervals) { + int n = intervals.size(); + int res = n; + + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + if (i != j && intervals[j][0] <= intervals[i][0] && + intervals[j][1] >= intervals[i][1]) { + res--; + break; + } + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} intervals + * @return {number} + */ + removeCoveredIntervals(intervals) { + let n = intervals.length; + let res = n; + + for (let i = 0; i < n; i++) { + for (let j = 0; j < n; j++) { + if (i !== j && intervals[j][0] <= intervals[i][0] && + intervals[j][1] >= intervals[i][1]) { + res--; + break; + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(1)$ extra space. + +--- + +## 2. Sorting - I + +::tabs-start + +```python +class Solution: + def removeCoveredIntervals(self, intervals: List[List[int]]) -> int: + intervals.sort(key=lambda x: (x[0], -x[1])) + res = 1 + prevL, prevR = intervals[0][0], intervals[0][1] + for l, r in intervals: + if prevL <= l and prevR >= r: + continue + res += 1 + prevL, prevR = l, r + + return res +``` + +```java +public class Solution { + public int removeCoveredIntervals(int[][] intervals) { + Arrays.sort(intervals, (a, b) -> + a[0] == b[0] ? Integer.compare(b[1], a[1]) : Integer.compare(a[0], b[0]) + ); + int res = 1, prevL = intervals[0][0], prevR = intervals[0][1]; + for (int[] interval : intervals) { + int l = interval[0], r = interval[1]; + if (prevL <= l && prevR >= r) { + continue; + } + res++; + prevL = l; + prevR = r; + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int removeCoveredIntervals(vector>& intervals) { + sort(intervals.begin(), intervals.end(), [](const auto& a, const auto& b) { + return a[0] == b[0] ? b[1] < a[1] : a[0] < b[0]; + }); + + int res = 1, prevL = intervals[0][0], prevR = intervals[0][1]; + for (const auto& interval : intervals) { + int l = interval[0], r = interval[1]; + if (prevL <= l && prevR >= r) { + continue; + } + res++; + prevL = l; + prevR = r; + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} intervals + * @return {number} + */ + removeCoveredIntervals(intervals) { + intervals.sort((a, b) => a[0] === b[0] ? b[1] - a[1] : a[0] - b[0]); + let res = 1, [prevL, prevR] = intervals[0]; + for (const [l, r] of intervals) { + if (prevL <= l && prevR >= r) { + continue; + } + res++; + prevL = l; + prevR = r; + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n\log n)$ +* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. + +--- + +## 3. Sorting - II + +::tabs-start + +```python +class Solution: + def removeCoveredIntervals(self, intervals: List[List[int]]) -> int: + intervals.sort() + res, start, end = 1, intervals[0][0], intervals[0][1] + + for l, r in intervals: + if start < l and end < r: + start = l + res += 1 + end = max(end, r) + + return res +``` + +```java +public class Solution { + public int removeCoveredIntervals(int[][] intervals) { + Arrays.sort(intervals, (a, b) -> a[0] - b[0]); + int res = 1, start = intervals[0][0], end = intervals[0][1]; + + for (int[] interval : intervals) { + int l = interval[0], r = interval[1]; + if (start < l && end < r) { + start = l; + res++; + } + end = Math.max(end, r); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int removeCoveredIntervals(vector>& intervals) { + sort(intervals.begin(), intervals.end()); + int res = 1, start = intervals[0][0], end = intervals[0][1]; + + for (const auto& interval : intervals) { + int l = interval[0], r = interval[1]; + if (start < l && end < r) { + start = l; + res++; + } + end = max(end, r); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} intervals + * @return {number} + */ + removeCoveredIntervals(intervals) { + intervals.sort((a, b) => a[0] - b[0]); + let res = 1, start = intervals[0][0], end = intervals[0][1]; + + for (const [l, r] of intervals) { + if (start < l && end < r) { + start = l; + res++; + } + end = Math.max(end, r); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. \ No newline at end of file diff --git a/articles/remove-max-number-of-edges-to-keep-graph-fully-traversable.md b/articles/remove-max-number-of-edges-to-keep-graph-fully-traversable.md new file mode 100644 index 000000000..04c3da1ac --- /dev/null +++ b/articles/remove-max-number-of-edges-to-keep-graph-fully-traversable.md @@ -0,0 +1,274 @@ +## 1. Disjoint Set Union + +::tabs-start + +```python +class DSU: + def __init__(self, n): + self.n = n + self.Parent = list(range(n + 1)) + self.Size = [1] * (n + 1) + + def find(self, node): + if self.Parent[node] != node: + self.Parent[node] = self.find(self.Parent[node]) + return self.Parent[node] + + def union(self, u, v): + pu = self.find(u) + pv = self.find(v) + if pu == pv: + return 0 + if self.Size[pu] < self.Size[pv]: + pu, pv = pv, pu + self.Size[pu] += self.Size[pv] + self.Parent[pv] = pu + self.n -= 1 + return 1 + + def isConnected(self): + return self.n == 1 + +class Solution: + def maxNumEdgesToRemove(self, n: int, edges: List[List[int]]) -> int: + alice, bob = DSU(n), DSU(n) + cnt = 0 + + for type, src, dst in edges: + if type == 3: + cnt += (alice.union(src, dst) | bob.union(src, dst)) + + for type, src, dst in edges: + if type == 1: + cnt += alice.union(src, dst) + elif type == 2: + cnt += bob.union(src, dst) + + if alice.isConnected() and bob.isConnected(): + return len(edges) - cnt + return -1 +``` + +```java +class DSU { + private int[] parent, size; + private int n; + + public DSU(int n) { + this.n = n; + parent = new int[n + 1]; + size = new int[n + 1]; + for (int i = 0; i <= n; i++) { + parent[i] = i; + size[i] = 1; + } + } + + public int find(int node) { + if (parent[node] != node) { + parent[node] = find(parent[node]); + } + return parent[node]; + } + + public int union(int u, int v) { + int pu = find(u), pv = find(v); + if (pu == pv) { + return 0; + } + if (size[pu] < size[pv]) { + int temp = pu; + pu = pv; + pv = temp; + } + size[pu] += size[pv]; + parent[pv] = pu; + n--; + return 1; + } + + public boolean isConnected() { + return n == 1; + } +} + +public class Solution { + public int maxNumEdgesToRemove(int n, int[][] edges) { + DSU alice = new DSU(n), bob = new DSU(n); + int cnt = 0; + + for (int[] edge : edges) { + if (edge[0] == 3) { + cnt += (alice.union(edge[1], edge[2]) | bob.union(edge[1], edge[2])); + } + } + + for (int[] edge : edges) { + if (edge[0] == 1) { + cnt += alice.union(edge[1], edge[2]); + } else if (edge[0] == 2) { + cnt += bob.union(edge[1], edge[2]); + } + } + + if (alice.isConnected() && bob.isConnected()) { + return edges.length - cnt; + } + return -1; + } +} +``` + +```cpp +class DSU { +private: + vector parent, size; + int n; + +public: + DSU(int n) : n(n), parent(n + 1), size(n + 1, 1) { + for (int i = 0; i <= n; i++) { + parent[i] = i; + } + } + + int find(int node) { + if (parent[node] != node) { + parent[node] = find(parent[node]); + } + return parent[node]; + } + + int unionSets(int u, int v) { + int pu = find(u), pv = find(v); + if (pu == pv) { + return 0; + } + if (size[pu] < size[pv]) { + swap(pu, pv); + } + size[pu] += size[pv]; + parent[pv] = pu; + n--; + return 1; + } + + bool isConnected() { + return n == 1; + } +}; + +class Solution { +public: + int maxNumEdgesToRemove(int n, vector>& edges) { + DSU alice(n), bob(n); + int cnt = 0; + + for (auto& edge : edges) { + if (edge[0] == 3) { + cnt += (alice.unionSets(edge[1], edge[2]) | bob.unionSets(edge[1], edge[2])); + } + } + + for (auto& edge : edges) { + if (edge[0] == 1) { + cnt += alice.unionSets(edge[1], edge[2]); + } else if (edge[0] == 2) { + cnt += bob.unionSets(edge[1], edge[2]); + } + } + + if (alice.isConnected() && bob.isConnected()) { + return edges.size() - cnt; + } + return -1; + } +}; +``` + +```javascript +class DSU { + /** + * @param {number} n + */ + constructor(n) { + this.n = n; + this.parent = Array(n + 1).fill(0).map((_, i) => i); + this.size = Array(n + 1).fill(1); + } + + /** + * @param {number} node + * @return {number} + */ + find(node) { + if (this.parent[node] !== node) { + this.parent[node] = this.find(this.parent[node]); + } + return this.parent[node]; + } + + /** + * @param {number} u + * @param {number} v + * @return {number} + */ + union(u, v) { + let pu = this.find(u), pv = this.find(v); + if (pu === pv) { + return 0; + } + if (this.size[pu] < this.size[pv]) { + [pu, pv] = [pv, pu]; + } + this.size[pu] += this.size[pv]; + this.parent[pv] = pu; + this.n--; + return 1; + } + + /** + * @return {boolean} + */ + isConnected() { + return this.n === 1; + } +} + +class Solution { + /** + * @param {number} n + * @param {number[][]} edges + * @return {number} + */ + maxNumEdgesToRemove(n, edges) { + let alice = new DSU(n), bob = new DSU(n); + let cnt = 0; + + for (let [type, src, dst] of edges) { + if (type === 3) { + cnt += (alice.union(src, dst) | bob.union(src, dst)); + } + } + + for (let [type, src, dst] of edges) { + if (type === 1) { + cnt += alice.union(src, dst); + } else if (type === 2) { + cnt += bob.union(src, dst); + } + } + + return alice.isConnected() && bob.isConnected() ? edges.length - cnt : -1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(E * α(V))$ +* Space complexity: $O(V)$ + +> Where $V$ is the number of verticies and $E$ is the number of edges. \ No newline at end of file diff --git a/articles/reveal-cards-in-increasing-order.md b/articles/reveal-cards-in-increasing-order.md new file mode 100644 index 000000000..4759af658 --- /dev/null +++ b/articles/reveal-cards-in-increasing-order.md @@ -0,0 +1,406 @@ +## 1. Simulation Using Queue - I + +::tabs-start + +```python +class Solution: + def deckRevealedIncreasing(self, deck: List[int]) -> List[int]: + deck.sort() + res = [0] * len(deck) + q = deque(range(len(deck))) + + for num in deck: + i = q.popleft() + res[i] = num + if q: + q.append(q.popleft()) + + return res +``` + +```java +public class Solution { + public int[] deckRevealedIncreasing(int[] deck) { + Arrays.sort(deck); + int n = deck.length; + int[] res = new int[n]; + Queue q = new LinkedList<>(); + + for (int i = 0; i < n; i++) { + q.offer(i); + } + + for (int num : deck) { + int i = q.poll(); + res[i] = num; + if (!q.isEmpty()) { + q.offer(q.poll()); + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector deckRevealedIncreasing(vector& deck) { + sort(deck.begin(), deck.end()); + int n = deck.size(); + vector res(n); + queue q; + + for (int i = 0; i < n; i++) { + q.push(i); + } + + for (int num : deck) { + int i = q.front(); + q.pop(); + res[i] = num; + if (!q.empty()) { + q.push(q.front()); + q.pop(); + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} deck + * @return {number[]} + */ + deckRevealedIncreasing(deck) { + deck.sort((a, b) => a - b); + let n = deck.length; + let res = new Array(n).fill(0); + const q = new Queue(); + + for (let i = 0; i < n; i++) { + q.push(i); + } + + for (let num of deck) { + let i = q.pop(); + res[i] = num; + if (!q.isEmpty()) { + q.push(q.pop()); + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(n)$ + +--- + +## 2. Simuation Using Queue - II + +::tabs-start + +```python +class Solution: + def deckRevealedIncreasing(self, deck: List[int]) -> List[int]: + deck.sort() + q = deque() + for i in range(len(deck) - 1, -1, -1): + if q: + q.append(q.popleft()) + q.append(deck[i]) + return list(q)[::-1] +``` + +```java +public class Solution { + public int[] deckRevealedIncreasing(int[] deck) { + Arrays.sort(deck); + Queue q = new LinkedList<>(); + + for (int i = deck.length - 1; i >= 0; i--) { + if (!q.isEmpty()) { + q.offer(q.poll()); + } + q.offer(deck[i]); + } + + int[] res = new int[deck.length]; + for (int i = deck.length - 1; i >= 0; i--) { + res[i] = q.poll(); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + vector deckRevealedIncreasing(vector& deck) { + sort(deck.begin(), deck.end()); + queue q; + + for (int i = deck.size() - 1; i >= 0; i--) { + if (!q.empty()) { + q.push(q.front()); + q.pop(); + } + q.push(deck[i]); + } + + vector res(deck.size()); + for (int i = deck.size() - 1; i >= 0; i--) { + res[i] = q.front(); + q.pop(); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} deck + * @return {number[]} + */ + deckRevealedIncreasing(deck) { + deck.sort((a, b) => a - b); + const q = new Queue(); + + for (let i = deck.length - 1; i >= 0; i--) { + if (!q.isEmpty()) { + q.push(q.pop()); + } + q.push(deck[i]); + } + + return q.toArray().reverse(); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(n)$ + +--- + +## 3. Simulation Using Deque + +::tabs-start + +```python +class Solution: + def deckRevealedIncreasing(self, deck: List[int]) -> List[int]: + deck.sort() + dq = deque() + dq.append(deck.pop()) + for i in range(len(deck) - 1, -1, -1): + dq.appendleft(dq.pop()) + dq.appendleft(deck[i]) + return list(dq) +``` + +```java +public class Solution { + public int[] deckRevealedIncreasing(int[] deck) { + int n = deck.length; + Arrays.sort(deck); + Deque dq = new LinkedList<>(); + dq.addLast(deck[n - 1]); + + for (int i = n - 2; i >= 0; i--) { + dq.addFirst(dq.removeLast()); + dq.addFirst(deck[i]); + } + + return dq.stream().mapToInt(Integer::intValue).toArray(); + } +} +``` + +```cpp +class Solution { +public: + vector deckRevealedIncreasing(vector& deck) { + sort(deck.begin(), deck.end()); + deque dq; + dq.push_back(deck.back()); + + for (int i = deck.size() - 2; i >= 0; i--) { + dq.push_front(dq.back()); + dq.pop_back(); + dq.push_front(deck[i]); + } + + return vector(dq.begin(), dq.end()); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} deck + * @return {number[]} + */ + deckRevealedIncreasing(deck) { + deck.sort((a, b) => a - b); + const dq = new Deque([deck.pop()]); + + for (let i = deck.length - 1; i >= 0; i--) { + let val = dq.popBack(); + dq.pushFront(val); + dq.pushFront(deck[i]); + } + + let res = []; + while (!dq.isEmpty()) { + res.push(dq.popFront()); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(n)$ + +--- + +## 4. Simulation Using Two Pointers + +::tabs-start + +```python +class Solution: + def deckRevealedIncreasing(self, deck: List[int]) -> List[int]: + n = len(deck) + res = [0] * n + skip = False + deckIndex, i = 0, 0 + + deck.sort() + + while deckIndex < n: + if res[i] == 0: + if not skip: + res[i] = deck[deckIndex] + deckIndex += 1 + skip = not skip + i = (i + 1) % n + + return res +``` + +```java +public class Solution { + public int[] deckRevealedIncreasing(int[] deck) { + int n = deck.length; + int[] res = new int[n]; + Arrays.fill(res, 0); + boolean skip = false; + int deckIndex = 0, i = 0; + + Arrays.sort(deck); + + while (deckIndex < n) { + if (res[i] == 0) { + if (!skip) { + res[i] = deck[deckIndex++]; + } + skip = !skip; + } + i = (i + 1) % n; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector deckRevealedIncreasing(vector& deck) { + int n = deck.size(); + vector res(n, 0); + bool skip = false; + int deckIndex = 0, i = 0; + + sort(deck.begin(), deck.end()); + + while (deckIndex < n) { + if (res[i] == 0) { + if (!skip) { + res[i] = deck[deckIndex++]; + } + skip = !skip; + } + i = (i + 1) % n; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} deck + * @return {number[]} + */ + deckRevealedIncreasing(deck) { + let n = deck.length; + let res = new Array(n).fill(0); + let skip = false; + let deckIndex = 0, i = 0; + + deck.sort((a, b) => a - b); + + while (deckIndex < n) { + if (res[i] === 0) { + if (!skip) { + res[i] = deck[deckIndex++]; + } + skip = !skip; + } + i = (i + 1) % n; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: + * $O(1)$ or $O(n)$ space depending on the sorting algorithm. + * $O(n)$ space for the output array. \ No newline at end of file diff --git a/articles/rotate-list.md b/articles/rotate-list.md new file mode 100644 index 000000000..675821f82 --- /dev/null +++ b/articles/rotate-list.md @@ -0,0 +1,486 @@ +## 1. Convert To Array + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def rotateRight(self, head: Optional[ListNode], k: int) -> Optional[ListNode]: + if not head: + return None + + arr, cur = [], head + while cur: + arr.append(cur.val) + cur = cur.next + + n = len(arr) + k %= n + cur = head + for i in range(n - k, n): + cur.val = arr[i] + cur = cur.next + + for i in range(n - k): + cur.val = arr[i] + cur = cur.next + + return head +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + public ListNode rotateRight(ListNode head, int k) { + if (head == null) return null; + + ArrayList arr = new ArrayList<>(); + ListNode cur = head; + while (cur != null) { + arr.add(cur.val); + cur = cur.next; + } + + int n = arr.size(); + k %= n; + cur = head; + for (int i = n - k; i < n; i++) { + cur.val = arr.get(i); + cur = cur.next; + } + for (int i = 0; i < n - k; i++) { + cur.val = arr.get(i); + cur = cur.next; + } + return head; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode() : val(0), next(nullptr) {} + * ListNode(int x) : val(x), next(nullptr) {} + * ListNode(int x, ListNode *next) : val(x), next(next) {} + * }; + */ +class Solution { +public: + ListNode* rotateRight(ListNode* head, int k) { + if (!head) return nullptr; + + vector arr; + ListNode* cur = head; + while (cur) { + arr.push_back(cur->val); + cur = cur->next; + } + + int n = arr.size(); + k %= n; + cur = head; + for (int i = n - k; i < n; i++) { + cur->val = arr[i]; + cur = cur->next; + } + for (int i = 0; i < n - k; i++) { + cur->val = arr[i]; + cur = cur->next; + } + return head; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} head + * @param {number} k + * @return {ListNode} + */ + rotateRight(head, k) { + if (!head) return null; + + let arr = []; + let cur = head; + while (cur) { + arr.push(cur.val); + cur = cur.next; + } + + let n = arr.length; + k %= n; + cur = head; + for (let i = n - k; i < n; i++) { + cur.val = arr[i]; + cur = cur.next; + } + for (let i = 0; i < n - k; i++) { + cur.val = arr[i]; + cur = cur.next; + } + return head; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 2. Iteration + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def rotateRight(self, head: ListNode, k: int) -> ListNode: + if not head: + return head + + length, tail = 1, head + while tail.next: + tail = tail.next + length += 1 + + k = k % length + if k == 0: + return head + + cur = head + for i in range(length - k - 1): + cur = cur.next + newHead = cur.next + cur.next = None + tail.next = head + + return newHead +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + public ListNode rotateRight(ListNode head, int k) { + if (head == null) { + return head; + } + + int length = 1; + ListNode tail = head; + while (tail.next != null) { + tail = tail.next; + length++; + } + + k = k % length; + if (k == 0) { + return head; + } + + ListNode cur = head; + for (int i = 0; i < length - k - 1; i++) { + cur = cur.next; + } + ListNode newHead = cur.next; + cur.next = null; + tail.next = head; + + return newHead; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode() : val(0), next(nullptr) {} + * ListNode(int x) : val(x), next(nullptr) {} + * ListNode(int x, ListNode *next) : val(x), next(next) {} + * }; + */ +class Solution { +public: + ListNode* rotateRight(ListNode* head, int k) { + if (!head) { + return head; + } + + int length = 1; + ListNode* tail = head; + while (tail->next) { + tail = tail->next; + length++; + } + + k = k % length; + if (k == 0) { + return head; + } + + ListNode* cur = head; + for (int i = 0; i < length - k - 1; i++) { + cur = cur->next; + } + ListNode* newHead = cur->next; + cur->next = nullptr; + tail->next = head; + + return newHead; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} head + * @param {number} k + * @return {ListNode} + */ + rotateRight(head, k) { + if (!head) { + return head; + } + + let length = 1, tail = head; + while (tail.next) { + tail = tail.next; + length++; + } + + k = k % length; + if (k === 0) { + return head; + } + + let cur = head; + for (let i = 0; i < length - k - 1; i++) { + cur = cur.next; + } + let newHead = cur.next; + cur.next = null; + tail.next = head; + + return newHead; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ extra space. + +--- + +## 3. Iteration (Using One Pointer) + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def rotateRight(self, head: ListNode, k: int) -> ListNode: + if not head: + return head + + cur, n = head, 1 + while cur.next: + n += 1 + cur = cur.next + + cur.next = head + k %= n + for i in range(n - k): + cur = cur.next + + head = cur.next + cur.next = None + return head +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + public ListNode rotateRight(ListNode head, int k) { + if (head == null) { + return head; + } + + ListNode cur = head; + int n = 1; + while (cur.next != null) { + n++; + cur = cur.next; + } + + cur.next = head; + k %= n; + for (int i = 0; i < n - k; i++) { + cur = cur.next; + } + + head = cur.next; + cur.next = null; + return head; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode() : val(0), next(nullptr) {} + * ListNode(int x) : val(x), next(nullptr) {} + * ListNode(int x, ListNode *next) : val(x), next(next) {} + * }; + */ +class Solution { +public: + ListNode* rotateRight(ListNode* head, int k) { + if (!head) { + return head; + } + + ListNode* cur = head; + int n = 1; + while (cur->next) { + n++; + cur = cur->next; + } + + cur->next = head; + k %= n; + for (int i = 0; i < n - k; i++) { + cur = cur->next; + } + + head = cur->next; + cur->next = nullptr; + return head; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} head + * @param {number} k + * @return {ListNode} + */ + rotateRight(head, k) { + if (!head) { + return head; + } + + let cur = head, n = 1; + while (cur.next) { + n++; + cur = cur.next; + } + + cur.next = head; + k %= n; + for (let i = 0; i < n - k; i++) { + cur = cur.next; + } + + head = cur.next; + cur.next = null; + return head; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ extra space. \ No newline at end of file diff --git a/articles/score-after-flipping-matrix.md b/articles/score-after-flipping-matrix.md new file mode 100644 index 000000000..83c222266 --- /dev/null +++ b/articles/score-after-flipping-matrix.md @@ -0,0 +1,253 @@ +## 1. Greedy (Overwriting the Input) + +::tabs-start + +```python +class Solution: + def matrixScore(self, grid: List[List[int]]) -> int: + ROWS, COLS = len(grid), len(grid[0]) + + for r in range(ROWS): + if grid[r][0] == 0: + for c in range(COLS): + grid[r][c] ^= 1 + + for c in range(COLS): + one_cnt = sum(grid[r][c] for r in range(ROWS)) + if one_cnt < ROWS - one_cnt: + for r in range(ROWS): + grid[r][c] ^= 1 + + res = 0 + for r in range(ROWS): + for c in range(COLS): + res += grid[r][c] << (COLS - c - 1) + + return res +``` + +```java +public class Solution { + public int matrixScore(int[][] grid) { + int ROWS = grid.length, COLS = grid[0].length; + + for (int r = 0; r < ROWS; r++) { + if (grid[r][0] == 0) { + for (int c = 0; c < COLS; c++) { + grid[r][c] ^= 1; + } + } + } + + for (int c = 0; c < COLS; c++) { + int oneCnt = 0; + for (int r = 0; r < ROWS; r++) { + oneCnt += grid[r][c]; + } + if (oneCnt < ROWS - oneCnt) { + for (int r = 0; r < ROWS; r++) { + grid[r][c] ^= 1; + } + } + } + + int res = 0; + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + res += grid[r][c] << (COLS - c - 1); + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int matrixScore(vector>& grid) { + int ROWS = grid.size(), COLS = grid[0].size(); + + for (int r = 0; r < ROWS; r++) { + if (grid[r][0] == 0) { + for (int c = 0; c < COLS; c++) { + grid[r][c] ^= 1; + } + } + } + + for (int c = 0; c < COLS; c++) { + int oneCnt = 0; + for (int r = 0; r < ROWS; r++) { + oneCnt += grid[r][c]; + } + if (oneCnt < ROWS - oneCnt) { + for (int r = 0; r < ROWS; r++) { + grid[r][c] ^= 1; + } + } + } + + int res = 0; + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + res += grid[r][c] << (COLS - c - 1); + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + matrixScore(grid) { + let ROWS = grid.length, COLS = grid[0].length; + + for (let r = 0; r < ROWS; r++) { + if (grid[r][0] === 0) { + for (let c = 0; c < COLS; c++) { + grid[r][c] ^= 1; + } + } + } + + for (let c = 0; c < COLS; c++) { + let oneCnt = 0; + for (let r = 0; r < ROWS; r++) { + oneCnt += grid[r][c]; + } + if (oneCnt < ROWS - oneCnt) { + for (let r = 0; r < ROWS; r++) { + grid[r][c] ^= 1; + } + } + } + + let res = 0; + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + res += grid[r][c] << (COLS - c - 1); + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * n)$ +* Space complexity: $O(1)$ extra space. + +> Where $m$ is the number of rows and $n$ is the number of columns. + +--- + +## 2. Greedy (Optimal) + +::tabs-start + +```python +class Solution: + def matrixScore(self, grid: List[List[int]]) -> int: + ROWS, COLS = len(grid), len(grid[0]) + res = ROWS * (1 << (COLS - 1)) + + for c in range(1, COLS): + cnt = 0 + for r in range(ROWS): + if grid[r][c] != grid[r][0]: + cnt += 1 + + cnt = max(cnt, ROWS - cnt) + res += cnt * (1 << (COLS - c - 1)) + + return res +``` + +```java +public class Solution { + public int matrixScore(int[][] grid) { + int ROWS = grid.length, COLS = grid[0].length; + int res = ROWS * (1 << (COLS - 1)); + + for (int c = 1; c < COLS; c++) { + int cnt = 0; + for (int r = 0; r < ROWS; r++) { + if (grid[r][c] != grid[r][0]) { + cnt++; + } + } + cnt = Math.max(cnt, ROWS - cnt); + res += cnt * (1 << (COLS - c - 1)); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int matrixScore(vector>& grid) { + int ROWS = grid.size(), COLS = grid[0].size(); + int res = ROWS * (1 << (COLS - 1)); + + for (int c = 1; c < COLS; c++) { + int cnt = 0; + for (int r = 0; r < ROWS; r++) { + if (grid[r][c] != grid[r][0]) { + cnt++; + } + } + cnt = max(cnt, ROWS - cnt); + res += cnt * (1 << (COLS - c - 1)); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + matrixScore(grid) { + const ROWS = grid.length, COLS = grid[0].length; + let res = ROWS * (1 << (COLS - 1)); + + for (let c = 1; c < COLS; c++) { + let cnt = 0; + for (let r = 0; r < ROWS; r++) { + if (grid[r][c] !== grid[r][0]) { + cnt++; + } + } + cnt = Math.max(cnt, ROWS - cnt); + res += cnt * (1 << (COLS - c - 1)); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * n)$ +* Space complexity: $O(1)$ extra space. + +> Where $m$ is the number of rows and $n$ is the number of columns. \ No newline at end of file diff --git a/articles/splitting-a-string-into-descending-consecutive-values.md b/articles/splitting-a-string-into-descending-consecutive-values.md new file mode 100644 index 000000000..b736eda11 --- /dev/null +++ b/articles/splitting-a-string-into-descending-consecutive-values.md @@ -0,0 +1,570 @@ +## 1. Backtracking + +::tabs-start + +```python +class Solution: + def splitString(self, s: str) -> bool: + n = len(s) + + def isValid(splits): + for i in range(1, len(splits)): + if splits[i] != splits[i - 1] - 1: + return False + return len(splits) > 1 + + def dfs(i, splits): + if i == n: + return isValid(splits) + num = 0 + for j in range(i, n): + num = num * 10 + int(s[j]) + splits.append(num) + if dfs(j + 1, splits): + return True + splits.pop() + return False + + return dfs(0, []) +``` + +```java +public class Solution { + public boolean splitString(String s) { + return dfs(s, 0, new ArrayList<>()); + } + + private boolean isValid(List splits) { + for (int i = 1; i < splits.size(); i++) { + if (splits.get(i) != splits.get(i - 1) - 1) { + return false; + } + } + return splits.size() > 1; + } + + private boolean dfs(String s, int i, List splits) { + if (i == s.length()) { + return isValid(splits); + } + long num = 0; + for (int j = i; j < s.length(); j++) { + num = num * 10 + (s.charAt(j) - '0'); + splits.add(num); + if (dfs(s, j + 1, splits)) { + return true; + } + splits.remove(splits.size() - 1); + } + return false; + } +} +``` + +```cpp +class Solution { +public: + bool splitString(string s) { + vector splits; + return dfs(s, 0, splits); + } + +private: + bool isValid(vector& splits) { + for (int i = 1; i < splits.size(); i++) { + if (splits[i] != splits[i - 1] - 1) { + return false; + } + } + return splits.size() > 1; + } + + bool dfs(string& s, int i, vector& splits) { + if (i == s.size()) { + return isValid(splits); + } + unsigned long long num = 0; + for (int j = i; j < s.size(); j++) { + num = num * 10 + (s[j] - '0'); + splits.push_back(num); + if (dfs(s, j + 1, splits)) { + return true; + } + splits.pop_back(); + } + return false; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {boolean} + */ + splitString(s) { + const n = s.length; + + const isValid = (splits) => { + for (let i = 1; i < splits.length; i++) { + if (splits[i] !== splits[i - 1] - 1) { + return false; + } + } + return splits.length > 1; + }; + + const dfs = (i, splits) => { + if (i === n) { + return isValid(splits); + } + let num = 0; + for (let j = i; j < n; j++) { + num = num * 10 + Number(s[j]); + splits.push(num); + if (dfs(j + 1, splits)) { + return true; + } + splits.pop(); + } + return false; + }; + + return dfs(0, []); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ n)$ +* Space complexity: $O(n)$ + +--- + +## 2. Recursion - I + +::tabs-start + +```python +class Solution: + def splitString(self, s: str) -> bool: + def dfs(index, prev): + if index == len(s): + return True + num = 0 + for j in range(index, len(s)): + num = num * 10 + int(s[j]) + if num + 1 == prev and dfs(j + 1, num): + return True + return False + + val = 0 + for i in range(len(s) - 1): + val = val * 10 + int(s[i]) + if dfs(i + 1, val): + return True + + return False +``` + +```java +public class Solution { + public boolean splitString(String s) { + int n = s.length(); + long val = 0; + for (int i = 0; i < n - 1; i++) { + val = val * 10 + (s.charAt(i) - '0'); + if (dfs(s, i + 1, val)) { + return true; + } + } + return false; + } + + private boolean dfs(String s, int index, long prev) { + if (index == s.length()) { + return true; + } + long num = 0; + for (int j = index; j < s.length(); j++) { + num = num * 10 + (s.charAt(j) - '0'); + if (num + 1 == prev && dfs(s, j + 1, num)) { + return true; + } + } + return false; + } +} +``` + +```cpp +class Solution { +public: + bool splitString(string s) { + int n = s.size(); + unsigned long long val = 0; + for (int i = 0; i < n - 1; i++) { + val = val * 10 + (s[i] - '0'); + if (dfs(s, i + 1, val)) { + return true; + } + } + return false; + } + +private: + bool dfs(string& s, int index, long long prev) { + if (index == s.size()) { + return true; + } + unsigned long long num = 0; + for (int j = index; j < s.size(); j++) { + num = num * 10 + (s[j] - '0'); + if (num + 1 == prev && dfs(s, j + 1, num)) { + return true; + } + } + return false; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {boolean} + */ + splitString(s) { + const n = s.length; + + const dfs = (index, prev) => { + if (index === n) { + return true; + } + let num = 0; + for (let j = index; j < n; j++) { + num = num * 10 + Number(s[j]); + if (num + 1 === prev && dfs(j + 1, num)) { + return true; + } + } + return false; + }; + + let val = 0; + for (let i = 0; i < n - 1; i++) { + val = val * 10 + Number(s[i]); + if (dfs(i + 1, val)) { + return true; + } + } + + return false; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n)$ for recursion stack. + +--- + +## 3. Recursion - II + +::tabs-start + +```python +class Solution: + def splitString(self, s: str) -> bool: + def dfs(index, prev): + if index == len(s): + return True + num = 0 + for j in range(index, len(s)): + num = num * 10 + int(s[j]) + if num + 1 == prev and dfs(j + 1, num): + return True + if num >= prev: + break + return False + + val = 0 + for i in range(len(s) - 1): + val = val * 10 + int(s[i]) + if dfs(i + 1, val): + return True + + return False +``` + +```java +public class Solution { + public boolean splitString(String s) { + int n = s.length(); + long val = 0; + for (int i = 0; i < n - 1; i++) { + val = val * 10 + (s.charAt(i) - '0'); + if (dfs(s, i + 1, val)) { + return true; + } + } + return false; + } + + private boolean dfs(String s, int index, long prev) { + if (index == s.length()) { + return true; + } + long num = 0; + for (int j = index; j < s.length(); j++) { + num = num * 10 + (s.charAt(j) - '0'); + if (num + 1 == prev && dfs(s, j + 1, num)) { + return true; + } + if (num >= prev) { + break; + } + } + return false; + } +} +``` + +```cpp +class Solution { +public: + bool splitString(string s) { + int n = s.size(); + unsigned long long val = 0; + for (int i = 0; i < n - 1; i++) { + val = val * 10 + (s[i] - '0'); + if (dfs(s, i + 1, val)) { + return true; + } + } + return false; + } + +private: + bool dfs(string& s, int index, long long prev) { + if (index == s.size()) { + return true; + } + unsigned long long num = 0; + for (int j = index; j < s.size(); j++) { + num = num * 10 + (s[j] - '0'); + if (num + 1 == prev && dfs(s, j + 1, num)) { + return true; + } + if (num >= prev) { + break; + } + } + return false; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {boolean} + */ + splitString(s) { + const n = s.length; + + const dfs = (index, prev) => { + if (index === n) { + return true; + } + let num = 0; + for (let j = index; j < n; j++) { + num = num * 10 + Number(s[j]); + if (num + 1 === prev && dfs(j + 1, num)) { + return true; + } + if (num >= prev) { + break; + } + } + return false; + }; + + let val = 0; + for (let i = 0; i < n - 1; i++) { + val = val * 10 + Number(s[i]); + if (dfs(i + 1, val)) { + return true; + } + } + + return false; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n)$ for recursion stack. + +--- + +## 4. Stack + +::tabs-start + +```python +class Solution: + def splitString(self, s: str) -> bool: + n = len(s) + stack = [] + val = 0 + + for i in range(n - 1): + val = val * 10 + int(s[i]) + stack.append((i + 1, val)) + + while stack: + index, prev = stack.pop() + num = 0 + for j in range(index, n): + num = num * 10 + int(s[j]) + if num + 1 == prev: + if j + 1 == n: + return True + stack.append((j + 1, num)) + elif num >= prev: + break + + return False +``` + +```java +public class Solution { + public boolean splitString(String s) { + int n = s.length(); + Stack stack = new Stack<>(); + long val = 0; + + for (int i = 0; i < n - 1; i++) { + val = val * 10 + (s.charAt(i) - '0'); + stack.push(new long[]{i + 1, val}); + + while (!stack.isEmpty()) { + long[] top = stack.pop(); + int index = (int) top[0]; + long prev = top[1]; + long num = 0; + + for (int j = index; j < n; j++) { + num = num * 10 + (s.charAt(j) - '0'); + if (num + 1 == prev) { + if (j + 1 == n) { + return true; + } + stack.push(new long[]{j + 1, num}); + } else if (num >= prev) { + break; + } + } + } + } + + return false; + } +} +``` + +```cpp +class Solution { +public: + bool splitString(string s) { + int n = s.size(); + stack> stack; + unsigned long long val = 0; + + for (int i = 0; i < n - 1; i++) { + val = val * 10 + (s[i] - '0'); + stack.push({i + 1, val}); + + while (!stack.empty()) { + auto [index, prev] = stack.top(); + stack.pop(); + unsigned long long num = 0; + + for (int j = index; j < n; j++) { + num = num * 10 + (s[j] - '0'); + if (num + 1 == prev) { + if (j + 1 == n) { + return true; + } + stack.push({j + 1, num}); + } else if (num >= prev) { + break; + } + } + } + } + + return false; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {boolean} + */ + splitString(s) { + const n = s.length; + let stack = []; + let val = 0; + + for (let i = 0; i < n - 1; i++) { + val = val * 10 + Number(s[i]); + stack.push([i + 1, val]); + + while (stack.length) { + let [index, prev] = stack.pop(); + let num = 0; + + for (let j = index; j < n; j++) { + num = num * 10 + Number(s[j]); + if (num + 1 === prev) { + if (j + 1 === n) { + return true; + } + stack.push([j + 1, num]); + } else if (num >= prev) { + break; + } + } + } + } + + return false; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n)$ \ No newline at end of file diff --git a/articles/the-number-of-beautiful-subsets.md b/articles/the-number-of-beautiful-subsets.md new file mode 100644 index 000000000..1ed55b435 --- /dev/null +++ b/articles/the-number-of-beautiful-subsets.md @@ -0,0 +1,739 @@ +## 1. Backtracking + +::tabs-start + +```python +class Solution: + def beautifulSubsets(self, nums: List[int], k: int) -> int: + def helper(i, count): + if i == len(nums): + return 1 + + res = helper(i + 1, count) # Skip nums[i] + if not count[nums[i] + k] and not count[nums[i] - k]: + count[nums[i]] += 1 + res += helper(i + 1, count) + count[nums[i]] -= 1 + + return res + + return helper(0, defaultdict(int)) - 1 +``` + +```java +public class Solution { + public int beautifulSubsets(int[] nums, int k) { + return helper(0, new HashMap<>(), nums, k) - 1; + } + + private int helper(int i, Map count, int[] nums, int k) { + if (i == nums.length) { + return 1; + } + + int res = helper(i + 1, count, nums, k); // Skip nums[i] + + if (!count.containsKey(nums[i] + k) && !count.containsKey(nums[i] - k)) { + count.put(nums[i], count.getOrDefault(nums[i], 0) + 1); + res += helper(i + 1, count, nums, k); + count.put(nums[i], count.get(nums[i]) - 1); + if (count.get(nums[i]) == 0) { + count.remove(nums[i]); + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int beautifulSubsets(vector& nums, int k) { + unordered_map count; + return helper(0, count, nums, k) - 1; + } + +private: + int helper(int i, unordered_map& count, vector& nums, int k) { + if (i == nums.size()) { + return 1; + } + + int res = helper(i + 1, count, nums, k); // Skip nums[i] + if (!count[nums[i] + k] && !count[nums[i] - k]) { + count[nums[i]]++; + res += helper(i + 1, count, nums, k); + count[nums[i]]--; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + beautifulSubsets(nums, k) { + const helper = (i, count) => { + if (i === nums.length) { + return 1; + } + + let res = helper(i + 1, count); // Skip nums[i] + + if (!count.has(nums[i] + k) && !count.has(nums[i] - k)) { + count.set(nums[i], (count.get(nums[i]) || 0) + 1); + res += helper(i + 1, count); + count.set(nums[i], count.get(nums[i]) - 1); + if (count.get(nums[i]) === 0) { + count.delete(nums[i]); + } + } + + return res; + }; + + return helper(0, new Map()) - 1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(2 ^ n)$ +* Space complexity: $O(n)$ + +--- + +## 2. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def beautifulSubsets(self, nums: List[int], k: int) -> int: + cnt = Counter(nums) + groups = [] # List of dicts + cache = {} + + def helper(n, g): + if n not in g: + return 1 + if n in cache: + return cache[n] + + skip = helper(n + k, g) + include = (2**g[n] - 1) * helper(n + 2 * k, g) + cache[n] = skip + include + return skip + include + + visit = set() + for n in cnt.keys(): + if n in visit: + continue + g = {} + while n - k in cnt: + n -= k + while n in cnt: + g[n] = cnt[n] + visit.add(n) + n += k + groups.append(g) + + res = 1 + for g in groups: + n = min(g.keys()) + res *= helper(n, g) + + return res - 1 +``` + +```java +public class Solution { + private Map cache; + private Map cnt; + private Set visit; + + public int beautifulSubsets(int[] nums, int k) { + List> groups = new ArrayList<>(); + this.cache = new HashMap<>(); + this.cnt = new HashMap<>(); + this.visit = new HashSet<>(); + + for (int num : nums) { + cnt.put(num, cnt.getOrDefault(num, 0) + 1); + } + + for (int n : cnt.keySet()) { + if (visit.contains(n)) { + continue; + } + Map g = new HashMap<>(); + while (cnt.containsKey(n - k)) { + n -= k; + } + while (cnt.containsKey(n)) { + g.put(n, cnt.get(n)); + visit.add(n); + n += k; + } + groups.add(g); + } + + int res = 1; + for (Map g : groups) { + int n = Collections.min(g.keySet()); + res *= helper(n, g, k); + } + + return res - 1; + } + + private int helper(int n, Map g, int k) { + if (!g.containsKey(n)) { + return 1; + } + if (cache.containsKey(n)) { + return cache.get(n); + } + + int skip = helper(n + k, g, k); + int include = (int) ((Math.pow(2, g.get(n)) - 1) * helper(n + 2 * k, g, k)); + int result = skip + include; + cache.put(n, result); + return result; + } +} +``` + +```cpp +class Solution { +public: + int beautifulSubsets(vector& nums, int k) { + vector> groups; + cache.clear(); + cnt.clear(); + visit.clear(); + + for (int& num : nums) { + cnt[num]++; + } + + for (auto it = cnt.begin(); it != cnt.end(); ++it) { + int n = it->first; + if (visit.count(n)) { + continue; + } + unordered_map g; + while (cnt.count(n - k)) { + n -= k; + } + while (cnt.count(n)) { + g[n] = cnt[n]; + visit.insert(n); + n += k; + } + groups.push_back(g); + } + + int res = 1; + for (auto& g : groups) { + int n = min_element(g.begin(), g.end())->first; + res *= helper(n, g, k); + } + return res - 1; + } + +private: + unordered_map cache; + unordered_map cnt; + unordered_set visit; + + int helper(int n, unordered_map& g, int k) { + if (!g.count(n)) { + return 1; + } + if (cache.count(n)) { + return cache[n]; + } + + int skip = helper(n + k, g, k); + int include = (pow(2, g[n]) - 1) * helper(n + 2 * k, g, k); + return cache[n] = skip + include; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + beautifulSubsets(nums, k) { + let cnt = new Map(); + for (const num of nums) { + cnt.set(num, (cnt.get(num) || 0) + 1); + } + + let groups = []; + let cache = new Map(); + let visit = new Set(); + + for (let n of cnt.keys()) { + if (visit.has(n)) { + continue; + } + let g = new Map(); + while (cnt.has(n - k)) { + n -= k; + } + while (cnt.has(n)) { + g.set(n, cnt.get(n)); + visit.add(n); + n += k; + } + groups.push(g); + } + + const helper = (n, g) => { + if (!g.has(n)) { + return 1; + } + if (cache.has(n)) { + return cache.get(n); + } + + let skip = helper(n + k, g); + let include = (2 ** g.get(n) - 1) * helper(n + 2 * k, g); + let result = skip + include; + cache.set(n, result); + return result; + }; + + let res = 1; + for (const g of groups) { + let n = Math.min(...g.keys()); + res *= helper(n, g); + } + return res - 1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 3. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def beautifulSubsets(self, nums: List[int], k: int) -> int: + cnt = Counter(nums) + groups = [] # List of dicts + + visit = set() + for n in cnt.keys(): + if n in visit: + continue + g = {} + while n - k in cnt: + n -= k + while n in cnt: + g[n] = cnt[n] + visit.add(n) + n += k + groups.append(g) + + res = 1 + for g in groups: + dp = {} + prev = None + + for num in sorted(g): + count = g[num] + if prev is None or prev + k != num: + dp[num] = (dp.get(prev, 1) * (1 + (2 ** count - 1))) + else: + dp[num] = dp[prev] + (2 ** count - 1) * dp.get(prev - k, 1) + prev = num + + res *= dp[prev] + + return res - 1 +``` + +```java +class Solution { + public int beautifulSubsets(int[] nums, int k) { + Map cnt = new HashMap<>(); + for (int num : nums) { + cnt.put(num, cnt.getOrDefault(num, 0) + 1); + } + + List> groups = new ArrayList<>(); + Set visit = new HashSet<>(); + + for (int n : cnt.keySet()) { + if (visit.contains(n)) { + continue; + } + Map g = new HashMap<>(); + while (cnt.containsKey(n - k)) { + n -= k; + } + while (cnt.containsKey(n)) { + g.put(n, cnt.get(n)); + visit.add(n); + n += k; + } + groups.add(g); + } + + int res = 1; + for (Map g : groups) { + Map dp = new HashMap<>(); + Integer prev = null; + + List arr = new ArrayList<>(g.keySet()); + Collections.sort(arr); + for (int num : arr) { + int count = g.get(num); + if (prev == null || prev + k != num) { + dp.put(num, dp.getOrDefault(prev, 1) * (1 + (int) Math.pow(2, count) - 1)); + } else { + dp.put(num, dp.get(prev) + + ((int) Math.pow(2, count) - 1) * dp.getOrDefault(prev - k, 1)); + } + prev = num; + } + + res *= dp.get(prev); + } + + return res - 1; + } +} +``` + +```cpp +class Solution { +public: + int beautifulSubsets(vector& nums, int k) { + unordered_map cnt; + for (int num : nums) { + cnt[num]++; + } + + vector> groups; + unordered_set visit; + + for (auto it = cnt.begin(); it != cnt.end(); ++it) { + int n = it->first; + if (visit.count(n)) { + continue; + } + unordered_map g; + while (cnt.count(n - k)) { + n -= k; + } + while (cnt.count(n)) { + g[n] = cnt[n]; + visit.insert(n); + n += k; + } + groups.push_back(g); + } + + int res = 1; + for (auto& g : groups) { + unordered_map dp; + int prev = -1; + + vector keys; + for (auto& [num, _] : g) { + keys.push_back(num); + } + sort(keys.begin(), keys.end()); + + for (int num : keys) { + int count = g[num]; + if (prev == -1 || prev + k != num) { + dp[num] = dp.count(prev) ? dp[prev] * (1 + (1 << count) - 1) : + (1 + (1 << count) - 1); + } else { + dp[num] = dp[prev] + ((1 << count) - 1) * + (dp.count(prev - k) ? dp[prev - k] : 1); + } + prev = num; + } + + res *= dp[prev]; + } + + return res - 1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + beautifulSubsets(nums, k) { + let cnt = new Map(); + for (const num of nums) { + cnt.set(num, (cnt.get(num) || 0) + 1); + } + + let groups = []; + let visit = new Set(); + + for (const n of cnt.keys()) { + if (visit.has(n)) { + continue; + } + let g = new Map(); + let num = n; + while (cnt.has(num - k)) { + num -= k; + } + while (cnt.has(num)) { + g.set(num, cnt.get(num)); + visit.add(num); + num += k; + } + groups.push(g); + } + + let res = 1; + for (const g of groups) { + let dp = new Map(); + let prev = null; + + for (const num of g.keys()) { + let count = g.get(num); + if (prev === null || prev + k !== num) { + dp.set(num, (dp.get(prev) || 1) * (1 + (2 ** count - 1))); + } else { + dp.set(num, dp.get(prev) + (2 ** count - 1) * (dp.get(prev - k) || 1)); + } + prev = num; + } + + res *= dp.get(prev); + } + + return res - 1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(n)$ + +--- + +## 4. Dynamic Programming (Space Optimized) + +::tabs-start + +```python +class Solution: + def beautifulSubsets(self, nums: List[int], k: int) -> int: + cnt = Counter(nums) + groups = defaultdict(dict) + + # Group numbers based on their remainder with k + for num in nums: + groups[num % k][num] = cnt[num] + + res = 1 + for g in groups.values(): + prev = 0 + dp, ndp = 0, 1 + + for num in sorted(g.keys()): + count = g[num] + have = (1 << count) - 1 + tmp = ndp + ndp += dp + + if prev == 0 or prev + k != num: + dp = have * (tmp + dp) + else: + dp = tmp * have + + prev = num + + res *= (dp + ndp) + + return res - 1 +``` + +```java +public class Solution { + public int beautifulSubsets(int[] nums, int k) { + Map> groups = new HashMap<>(); + Map cnt = new HashMap<>(); + for (int num : nums) { + cnt.put(num, cnt.getOrDefault(num, 0) + 1); + } + + // Group numbers based on remainder with k + for (int num : nums) { + groups.putIfAbsent(num % k, new HashMap<>()); + groups.get(num % k).put(num, cnt.get(num)); + } + + int res = 1; + for (Map g : groups.values()) { + int prev = 0, dp = 0, ndp = 1; + List sortedKeys = new ArrayList<>(g.keySet()); + Collections.sort(sortedKeys); + + for (int num : sortedKeys) { + int count = g.get(num); + int have = (1 << count) - 1; + int tmp = ndp; + ndp += dp; + + if (prev == 0 || prev + k != num) { + dp = have * (tmp + dp); + } else { + dp = tmp * have; + } + + prev = num; + } + + res *= (dp + ndp); + } + + return res - 1; + } +} +``` + +```cpp +class Solution { +public: + int beautifulSubsets(vector& nums, int k) { + unordered_map> groups; + unordered_map cnt; + for (int& num : nums) { + cnt[num]++; + } + + // Group numbers based on remainder with k + for (int num : nums) { + groups[num % k][num] = cnt[num]; + } + + int res = 1; + for (auto& [rem, g] : groups) { + int prev = 0, dp = 0, ndp = 1; + + for (auto& [num, count] : g) { + int have = (1 << count) - 1; + int tmp = ndp; + ndp += dp; + + if (prev == 0 || prev + k != num) { + dp = have * (tmp + dp); + } else { + dp = tmp * have; + } + + prev = num; + } + + res *= (dp + ndp); + } + + return res - 1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + beautifulSubsets(nums, k) { + let groups = new Map(); + let cnt = new Map(); + for (const num of nums) { + cnt.set(num, (cnt.get(num) || 0) + 1); + } + + // Group numbers based on remainder with k + for (const num of nums) { + if (!groups.has(num % k)) { + groups.set(num % k, new Map()); + } + groups.get(num % k).set(num, cnt.get(num)); + } + + let res = 1; + for (const g of groups.values()) { + let prev = 0, dp = 0, ndp = 1; + let sortedKeys = Array.from(g.keys()).sort((a, b) => a - b); + + for (const num of sortedKeys) { + let count = g.get(num); + let have = (1 << count) - 1; + let tmp = ndp; + ndp += dp; + + if (prev === 0 || prev + k !== num) { + dp = have * (tmp + dp); + } else { + dp = tmp * have; + } + + prev = num; + } + + res *= (dp + ndp); + } + + return res - 1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(n)$ \ No newline at end of file diff --git a/articles/two-city-scheduling.md b/articles/two-city-scheduling.md new file mode 100644 index 000000000..61f80767c --- /dev/null +++ b/articles/two-city-scheduling.md @@ -0,0 +1,683 @@ +## 1. Recursion + +::tabs-start + +```python +class Solution: + def twoCitySchedCost(self, costs: List[List[int]]) -> int: + n = len(costs) // 2 + + def dfs(i, aCount, bCount): + if i == len(costs): + return 0 + + res = float("inf") + if aCount > 0: + res = costs[i][0] + dfs(i + 1, aCount - 1, bCount) + + if bCount > 0: + res = min(res, costs[i][1] + dfs(i + 1, aCount, bCount - 1)) + return res + + return dfs(0, n, n) +``` + +```java +public class Solution { + public int twoCitySchedCost(int[][] costs) { + int n = costs.length / 2; + return dfs(costs, 0, n, n); + } + + private int dfs(int[][] costs, int i, int aCount, int bCount) { + if (i == costs.length) { + return 0; + } + + int res = Integer.MAX_VALUE; + if (aCount > 0) { + res = costs[i][0] + dfs(costs, i + 1, aCount - 1, bCount); + } + + if (bCount > 0) { + res = Math.min(res, costs[i][1] + dfs(costs, i + 1, aCount, bCount - 1)); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int twoCitySchedCost(vector>& costs) { + int n = costs.size() / 2; + return dfs(costs, 0, n, n); + } + +private: + int dfs(vector>& costs, int i, int aCount, int bCount) { + if (i == costs.size()) { + return 0; + } + + int res = INT_MAX; + if (aCount > 0) { + res = costs[i][0] + dfs(costs, i + 1, aCount - 1, bCount); + } + + if (bCount > 0) { + res = min(res, costs[i][1] + dfs(costs, i + 1, aCount, bCount - 1)); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} costs + * @return {number} + */ + twoCitySchedCost(costs) { + let n = costs.length / 2; + + const dfs = (i, aCount, bCount) => { + if (i === costs.length) { + return 0; + } + + let res = Infinity; + if (aCount > 0) { + res = costs[i][0] + dfs(i + 1, aCount - 1, bCount); + } + + if (bCount > 0) { + res = Math.min(res, costs[i][1] + dfs(i + 1, aCount, bCount - 1)); + } + + return res; + }; + + return dfs(0, n, n); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(2 ^ N)$ +* Space complexity: $O(N)$ for recursion stack. + +> Where $N$ is the size of the array $costs$. + +--- + +## 2. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def twoCitySchedCost(self, costs: List[List[int]]) -> int: + n = len(costs) // 2 + dp = [[-1] * (n + 1) for _ in range(n + 1)] + + def dfs(i, aCount, bCount): + if i == len(costs): + return 0 + if dp[aCount][bCount] != -1: + return dp[aCount][bCount] + + res = float("inf") + if aCount > 0: + res = costs[i][0] + dfs(i + 1, aCount - 1, bCount) + if bCount > 0: + res = min(res, costs[i][1] + dfs(i + 1, aCount, bCount - 1)) + + dp[aCount][bCount] = res + return res + + return dfs(0, n, n) +``` + +```java +public class Solution { + private int[][] dp; + + public int twoCitySchedCost(int[][] costs) { + int n = costs.length / 2; + dp = new int[n + 1][n + 1]; + for (int[] row : dp) { + Arrays.fill(row, -1); + } + return dfs(costs, 0, n, n); + } + + private int dfs(int[][] costs, int i, int aCount, int bCount) { + if (i == costs.length) { + return 0; + } + if (dp[aCount][bCount] != -1) { + return dp[aCount][bCount]; + } + + int res = Integer.MAX_VALUE; + if (aCount > 0) { + res = costs[i][0] + dfs(costs, i + 1, aCount - 1, bCount); + } + if (bCount > 0) { + res = Math.min(res, costs[i][1] + dfs(costs, i + 1, aCount, bCount - 1)); + } + + dp[aCount][bCount] = res; + return res; + } +} +``` + +```cpp +class Solution { +public: + vector> dp; + + int twoCitySchedCost(vector>& costs) { + int n = costs.size() / 2; + dp = vector>(n + 1, vector(n + 1, -1)); + return dfs(costs, 0, n, n); + } + +private: + int dfs(vector>& costs, int i, int aCount, int bCount) { + if (i == costs.size()) { + return 0; + } + if (dp[aCount][bCount] != -1) { + return dp[aCount][bCount]; + } + + int res = INT_MAX; + if (aCount > 0) { + res = costs[i][0] + dfs(costs, i + 1, aCount - 1, bCount); + } + if (bCount > 0) { + res = min(res, costs[i][1] + dfs(costs, i + 1, aCount, bCount - 1)); + } + + dp[aCount][bCount] = res; + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} costs + * @return {number} + */ + twoCitySchedCost(costs) { + let n = costs.length / 2; + let dp = Array.from({ length: n + 1 }, () => new Array(n + 1).fill(-1)); + + const dfs = (i, aCount, bCount) => { + if (i === costs.length) { + return 0; + } + if (dp[aCount][bCount] !== -1) { + return dp[aCount][bCount]; + } + + let res = Infinity; + if (aCount > 0) { + res = costs[i][0] + dfs(i + 1, aCount - 1, bCount); + } + if (bCount > 0) { + res = Math.min(res, costs[i][1] + dfs(i + 1, aCount, bCount - 1)); + } + + dp[aCount][bCount] = res; + return res; + }; + + return dfs(0, n, n); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n ^ 2)$ + +> Where $n$ is the half of the size of the array $costs$. + +--- + +## 3. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def twoCitySchedCost(self, costs: List[List[int]]) -> int: + n = len(costs) // 2 + dp = [[0] * (n + 1) for _ in range(n + 1)] + + for aCount in range(n + 1): + for bCount in range(n + 1): + i = aCount + bCount + if i == 0: + continue + + dp[aCount][bCount] = float("inf") + if aCount > 0: + dp[aCount][bCount] = min(dp[aCount][bCount], dp[aCount - 1][bCount] + costs[i - 1][0]) + if bCount > 0: + dp[aCount][bCount] = min(dp[aCount][bCount], dp[aCount][bCount - 1] + costs[i - 1][1]) + + return dp[n][n] +``` + +```java +public class Solution { + public int twoCitySchedCost(int[][] costs) { + int n = costs.length / 2; + int[][] dp = new int[n + 1][n + 1]; + + for (int aCount = 0; aCount <= n; aCount++) { + for (int bCount = 0; bCount <= n; bCount++) { + int i = aCount + bCount; + if (i == 0) continue; + + dp[aCount][bCount] = Integer.MAX_VALUE; + if (aCount > 0) { + dp[aCount][bCount] = Math.min(dp[aCount][bCount], dp[aCount - 1][bCount] + costs[i - 1][0]); + } + if (bCount > 0) { + dp[aCount][bCount] = Math.min(dp[aCount][bCount], dp[aCount][bCount - 1] + costs[i - 1][1]); + } + } + } + + return dp[n][n]; + } +} +``` + +```cpp +class Solution { +public: + int twoCitySchedCost(vector>& costs) { + int n = costs.size() / 2; + vector> dp(n + 1, vector(n + 1)); + + for (int aCount = 0; aCount <= n; aCount++) { + for (int bCount = 0; bCount <= n; bCount++) { + int i = aCount + bCount; + if (i == 0) continue; + + dp[aCount][bCount] = INT_MAX; + if (aCount > 0) { + dp[aCount][bCount] = min(dp[aCount][bCount], dp[aCount - 1][bCount] + costs[i - 1][0]); + } + if (bCount > 0) { + dp[aCount][bCount] = min(dp[aCount][bCount], dp[aCount][bCount - 1] + costs[i - 1][1]); + } + } + } + + return dp[n][n]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} costs + * @return {number} + */ + twoCitySchedCost(costs) { + let n = costs.length / 2; + let dp = Array.from({ length: n + 1 }, () => new Array(n + 1).fill(0)); + + for (let aCount = 0; aCount <= n; aCount++) { + for (let bCount = 0; bCount <= n; bCount++) { + let i = aCount + bCount; + if (i === 0) continue; + + dp[aCount][bCount] = Infinity; + if (aCount > 0) { + dp[aCount][bCount] = Math.min(dp[aCount][bCount], dp[aCount - 1][bCount] + costs[i - 1][0]); + } + if (bCount > 0) { + dp[aCount][bCount] = Math.min(dp[aCount][bCount], dp[aCount][bCount - 1] + costs[i - 1][1]); + } + } + } + + return dp[n][n]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n ^ 2)$ + +> Where $n$ is the half of the size of the array $costs$. + +--- + +## 4. Dynamic Programming (Space Optimized) + +::tabs-start + +```python +class Solution: + def twoCitySchedCost(self, costs: List[List[int]]) -> int: + n = len(costs) // 2 + dp = [0] * (n + 1) + + for aCount in range(n + 1): + for bCount in range(n + 1): + i = aCount + bCount + if i == 0: + continue + + tmp = dp[bCount] + dp[bCount] = float("inf") + if aCount > 0: + dp[bCount] = min(dp[bCount], tmp + costs[i - 1][0]) + if bCount > 0: + dp[bCount] = min(dp[bCount], dp[bCount - 1] + costs[i - 1][1]) + + return dp[n] +``` + +```java +public class Solution { + public int twoCitySchedCost(int[][] costs) { + int n = costs.length / 2; + int[] dp = new int[n + 1]; + + for (int aCount = 0; aCount <= n; aCount++) { + for (int bCount = 0; bCount <= n; bCount++) { + int i = aCount + bCount; + if (i == 0) continue; + + int tmp = dp[bCount]; + dp[bCount] = Integer.MAX_VALUE; + if (aCount > 0) { + dp[bCount] = Math.min(dp[bCount], tmp + costs[i - 1][0]); + } + if (bCount > 0) { + dp[bCount] = Math.min(dp[bCount], dp[bCount - 1] + costs[i - 1][1]); + } + } + } + + return dp[n]; + } +} +``` + +```cpp +class Solution { +public: + int twoCitySchedCost(vector>& costs) { + int n = costs.size() / 2; + vector dp(n + 1, 0); + + for (int aCount = 0; aCount <= n; aCount++) { + for (int bCount = 0; bCount <= n; bCount++) { + int i = aCount + bCount; + if (i == 0) continue; + + int tmp = dp[bCount]; + dp[bCount] = INT_MAX; + if (aCount > 0) { + dp[bCount] = min(dp[bCount], tmp + costs[i - 1][0]); + } + if (bCount > 0) { + dp[bCount] = min(dp[bCount], dp[bCount - 1] + costs[i - 1][1]); + } + } + } + + return dp[n]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} costs + * @return {number} + */ + twoCitySchedCost(costs) { + let n = costs.length / 2; + let dp = new Array(n + 1).fill(0); + + for (let aCount = 0; aCount <= n; aCount++) { + for (let bCount = 0; bCount <= n; bCount++) { + let i = aCount + bCount; + if (i === 0) continue; + + let tmp = dp[bCount]; + dp[bCount] = Infinity; + if (aCount > 0) { + dp[bCount] = Math.min(dp[bCount], tmp + costs[i - 1][0]); + } + if (bCount > 0) { + dp[bCount] = Math.min(dp[bCount], dp[bCount - 1] + costs[i - 1][1]); + } + } + } + + return dp[n]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n)$ + +> Where $n$ is the half of the size of the array $costs$. + +--- + +## 5. Greedy + +::tabs-start + +```python +class Solution: + def twoCitySchedCost(self, costs: List[List[int]]) -> int: + diffs = [] + for c1, c2 in costs: + diffs.append([c2 - c1, c1, c2]) + + diffs.sort() + res = 0 + for i in range(len(diffs)): + if i < len(diffs) // 2: + res += diffs[i][2] + else: + res += diffs[i][1] + + return res +``` + +```java +public class Solution { + public int twoCitySchedCost(int[][] costs) { + List diffs = new ArrayList<>(); + for (int[] cost : costs) { + diffs.add(new int[]{cost[1] - cost[0], cost[0], cost[1]}); + } + + diffs.sort(Comparator.comparingInt(a -> a[0])); + + int res = 0; + for (int i = 0; i < diffs.size(); i++) { + if (i < diffs.size() / 2) { + res += diffs.get(i)[2]; + } else { + res += diffs.get(i)[1]; + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int twoCitySchedCost(vector>& costs) { + vector> diffs; + for (auto& cost : costs) { + diffs.push_back({cost[1] - cost[0], cost[0], cost[1]}); + } + + sort(diffs.begin(), diffs.end()); + + int res = 0; + for (int i = 0; i < diffs.size(); i++) { + if (i < diffs.size() / 2) { + res += diffs[i][2]; + } else { + res += diffs[i][1]; + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} costs + * @return {number} + */ + twoCitySchedCost(costs) { + let diffs = []; + for (let cost of costs) { + diffs.push([cost[1] - cost[0], cost[0], cost[1]]); + } + + diffs.sort((a, b) => a[0] - b[0]); + + let res = 0; + for (let i = 0; i < diffs.length; i++) { + if (i < diffs.length / 2) { + res += diffs[i][2]; + } else { + res += diffs[i][1]; + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(n)$ + +--- + +## 6. Greedy (Optimal) + +::tabs-start + +```python +class Solution: + def twoCitySchedCost(self, costs: List[List[int]]) -> int: + costs.sort(key=lambda x: x[1] - x[0]) + n, res = len(costs) // 2, 0 + + for i in range(n): + res += costs[i][1] + costs[i + n][0] + return res +``` + +```java +public class Solution { + public int twoCitySchedCost(int[][] costs) { + Arrays.sort(costs, (a, b) -> Integer.compare(a[1] - a[0], b[1] - b[0])); + int n = costs.length / 2, res = 0; + + for (int i = 0; i < n; i++) { + res += costs[i][1] + costs[i + n][0]; + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int twoCitySchedCost(vector>& costs) { + sort(costs.begin(), costs.end(), [](const auto& a, const auto& b) { + return (a[1] - a[0]) < (b[1] - b[0]); + }); + + int n = costs.size() / 2, res = 0; + for (int i = 0; i < n; i++) { + res += costs[i][1] + costs[i + n][0]; + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} costs + * @return {number} + */ + twoCitySchedCost(costs) { + costs.sort((a, b) => (a[1] - a[0]) - (b[1] - b[0])); + let n = costs.length / 2, res = 0; + + for (let i = 0; i < n; i++) { + res += costs[i][1] + costs[i + n][0]; + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. \ No newline at end of file diff --git a/articles/widest-vertical-area-between-two-points-containing-no-points.md b/articles/widest-vertical-area-between-two-points-containing-no-points.md new file mode 100644 index 000000000..b41a574f7 --- /dev/null +++ b/articles/widest-vertical-area-between-two-points-containing-no-points.md @@ -0,0 +1,212 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def maxWidthOfVerticalArea(self, points: List[List[int]]) -> int: + n = len(points) + res = 0 + + for i in range(1, n): + x1 = points[i][0] + for j in range(i): + x2 = points[j][0] + hasPoints = False + for k in range(n): + if k == i or k == j: + continue + + x3 = points[k][0] + if x3 > min(x1, x2) and x3 < max(x1, x2): + hasPoints = True + break + + if not hasPoints: + res = max(res, abs(x1 - x2)) + + return res +``` + +```java +public class Solution { + public int maxWidthOfVerticalArea(int[][] points) { + int n = points.length, res = 0; + + for (int i = 1; i < n; i++) { + int x1 = points[i][0]; + for (int j = 0; j < i; j++) { + int x2 = points[j][0]; + boolean hasPoints = false; + + for (int k = 0; k < n; k++) { + if (k == i || k == j) continue; + + int x3 = points[k][0]; + if (x3 > Math.min(x1, x2) && x3 < Math.max(x1, x2)) { + hasPoints = true; + break; + } + } + + if (!hasPoints) { + res = Math.max(res, Math.abs(x1 - x2)); + } + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int maxWidthOfVerticalArea(vector>& points) { + int n = points.size(), res = 0; + + for (int i = 1; i < n; i++) { + int x1 = points[i][0]; + for (int j = 0; j < i; j++) { + int x2 = points[j][0]; + bool hasPoints = false; + + for (int k = 0; k < n; k++) { + if (k == i || k == j) continue; + + int x3 = points[k][0]; + if (x3 > min(x1, x2) && x3 < max(x1, x2)) { + hasPoints = true; + break; + } + } + + if (!hasPoints) { + res = max(res, abs(x1 - x2)); + } + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} points + * @return {number} + */ + maxWidthOfVerticalArea(points) { + let n = points.length, res = 0; + + for (let i = 1; i < n; i++) { + let x1 = points[i][0]; + for (let j = 0; j < i; j++) { + let x2 = points[j][0]; + let hasPoints = false; + + for (let k = 0; k < n; k++) { + if (k === i || k === j) continue; + + let x3 = points[k][0]; + if (x3 > Math.min(x1, x2) && x3 < Math.max(x1, x2)) { + hasPoints = true; + break; + } + } + + if (!hasPoints) { + res = Math.max(res, Math.abs(x1 - x2)); + } + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 3)$ +* Space complexity: $O(1)$ + +--- + +## 2. Sorting + +::tabs-start + +```python +class Solution: + def maxWidthOfVerticalArea(self, points: List[List[int]]) -> int: + points.sort() + res = 0 + for i in range(len(points) - 1): + res = max(res, points[i + 1][0] - points[i][0]) + return res +``` + +```java +public class Solution { + public int maxWidthOfVerticalArea(int[][] points) { + Arrays.sort(points, Comparator.comparingInt(a -> a[0])); + int res = 0; + + for (int i = 0; i < points.length - 1; i++) { + res = Math.max(res, points[i + 1][0] - points[i][0]); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int maxWidthOfVerticalArea(vector>& points) { + sort(points.begin(), points.end(), [](const auto& a, const auto& b) { + return a[0] < b[0]; + }); + + int res = 0; + for (int i = 0; i < points.size() - 1; i++) { + res = max(res, points[i + 1][0] - points[i][0]); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} points + * @return {number} + */ + maxWidthOfVerticalArea(points) { + points.sort((a, b) => a[0] - b[0]); + let res = 0; + + for (let i = 0; i < points.length - 1; i++) { + res = Math.max(res, points[i + 1][0] - points[i][0]); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. \ No newline at end of file From 9e68fa1311a58a5e047535d98b97ed5a1ad1a8ac Mon Sep 17 00:00:00 2001 From: Sri Hari <94112314+Srihari2222@users.noreply.github.com> Date: Fri, 28 Feb 2025 09:04:50 +0530 Subject: [PATCH 02/12] Batch-5/Neetcode-ALL/Added-articles (#3858) --- articles/design-a-food-rating-system.md | 457 +++++++++++++++ articles/design-parking-system.md | 167 ++++++ articles/design-underground-system.md | 357 ++++++++++++ articles/naming-a-company.md | 495 ++++++++++++++++ ...umber-of-submatrices-that-sum-to-target.md | 549 ++++++++++++++++++ articles/text-justification.md | 181 ++++++ 6 files changed, 2206 insertions(+) create mode 100644 articles/design-a-food-rating-system.md create mode 100644 articles/design-parking-system.md create mode 100644 articles/design-underground-system.md create mode 100644 articles/naming-a-company.md create mode 100644 articles/number-of-submatrices-that-sum-to-target.md create mode 100644 articles/text-justification.md diff --git a/articles/design-a-food-rating-system.md b/articles/design-a-food-rating-system.md new file mode 100644 index 000000000..7be2642c1 --- /dev/null +++ b/articles/design-a-food-rating-system.md @@ -0,0 +1,457 @@ +## 1. Brute Force + +::tabs-start + +```python +class FoodRatings: + + def __init__(self, foods: List[str], cuisines: List[str], ratings: List[int]): + self.foodToRating = {} # food -> rating + self.cuisineToFood = defaultdict(list) # cuisine -> [food] + for i in range(len(foods)): + self.foodToRating[foods[i]] = ratings[i] + self.cuisineToFood[cuisines[i]].append(foods[i]) + + def changeRating(self, food: str, newRating: int) -> None: + self.foodToRating[food] = newRating + + def highestRated(self, cuisine: str) -> str: + maxR, res = 0, "" + for food in self.cuisineToFood[cuisine]: + r = self.foodToRating[food] + if r > maxR or (r == maxR and food < res): + res = food + maxR = r + return res +``` + +```java +public class FoodRatings { + private Map foodToRating; + private Map> cuisineToFood; + + public FoodRatings(String[] foods, String[] cuisines, int[] ratings) { + foodToRating = new HashMap<>(); + cuisineToFood = new HashMap<>(); + for (int i = 0; i < foods.length; i++) { + foodToRating.put(foods[i], ratings[i]); + cuisineToFood.computeIfAbsent(cuisines[i], k -> new ArrayList<>()).add(foods[i]); + } + } + + public void changeRating(String food, int newRating) { + foodToRating.put(food, newRating); + } + + public String highestRated(String cuisine) { + int maxR = 0; + String res = ""; + for (String food : cuisineToFood.get(cuisine)) { + int r = foodToRating.get(food); + if (r > maxR || (r == maxR && food.compareTo(res) < 0)) { + res = food; + maxR = r; + } + } + return res; + } +} +``` + +```cpp +class FoodRatings { +private: + unordered_map foodToRating; + unordered_map> cuisineToFood; + +public: + FoodRatings(vector& foods, vector& cuisines, vector& ratings) { + for (size_t i = 0; i < foods.size(); i++) { + foodToRating[foods[i]] = ratings[i]; + cuisineToFood[cuisines[i]].push_back(foods[i]); + } + } + + void changeRating(string food, int newRating) { + foodToRating[food] = newRating; + } + + string highestRated(string cuisine) { + int maxR = 0; + string res = ""; + for (const string& food : cuisineToFood[cuisine]) { + int r = foodToRating[food]; + if (r > maxR || (r == maxR && food < res)) { + res = food; + maxR = r; + } + } + return res; + } +}; +``` + +```javascript +class FoodRatings { + /** + * @param {string[]} foods + * @param {string[]} cuisines + * @param {number[]} ratings + */ + constructor(foods, cuisines, ratings) { + this.foodToRating = new Map(); + this.cuisineToFood = new Map(); + + for (let i = 0; i < foods.length; i++) { + this.foodToRating.set(foods[i], ratings[i]); + if (!this.cuisineToFood.has(cuisines[i])) { + this.cuisineToFood.set(cuisines[i], []); + } + this.cuisineToFood.get(cuisines[i]).push(foods[i]); + } + } + + /** + * @param {string} food + * @param {number} newRating + * @return {void} + */ + changeRating(food, newRating) { + this.foodToRating.set(food, newRating); + } + + /** + * @param {string} cuisine + * @return {string} + */ + highestRated(cuisine) { + let maxR = 0, res = ""; + for (let food of this.cuisineToFood.get(cuisine)) { + let r = this.foodToRating.get(food); + if (r > maxR || (r === maxR && food < res)) { + res = food; + maxR = r; + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: + * $O(n)$ time for initialization. + * $O(1)$ time for each $changeRating()$ function call. + * $O(n)$ time for each $highestRated()$ function call. +* Space complexity: $O(n)$ + +--- + +## 2. Heap + +::tabs-start + +```python +class FoodRatings: + + def __init__(self, foods: List[str], cuisines: List[str], ratings: List[int]): + self.foodToRating = {} # food -> rating + self.foodToCuisine = {} # food -> cuisine + self.cuisineToHeap = defaultdict(list) # cuisine -> max_heap + + for i in range(len(foods)): + self.foodToRating[foods[i]] = ratings[i] + self.foodToCuisine[foods[i]] = cuisines[i] + heappush(self.cuisineToHeap[cuisines[i]], (-ratings[i], foods[i])) + + def changeRating(self, food: str, newRating: int) -> None: + cuisine = self.foodToCuisine[food] + self.foodToRating[food] = newRating + heappush(self.cuisineToHeap[cuisine], (-newRating, food)) + + def highestRated(self, cuisine: str) -> str: + heap = self.cuisineToHeap[cuisine] + while heap: + rating, food = heap[0] + if -rating == self.foodToRating[food]: + return food + heappop(heap) +``` + +```java +public class FoodRatings { + private Map foodToRating; + private Map foodToCuisine; + private Map> cuisineToHeap; + + private static class Food { + int rating; + String name; + + Food(int rating, String name) { + this.rating = rating; + this.name = name; + } + } + + public FoodRatings(String[] foods, String[] cuisines, int[] ratings) { + foodToRating = new HashMap<>(); + foodToCuisine = new HashMap<>(); + cuisineToHeap = new HashMap<>(); + + for (int i = 0; i < foods.length; i++) { + foodToRating.put(foods[i], ratings[i]); + foodToCuisine.put(foods[i], cuisines[i]); + cuisineToHeap + .computeIfAbsent(cuisines[i], k -> new PriorityQueue<>( + (a, b) -> a.rating == b.rating ? a.name.compareTo(b.name) : b.rating - a.rating)) + .offer(new Food(ratings[i], foods[i])); + } + } + + public void changeRating(String food, int newRating) { + String cuisine = foodToCuisine.get(food); + foodToRating.put(food, newRating); + cuisineToHeap.get(cuisine).offer(new Food(newRating, food)); + } + + public String highestRated(String cuisine) { + PriorityQueue heap = cuisineToHeap.get(cuisine); + while (!heap.isEmpty()) { + Food top = heap.peek(); + if (foodToRating.get(top.name) == top.rating) { + return top.name; + } + heap.poll(); + } + return ""; + } +} +``` + +```cpp +class FoodRatings { + unordered_map foodToRating; + unordered_map foodToCuisine; + struct cmp { + bool operator()(const pair& a, const pair& b) { + if (a.first == b.first) return a.second > b.second; + return a.first < b.first; + } + }; + unordered_map, + vector>, cmp>> cuisineToHeap; + +public: + FoodRatings(vector& foods, vector& cuisines, vector& ratings) { + for (int i = 0; i < foods.size(); i++) { + foodToRating[foods[i]] = ratings[i]; + foodToCuisine[foods[i]] = cuisines[i]; + cuisineToHeap[cuisines[i]].push({ratings[i], foods[i]}); + } + } + + void changeRating(string food, int newRating) { + string cuisine = foodToCuisine[food]; + foodToRating[food] = newRating; + cuisineToHeap[cuisine].push({newRating, food}); + } + + string highestRated(string cuisine) { + auto &heap = cuisineToHeap[cuisine]; + while (!heap.empty()) { + auto [rating, food] = heap.top(); + if (foodToRating[food] == rating) return food; + heap.pop(); + } + return ""; + } +}; +``` + +```javascript +class FoodRatings { + /** + * @param {string[]} foods + * @param {string[]} cuisines + * @param {number[]} ratings + */ + constructor(foods, cuisines, ratings) { + this.foodToRating = new Map(); + this.foodToCuisine = new Map(); + this.cuisineToHeap = new Map(); + + for (let i = 0; i < foods.length; i++) { + this.foodToRating.set(foods[i], ratings[i]); + this.foodToCuisine.set(foods[i], cuisines[i]); + if (!this.cuisineToHeap.has(cuisines[i])) { + this.cuisineToHeap.set(cuisines[i], new PriorityQueue( + (a, b) => b.rating - a.rating || a.name.localeCompare(b.name) + )); + } + this.cuisineToHeap.get(cuisines[i]).enqueue( + { rating: ratings[i], name: foods[i] } + ); + } + } + + /** + * @param {string} food + * @param {number} newRating + * @return {void} + */ + changeRating(food, newRating) { + let cuisine = this.foodToCuisine.get(food); + this.foodToRating.set(food, newRating); + this.cuisineToHeap.get(cuisine).enqueue( + { rating: newRating, name: food } + ); + } + + /** + * @param {string} cuisine + * @return {string} + */ + highestRated(cuisine) { + let heap = this.cuisineToHeap.get(cuisine); + while (!heap.isEmpty()) { + let top = heap.front(); + if (this.foodToRating.get(top.name) === top.rating) { + return top.name; + } + heap.dequeue(); + } + return ""; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: + * $O(n \log n)$ time for initialization. + * $O(\log n)$ time for each $changeRating()$ function call. + * $O(\log n)$ time for each $highestRated()$ function call. +* Space complexity: $O(n)$ + +--- + +## 3. Sorted Set + +::tabs-start + +```python +class FoodRatings: + + def __init__(self, foods: List[str], cuisines: List[str], ratings: List[int]): + self.foodToRating = {} # food -> rating + self.foodToCuisine = {} # food -> cuisine + self.cuisineToSortedSet = defaultdict(SortedSet) # cuisine -> SortedSet[(rating, food)] + + for i in range(len(foods)): + self.foodToRating[foods[i]] = ratings[i] + self.foodToCuisine[foods[i]] = cuisines[i] + self.cuisineToSortedSet[cuisines[i]].add((-ratings[i], foods[i])) + + def changeRating(self, food: str, newRating: int) -> None: + cuisine = self.foodToCuisine[food] + oldRating = self.foodToRating[food] + + self.cuisineToSortedSet[cuisine].remove((-oldRating, food)) + self.foodToRating[food] = newRating + self.cuisineToSortedSet[cuisine].add((-newRating, food)) + + def highestRated(self, cuisine: str) -> str: + return self.cuisineToSortedSet[cuisine][0][1] +``` + +```java +public class FoodRatings { + private Map foodToRating; + private Map foodToCuisine; + private Map> cuisineToSortedSet; + + private static class FoodPair { + int rating; + String food; + + FoodPair(int rating, String food) { + this.rating = rating; + this.food = food; + } + } + + public FoodRatings(String[] foods, String[] cuisines, int[] ratings) { + foodToRating = new HashMap<>(); + foodToCuisine = new HashMap<>(); + cuisineToSortedSet = new HashMap<>(); + + for (int i = 0; i < foods.length; i++) { + foodToRating.put(foods[i], ratings[i]); + foodToCuisine.put(foods[i], cuisines[i]); + cuisineToSortedSet.computeIfAbsent(cuisines[i], k -> new TreeSet<>((a, b) -> { + if (a.rating != b.rating) return b.rating - a.rating; + return a.food.compareTo(b.food); + })).add(new FoodPair(ratings[i], foods[i])); + } + } + + public void changeRating(String food, int newRating) { + String cuisine = foodToCuisine.get(food); + int oldRating = foodToRating.get(food); + TreeSet set = cuisineToSortedSet.get(cuisine); + set.remove(new FoodPair(oldRating, food)); + foodToRating.put(food, newRating); + set.add(new FoodPair(newRating, food)); + } + + public String highestRated(String cuisine) { + return cuisineToSortedSet.get(cuisine).first().food; + } +} +``` + +```cpp +class FoodRatings { + unordered_map foodToRating; + unordered_map foodToCuisine; + unordered_map>> cuisineToSet; + +public: + FoodRatings(vector& foods, vector& cuisines, vector& ratings) { + for (int i = 0; i < foods.size(); i++) { + foodToRating[foods[i]] = ratings[i]; + foodToCuisine[foods[i]] = cuisines[i]; + cuisineToSet[cuisines[i]].insert({-ratings[i], foods[i]}); + } + } + + void changeRating(string food, int newRating) { + string cuisine = foodToCuisine[food]; + auto& s = cuisineToSet[cuisine]; + + s.erase({-foodToRating[food], food}); + foodToRating[food] = newRating; + s.insert({-newRating, food}); + } + + string highestRated(string cuisine) { + return begin(cuisineToSet[cuisine])->second; + } +}; +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: + * $O(n \log n)$ time for initialization. + * $O(\log n)$ time for each $changeRating()$ function call. + * $O(1)$ in Python and $O(\log n)$ in other languages for each $highestRated()$ function call. +* Space complexity: $O(n)$ \ No newline at end of file diff --git a/articles/design-parking-system.md b/articles/design-parking-system.md new file mode 100644 index 000000000..4abdb9aa3 --- /dev/null +++ b/articles/design-parking-system.md @@ -0,0 +1,167 @@ +## 1. Array - I + +::tabs-start + +```python +class ParkingSystem: + + def __init__(self, big: int, medium: int, small: int): + self.spaces = [big, medium, small] + + def addCar(self, carType: int) -> bool: + if self.spaces[carType - 1] > 0: + self.spaces[carType - 1] -= 1 + return True + return False +``` + +```java +public class ParkingSystem { + private int[] spaces; + + public ParkingSystem(int big, int medium, int small) { + spaces = new int[]{big, medium, small}; + } + + public boolean addCar(int carType) { + if (spaces[carType - 1] > 0) { + spaces[carType - 1]--; + return true; + } + return false; + } +} +``` + +```cpp +class ParkingSystem { + int spaces[3]; + +public: + ParkingSystem(int big, int medium, int small) { + spaces[0] = big; + spaces[1] = medium; + spaces[2] = small; + } + + bool addCar(int carType) { + if (spaces[carType - 1] > 0) { + spaces[carType - 1]--; + return true; + } + return false; + } +}; +``` + +```javascript +class ParkingSystem { + /** + * @constructor + * @param {number} big + * @param {number} medium + * @param {number} small + */ + constructor(big, medium, small) { + this.spaces = [big, medium, small]; + } + + /** + * @param {number} carType + * @return {boolean} + */ + addCar(carType) { + if (this.spaces[carType - 1] > 0) { + this.spaces[carType - 1]--; + return true; + } + return false; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: + * $O(1)$ time for initialization. + * $O(1)$ time for each $addCar()$ function call. +* Space complexity: $O(1)$ + +--- + +## 2. Array - II + +::tabs-start + +```python +class ParkingSystem: + + def __init__(self, big: int, medium: int, small: int): + self.spaces = [big, medium, small] + + def addCar(self, carType: int) -> bool: + self.spaces[carType - 1] -= 1 + return self.spaces[carType - 1] >= 0 +``` + +```java +public class ParkingSystem { + int[] spaces; + + public ParkingSystem(int big, int medium, int small) { + spaces = new int[]{big, medium, small}; + } + + public boolean addCar(int carType) { + return spaces[carType - 1]-- > 0; + } +} +``` + +```cpp +class ParkingSystem { + int spaces[3]; + +public: + ParkingSystem(int big, int medium, int small) { + spaces[0] = big, spaces[1] = medium, spaces[2] = small; + } + + bool addCar(int carType) { + return spaces[carType - 1]-- > 0; + } +}; +``` + +```javascript +class ParkingSystem { + /** + * @constructor + * @param {number} big + * @param {number} medium + * @param {number} small + */ + constructor(big, medium, small) { + this.spaces = [big, medium, small]; + } + + /** + * @param {number} carType + * @return {boolean} + */ + addCar(carType) { + return this.spaces[carType - 1]-- > 0; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: + * $O(1)$ time for initialization. + * $O(1)$ time for each $addCar()$ function call. +* Space complexity: $O(1)$ \ No newline at end of file diff --git a/articles/design-underground-system.md b/articles/design-underground-system.md new file mode 100644 index 000000000..d03c0c9e8 --- /dev/null +++ b/articles/design-underground-system.md @@ -0,0 +1,357 @@ +## 1. Two HashMaps + +::tabs-start + +```python +class UndergroundSystem: + + def __init__(self): + self.checkInMap = {} # id -> (startStation, time) + self.routeMap = {} # (start, end) -> [totalTime, count] + + def checkIn(self, id: int, startStation: str, t: int) -> None: + self.checkInMap[id] = (startStation, t) + + def checkOut(self, id: int, endStation: str, t: int) -> None: + startStation, time = self.checkInMap[id] + route = (startStation, endStation) + if route not in self.routeMap: + self.routeMap[route] = [0, 0] + self.routeMap[route][0] += t - time + self.routeMap[route][1] += 1 + + def getAverageTime(self, startStation: str, endStation: str) -> float: + totalTime, count = self.routeMap[(startStation, endStation)] + return totalTime / count +``` + +```java +public class UndergroundSystem { + private Map> checkInMap; + private Map routeMap; + + public UndergroundSystem() { + checkInMap = new HashMap<>(); + routeMap = new HashMap<>(); + } + + public void checkIn(int id, String startStation, int t) { + checkInMap.put(id, new Pair<>(startStation, t)); + } + + public void checkOut(int id, String endStation, int t) { + Pair entry = checkInMap.get(id); + String route = entry.getKey() + "," + endStation; + routeMap.putIfAbsent(route, new int[]{0, 0}); + routeMap.get(route)[0] += t - entry.getValue(); + routeMap.get(route)[1] += 1; + } + + public double getAverageTime(String startStation, String endStation) { + int[] data = routeMap.get(startStation + "," + endStation); + return (double) data[0] / data[1]; + } +} +``` + +```cpp +class UndergroundSystem { + unordered_map> checkInMap; + unordered_map> routeMap; + +public: + UndergroundSystem() {} + + void checkIn(int id, string startStation, int t) { + checkInMap[id] = {startStation, t}; + } + + void checkOut(int id, string endStation, int t) { + auto [startStation, time] = checkInMap[id]; + string route = startStation + "," + endStation; + if (!routeMap.count(route)) + routeMap[route] = {0, 0}; + routeMap[route].first += t - time; + routeMap[route].second += 1; + } + + double getAverageTime(string startStation, string endStation) { + string route = startStation + "," + endStation; + auto [totalTime, count] = routeMap[route]; + return (double) totalTime / count; + } +}; +``` + +```javascript +class UndergroundSystem { + /** + * @constructor + */ + constructor() { + this.checkInMap = new Map(); + this.routeMap = new Map(); + } + + /** + * @param {number} id + * @param {string} startStation + * @param {number} t + * @return {void} + */ + checkIn(id, startStation, t) { + this.checkInMap.set(id, [startStation, t]); + } + + /** + * @param {number} id + * @param {string} endStation + * @param {number} t + * @return {void} + */ + checkOut(id, endStation, t) { + const [startStation, time] = this.checkInMap.get(id); + const route = `${startStation},${endStation}`; + if (!this.routeMap.has(route)) this.routeMap.set(route, [0, 0]); + this.routeMap.get(route)[0] += t - time; + this.routeMap.get(route)[1] += 1; + } + + /** + * @param {string} startStation + * @param {string} endStation + * @return {number} + */ + getAverageTime(startStation, endStation) { + const [totalTime, count] = this.routeMap.get(`${startStation},${endStation}`); + return totalTime / count; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: + * $O(1)$ time for initialization. + * $O(1)$ time for each $checkIn()$ function call. + * $O(m)$ time for each $checkOut()$ and $getAverageTime()$ function calls. +* Space complexity: $O(n + N ^ 2)$ + +> Where $n$ is the number of passengers, $N$ is the total number of stations, and $m$ is the average length of station name. + +--- + +## 2. Two HashMaps + Hashing + +::tabs-start + +```python +class UndergroundSystem: + MOD1, MOD2 = 768258391, 685683731 + BASE1, BASE2 = 37, 31 + + def __init__(self): + self.checkInMap = {} # id -> (startStation, time) + self.routeMap = {} # hash(route) -> (totalTime, count) + + def getHash(self, s1: str, s2: str) -> int: + h1, h2, p1, p2 = 0, 0, 1, 1 + for c in s1 + ',' + s2: + h1 = (h1 + (ord(c) - 96) * p1) % self.MOD1 + h2 = (h2 + (ord(c) - 96) * p2) % self.MOD2 + p1 = (p1 * self.BASE1) % self.MOD1 + p2 = (p2 * self.BASE2) % self.MOD2 + return (h1 << 32) | h2 + + def checkIn(self, id: int, startStation: str, t: int) -> None: + self.checkInMap[id] = (startStation, t) + + def checkOut(self, id: int, endStation: str, t: int) -> None: + startStation, time = self.checkInMap[id] + routeHash = self.getHash(startStation, endStation) + if routeHash not in self.routeMap: + self.routeMap[routeHash] = [0, 0] + self.routeMap[routeHash][0] += t - time + self.routeMap[routeHash][1] += 1 + + def getAverageTime(self, startStation: str, endStation: str) -> float: + routeHash = self.getHash(startStation, endStation) + totalTime, count = self.routeMap[routeHash] + return totalTime / count +``` + +```java +public class UndergroundSystem { + private static final int MOD1 = 768258391, MOD2 = 685683731; + private static final int BASE1 = 37, BASE2 = 31; + private Map> checkInMap; + private Map routeMap; + + public UndergroundSystem() { + checkInMap = new HashMap<>(); + routeMap = new HashMap<>(); + } + + private long getHash(String s1, String s2) { + long h1 = 0, h2 = 0, p1 = 1, p2 = 1; + String combined = s1 + "," + s2; + + for (char c : combined.toCharArray()) { + h1 = (h1 + (c - 96) * p1) % MOD1; + h2 = (h2 + (c - 96) * p2) % MOD2; + p1 = (p1 * BASE1) % MOD1; + p2 = (p2 * BASE2) % MOD2; + } + return (h1 << 32) | h2; + } + + public void checkIn(int id, String startStation, int t) { + checkInMap.put(id, new Pair<>(startStation, t)); + } + + public void checkOut(int id, String endStation, int t) { + Pair checkInData = checkInMap.get(id); + long routeHash = getHash(checkInData.getKey(), endStation); + routeMap.putIfAbsent(routeHash, new int[]{0, 0}); + int[] data = routeMap.get(routeHash); + data[0] += (t - checkInData.getValue()); + data[1]++; + } + + public double getAverageTime(String startStation, String endStation) { + long routeHash = getHash(startStation, endStation); + int[] data = routeMap.get(routeHash); + return (double) data[0] / data[1]; + } +} +``` + +```cpp +class UndergroundSystem { +private: + static constexpr int MOD1 = 768258391, MOD2 = 685683731; + static constexpr int BASE1 = 37, BASE2 = 31; + unordered_map> checkInMap; + unordered_map> routeMap; + + unsigned long long getHash(const string& s1, const string& s2) { + long long h1 = 0, h2 = 0, p1 = 1, p2 = 1; + string combined = s1 + "," + s2; + + for (char c : combined) { + h1 = (h1 + (c - 96) * p1) % MOD1; + h2 = (h2 + (c - 96) * p2) % MOD2; + p1 = (p1 * BASE1) % MOD1; + p2 = (p2 * BASE2) % MOD2; + } + return (h1 << 32) | h2; + } + +public: + UndergroundSystem() {} + + void checkIn(int id, string startStation, int t) { + checkInMap[id] = {startStation, t}; + } + + void checkOut(int id, string endStation, int t) { + auto [startStation, time] = checkInMap[id]; + unsigned long long routeHash = getHash(startStation, endStation); + routeMap[routeHash].first += (t - time); + routeMap[routeHash].second++; + } + + double getAverageTime(string startStation, string endStation) { + unsigned long long routeHash = getHash(startStation, endStation); + auto [totalTime, count] = routeMap[routeHash]; + return (double) totalTime / count; + } +}; +``` + +```javascript +class UndergroundSystem { + /** + * @constructor + */ + constructor() { + this.MOD1 = 768258391; + this.MOD2 = 685683731; + this.BASE1 = 37; + this.BASE2 = 31; + this.checkInMap = new Map(); + this.routeMap = new Map(); + } + + /** + * @param {string} s1 + * @param {string} s2 + * @return {number} + */ + getHash(s1, s2) { + let h1 = 0, h2 = 0, p1 = 1, p2 = 1; + let combined = s1 + "," + s2; + + for (let i = 0; i < combined.length; i++) { + let c = combined.charCodeAt(i) - 96; + h1 = (h1 + c * p1) % this.MOD1; + h2 = (h2 + c * p2) % this.MOD2; + p1 = (p1 * this.BASE1) % this.MOD1; + p2 = (p2 * this.BASE2) % this.MOD2; + } + return BigInt(h1) << BigInt(32) | BigInt(h2); + } + + /** + * @param {number} id + * @param {string} startStation + * @param {number} t + * @return {void} + */ + checkIn(id, startStation, t) { + this.checkInMap.set(id, [startStation, t]); + } + + /** + * @param {number} id + * @param {string} endStation + * @param {number} t + * @return {void} + */ + checkOut(id, endStation, t) { + let [startStation, time] = this.checkInMap.get(id); + let routeHash = this.getHash(startStation, endStation); + if (!this.routeMap.has(routeHash)) { + this.routeMap.set(routeHash, [0, 0]); + } + let data = this.routeMap.get(routeHash); + data[0] += t - time; + data[1]++; + } + + /** + * @param {string} startStation + * @param {string} endStation + * @return {number} + */ + getAverageTime(startStation, endStation) { + let routeHash = this.getHash(startStation, endStation); + let [totalTime, count] = this.routeMap.get(routeHash); + return totalTime / count; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: + * $O(1)$ time for initialization. + * $O(1)$ time for each $checkIn()$ function call. + * $O(m)$ time for each $checkOut()$ and $getAverageTime()$ function calls. +* Space complexity: $O(n + N ^ 2)$ + +> Where $n$ is the number of passengers, $N$ is the total number of stations, and $m$ is the average length of station name. \ No newline at end of file diff --git a/articles/naming-a-company.md b/articles/naming-a-company.md new file mode 100644 index 000000000..dbd85775d --- /dev/null +++ b/articles/naming-a-company.md @@ -0,0 +1,495 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def distinctNames(self, ideas: List[str]) -> int: + n = len(ideas) + res = set() + ideasSet = set(ideas) + + for i in range(n): + for j in range(i + 1, n): + A, B = ideas[j][0] + ideas[i][1:], ideas[i][0] + ideas[j][1:] + if A not in ideasSet and B not in ideasSet: + res.add(A + ' ' + B) + res.add(B + ' ' + A) + + return len(res) +``` + +```java +public class Solution { + public long distinctNames(String[] ideas) { + int n = ideas.length; + Set res = new HashSet<>(); + Set ideasSet = new HashSet<>(Arrays.asList(ideas)); + + for (int i = 0; i < n; i++) { + for (int j = i + 1; j < n; j++) { + String A = ideas[j].charAt(0) + ideas[i].substring(1); + String B = ideas[i].charAt(0) + ideas[j].substring(1); + + if (!ideasSet.contains(A) && !ideasSet.contains(B)) { + res.add(A + " " + B); + res.add(B + " " + A); + } + } + } + + return res.size(); + } +} +``` + +```cpp +class Solution { +public: + long long distinctNames(vector& ideas) { + int n = ideas.size(); + unordered_set res; + unordered_set ideasSet(ideas.begin(), ideas.end()); + + for (int i = 0; i < n; i++) { + for (int j = i + 1; j < n; j++) { + string A = ideas[j][0] + ideas[i].substr(1); + string B = ideas[i][0] + ideas[j].substr(1); + + if (!ideasSet.count(A) && !ideasSet.count(B)) { + res.insert(A + " " + B); + res.insert(B + " " + A); + } + } + } + + return res.size(); + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} ideas + * @return {number} + */ + distinctNames(ideas) { + let n = ideas.length; + let res = new Set(); + let ideasSet = new Set(ideas); + + for (let i = 0; i < n; i++) { + for (let j = i + 1; j < n; j++) { + let A = ideas[j][0] + ideas[i].slice(1); + let B = ideas[i][0] + ideas[j].slice(1); + + if (!ideasSet.has(A) && !ideasSet.has(B)) { + res.add(A + " " + B); + res.add(B + " " + A); + } + } + } + + return res.size; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * n ^ 2)$ +* Space complexity: $O(m * n ^ 2)$ + +> Where $n$ is the size of the array $ideas$ and $m$ is the average length of the strings. + +--- + +## 2. Group By First Letter (Hash Map) + +::tabs-start + +```python +class Solution: + def distinctNames(self, ideas: List[str]) -> int: + wordMap = collections.defaultdict(set) + for w in ideas: + wordMap[w[0]].add(w[1:]) + + res = 0 + for char1 in wordMap: + for char2 in wordMap: + if char1 == char2: + continue + + intersect = sum(1 for w in wordMap[char1] if w in wordMap[char2]) + distinct1 = len(wordMap[char1]) - intersect + distinct2 = len(wordMap[char2]) - intersect + res += distinct1 * distinct2 + + return res +``` + +```java +public class Solution { + public long distinctNames(String[] ideas) { + Map> wordMap = new HashMap<>(); + for (String word : ideas) { + wordMap.computeIfAbsent( + word.charAt(0), k -> new HashSet<>()).add(word.substring(1) + ); + } + + long res = 0; + for (char char1 : wordMap.keySet()) { + for (char char2 : wordMap.keySet()) { + if (char1 == char2) continue; + + int intersect = 0; + for (String w : wordMap.get(char1)) { + if (wordMap.get(char2).contains(w)) { + intersect++; + } + } + + int distinct1 = wordMap.get(char1).size() - intersect; + int distinct2 = wordMap.get(char2).size() - intersect; + res += distinct1 * 1L * distinct2; + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + long long distinctNames(vector& ideas) { + unordered_map> wordMap; + for (const string& word : ideas) { + wordMap[word[0]].insert(word.substr(1)); + } + + long long res = 0; + for (auto& [char1, set1] : wordMap) { + for (auto& [char2, set2] : wordMap) { + if (char1 == char2) continue; + + int intersect = 0; + for (const string& w : set1) { + if (set2.count(w)) { + intersect++; + } + } + + int distinct1 = set1.size() - intersect; + int distinct2 = set2.size() - intersect; + res += distinct1 * 1LL * distinct2; + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} ideas + * @return {number} + */ + distinctNames(ideas) { + const wordMap = new Map(); + for (let word of ideas) { + let key = word[0]; + if (!wordMap.has(key)) { + wordMap.set(key, new Set()); + } + wordMap.get(key).add(word.slice(1)); + } + + let res = 0; + for (let [char1, set1] of wordMap) { + for (let [char2, set2] of wordMap) { + if (char1 === char2) continue; + + let intersect = 0; + for (let w of set1) { + if (set2.has(w)) { + intersect++; + } + } + + let distinct1 = set1.size - intersect; + let distinct2 = set2.size - intersect; + res += distinct1 * distinct2; + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * n)$ +* Space complexity: $O(m * n)$ + +> Where $n$ is the size of the array $ideas$ and $m$ is the average length of the strings. + +--- + +## 3. Group By First Letter (Array) + +::tabs-start + +```python +class Solution: + def distinctNames(self, ideas: List[str]) -> int: + suffixes = [set() for _ in range(26)] + for w in ideas: + suffixes[ord(w[0]) - ord('a')].add(w[1:]) + + res = 0 + for i in range(26): + for j in range(i + 1, 26): + intersect = len(suffixes[i] & suffixes[j]) + res += 2 * (len(suffixes[i]) - intersect) * (len(suffixes[j]) - intersect) + + return res +``` + +```java +public class Solution { + public long distinctNames(String[] ideas) { + Set[] suffixes = new HashSet[26]; + for (int i = 0; i < 26; i++) { + suffixes[i] = new HashSet<>(); + } + for (String w : ideas) { + suffixes[w.charAt(0) - 'a'].add(w.substring(1)); + } + + long res = 0; + for (int i = 0; i < 26; i++) { + for (int j = i + 1; j < 26; j++) { + int intersect = 0; + for (String s : suffixes[i]) { + if (suffixes[j].contains(s)) { + intersect++; + } + } + res += 2L * (suffixes[i].size() - intersect) * (suffixes[j].size() - intersect); + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + long long distinctNames(vector& ideas) { + unordered_set suffixes[26]; + for (const string& w : ideas) { + suffixes[w[0] - 'a'].insert(w.substr(1)); + } + + long long res = 0; + for (int i = 0; i < 26; i++) { + for (int j = i + 1; j < 26; j++) { + int intersect = 0; + for (const string& s : suffixes[i]) { + if (suffixes[j].count(s)) { + intersect++; + } + } + res += 2LL * (suffixes[i].size() - intersect) * (suffixes[j].size() - intersect); + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} ideas + * @return {number} + */ + distinctNames(ideas) { + const suffixes = Array.from({ length: 26 }, () => new Set()); + for (let w of ideas) { + suffixes[w.charCodeAt(0) - 97].add(w.slice(1)); + } + + let res = 0; + for (let i = 0; i < 26; i++) { + for (let j = i + 1; j < 26; j++) { + let intersect = 0; + for (let s of suffixes[i]) { + if (suffixes[j].has(s)) { + intersect++; + } + } + res += 2 * (suffixes[i].size - intersect) * (suffixes[j].size - intersect); + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * n)$ +* Space complexity: $O(m * n)$ + +> Where $n$ is the size of the array $ideas$ and $m$ is the average length of the strings. + +--- + +## 4. Counting + +::tabs-start + +```python +class Solution: + def distinctNames(self, ideas: List[str]) -> int: + mp = defaultdict(lambda: [False] * 26) + count = [[0] * 26 for _ in range(26)] + res = 0 + + for s in ideas: + first_char = ord(s[0]) - ord('a') + suffix = s[1:] + mp[suffix][first_char] = True + + for suffix, arr in mp.items(): + for i in range(26): + if arr[i]: + for j in range(26): + if not arr[j]: + count[i][j] += 1 + res += count[j][i] + + return 2 * res +``` + +```java +public class Solution { + public long distinctNames(String[] ideas) { + Map mp = new HashMap<>(); + int[][] count = new int[26][26]; + long res = 0; + + for (String s : ideas) { + int firstChar = s.charAt(0) - 'a'; + String suffix = s.substring(1); + mp.putIfAbsent(suffix, new boolean[26]); + mp.get(suffix)[firstChar] = true; + } + + for (boolean[] arr : mp.values()) { + for (int i = 0; i < 26; i++) { + if (arr[i]) { + for (int j = 0; j < 26; j++) { + if (!arr[j]) { + count[i][j]++; + res += count[j][i]; + } + } + } + } + } + return 2 * res; + } +} +``` + +```cpp +class Solution { +public: + long long distinctNames(vector& ideas) { + unordered_map> mp; + long long count[26][26] = {}; + long long res = 0; + + for (const string& s : ideas) { + int firstChar = s[0] - 'a'; + string suffix = s.substr(1); + mp[suffix][firstChar] = true; + } + + for (auto& [suffix, arr] : mp) { + for (int i = 0; i < 26; i++) { + if (arr[i]) { + for (int j = 0; j < 26; j++) { + if (!arr[j]) { + count[i][j]++; + res += count[j][i]; + } + } + } + } + } + return 2 * res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} ideas + * @return {number} + */ + distinctNames(ideas) { + const mp = new Map(); + const count = Array.from({ length: 26 }, () => Array(26).fill(0)); + let res = 0; + + for (const s of ideas) { + const firstChar = s.charCodeAt(0) - 97; + const suffix = s.slice(1); + if (!mp.has(suffix)) mp.set(suffix, new Array(26).fill(false)); + mp.get(suffix)[firstChar] = true; + } + + for (const arr of mp.values()) { + for (let i = 0; i < 26; i++) { + if (arr[i]) { + for (let j = 0; j < 26; j++) { + if (!arr[j]) { + count[i][j]++; + res += count[j][i]; + } + } + } + } + } + return 2 * res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * n)$ +* Space complexity: $O(m * n)$ + +> Where $n$ is the size of the array $ideas$ and $m$ is the average length of the strings. \ No newline at end of file diff --git a/articles/number-of-submatrices-that-sum-to-target.md b/articles/number-of-submatrices-that-sum-to-target.md new file mode 100644 index 000000000..0fe84feca --- /dev/null +++ b/articles/number-of-submatrices-that-sum-to-target.md @@ -0,0 +1,549 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def numSubmatrixSumTarget(self, matrix: List[List[int]], target: int) -> int: + ROWS, COLS = len(matrix), len(matrix[0]) + res = 0 + + for r1 in range(ROWS): + for r2 in range(r1, ROWS): + for c1 in range(COLS): + for c2 in range(c1, COLS): + subSum = 0 + for r in range(r1, r2 + 1): + for c in range(c1, c2 + 1): + subSum += matrix[r][c] + + if subSum == target: + res += 1 + + return res +``` + +```java +public class Solution { + public int numSubmatrixSumTarget(int[][] matrix, int target) { + int ROWS = matrix.length, COLS = matrix[0].length; + int res = 0; + + for (int r1 = 0; r1 < ROWS; r1++) { + for (int r2 = r1; r2 < ROWS; r2++) { + for (int c1 = 0; c1 < COLS; c1++) { + for (int c2 = c1; c2 < COLS; c2++) { + int subSum = 0; + for (int r = r1; r <= r2; r++) { + for (int c = c1; c <= c2; c++) { + subSum += matrix[r][c]; + } + } + if (subSum == target) { + res++; + } + } + } + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int numSubmatrixSumTarget(vector>& matrix, int target) { + int ROWS = matrix.size(), COLS = matrix[0].size(); + int res = 0; + + for (int r1 = 0; r1 < ROWS; r1++) { + for (int r2 = r1; r2 < ROWS; r2++) { + for (int c1 = 0; c1 < COLS; c1++) { + for (int c2 = c1; c2 < COLS; c2++) { + int subSum = 0; + for (int r = r1; r <= r2; r++) { + for (int c = c1; c <= c2; c++) { + subSum += matrix[r][c]; + } + } + if (subSum == target) { + res++; + } + } + } + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} matrix + * @param {number} target + * @return {number} + */ + numSubmatrixSumTarget(matrix, target) { + const ROWS = matrix.length, COLS = matrix[0].length; + let res = 0; + + for (let r1 = 0; r1 < ROWS; r1++) { + for (let r2 = r1; r2 < ROWS; r2++) { + for (let c1 = 0; c1 < COLS; c1++) { + for (let c2 = c1; c2 < COLS; c2++) { + let subSum = 0; + for (let r = r1; r <= r2; r++) { + for (let c = c1; c <= c2; c++) { + subSum += matrix[r][c]; + } + } + if (subSum === target) { + res++; + } + } + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m ^ 3 * n ^ 3)$ +* Space complexity: $O(1)$ extra space. + +> Where $m$ is the number of rows and $n$ is the number of columns of the given matrix. + +--- + +## 2. Two Dimensional Prefix Sum + +::tabs-start + +```python +class Solution: + def numSubmatrixSumTarget(self, matrix: List[List[int]], target: int) -> int: + ROWS, COLS = len(matrix), len(matrix[0]) + sub_sum = [[0] * COLS for _ in range(ROWS)] + + for r in range(ROWS): + for c in range(COLS): + top = sub_sum[r - 1][c] if r > 0 else 0 + left = sub_sum[r][c - 1] if c > 0 else 0 + top_left = sub_sum[r - 1][c - 1] if min(r, c) > 0 else 0 + sub_sum[r][c] = matrix[r][c] + top + left - top_left + + res = 0 + for r1 in range(ROWS): + for r2 in range(r1, ROWS): + for c1 in range(COLS): + for c2 in range(c1, COLS): + top = sub_sum[r1 - 1][c2] if r1 > 0 else 0 + left = sub_sum[r2][c1 - 1] if c1 > 0 else 0 + top_left = sub_sum[r1 - 1][c1 - 1] if min(r1, c1) > 0 else 0 + cur_sum = sub_sum[r2][c2] - top - left + top_left + if cur_sum == target: + res += 1 + return res +``` + +```java +public class Solution { + public int numSubmatrixSumTarget(int[][] matrix, int target) { + int ROWS = matrix.length, COLS = matrix[0].length; + int[][] subSum = new int[ROWS][COLS]; + + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + int top = (r > 0) ? subSum[r - 1][c] : 0; + int left = (c > 0) ? subSum[r][c - 1] : 0; + int topLeft = (Math.min(r, c) > 0) ? subSum[r - 1][c - 1] : 0; + subSum[r][c] = matrix[r][c] + top + left - topLeft; + } + } + + int res = 0; + for (int r1 = 0; r1 < ROWS; r1++) { + for (int r2 = r1; r2 < ROWS; r2++) { + for (int c1 = 0; c1 < COLS; c1++) { + for (int c2 = c1; c2 < COLS; c2++) { + int top = (r1 > 0) ? subSum[r1 - 1][c2] : 0; + int left = (c1 > 0) ? subSum[r2][c1 - 1] : 0; + int topLeft = (Math.min(r1, c1) > 0) ? subSum[r1 - 1][c1 - 1] : 0; + int curSum = subSum[r2][c2] - top - left + topLeft; + if (curSum == target) { + res++; + } + } + } + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int numSubmatrixSumTarget(vector>& matrix, int target) { + int ROWS = matrix.size(), COLS = matrix[0].size(); + vector> subSum(ROWS, vector(COLS, 0)); + + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + int top = (r > 0) ? subSum[r - 1][c] : 0; + int left = (c > 0) ? subSum[r][c - 1] : 0; + int topLeft = (min(r, c) > 0) ? subSum[r - 1][c - 1] : 0; + subSum[r][c] = matrix[r][c] + top + left - topLeft; + } + } + + int res = 0; + for (int r1 = 0; r1 < ROWS; r1++) { + for (int r2 = r1; r2 < ROWS; r2++) { + for (int c1 = 0; c1 < COLS; c1++) { + for (int c2 = c1; c2 < COLS; c2++) { + int top = (r1 > 0) ? subSum[r1 - 1][c2] : 0; + int left = (c1 > 0) ? subSum[r2][c1 - 1] : 0; + int topLeft = (min(r1, c1) > 0) ? subSum[r1 - 1][c1 - 1] : 0; + int curSum = subSum[r2][c2] - top - left + topLeft; + if (curSum == target) { + res++; + } + } + } + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} matrix + * @param {number} target + * @return {number} + */ + numSubmatrixSumTarget(matrix, target) { + const ROWS = matrix.length, COLS = matrix[0].length; + const subSum = Array.from({ length: ROWS }, () => Array(COLS).fill(0)); + + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + let top = r > 0 ? subSum[r - 1][c] : 0; + let left = c > 0 ? subSum[r][c - 1] : 0; + let topLeft = Math.min(r, c) > 0 ? subSum[r - 1][c - 1] : 0; + subSum[r][c] = matrix[r][c] + top + left - topLeft; + } + } + + let res = 0; + for (let r1 = 0; r1 < ROWS; r1++) { + for (let r2 = r1; r2 < ROWS; r2++) { + for (let c1 = 0; c1 < COLS; c1++) { + for (let c2 = c1; c2 < COLS; c2++) { + let top = r1 > 0 ? subSum[r1 - 1][c2] : 0; + let left = c1 > 0 ? subSum[r2][c1 - 1] : 0; + let topLeft = Math.min(r1, c1) > 0 ? subSum[r1 - 1][c1 - 1] : 0; + let curSum = subSum[r2][c2] - top - left + topLeft; + if (curSum === target) { + res++; + } + } + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m ^ 2 * n ^ 2)$ +* Space complexity: $O(m * n)$ + +> Where $m$ is the number of rows and $n$ is the number of columns of the given matrix. + +--- + +## 3. Horizontal 1D Prefix Sum + +::tabs-start + +```python +class Solution: + def numSubmatrixSumTarget(self, matrix: List[List[int]], target: int) -> int: + ROWS, COLS = len(matrix), len(matrix[0]) + sub_sum = [[0] * COLS for _ in range(ROWS)] + + for r in range(ROWS): + for c in range(COLS): + top = sub_sum[r - 1][c] if r > 0 else 0 + left = sub_sum[r][c - 1] if c > 0 else 0 + top_left = sub_sum[r - 1][c - 1] if min(r, c) > 0 else 0 + sub_sum[r][c] = matrix[r][c] + top + left - top_left + + res = 0 + for r1 in range(ROWS): + for r2 in range(r1, ROWS): + count = defaultdict(int) + count[0] = 1 + for c in range(COLS): + cur_sum = sub_sum[r2][c] - (sub_sum[r1 - 1][c] if r1 > 0 else 0) + res += count[cur_sum - target] + count[cur_sum] += 1 + + return res +``` + +```java +public class Solution { + public int numSubmatrixSumTarget(int[][] matrix, int target) { + int ROWS = matrix.length, COLS = matrix[0].length; + int[][] subSum = new int[ROWS][COLS]; + + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + int top = (r > 0) ? subSum[r - 1][c] : 0; + int left = (c > 0) ? subSum[r][c - 1] : 0; + int topLeft = (Math.min(r, c) > 0) ? subSum[r - 1][c - 1] : 0; + subSum[r][c] = matrix[r][c] + top + left - topLeft; + } + } + + int res = 0; + for (int r1 = 0; r1 < ROWS; r1++) { + for (int r2 = r1; r2 < ROWS; r2++) { + Map count = new HashMap<>(); + count.put(0, 1); + for (int c = 0; c < COLS; c++) { + int curSum = subSum[r2][c] - (r1 > 0 ? subSum[r1 - 1][c] : 0); + res += count.getOrDefault(curSum - target, 0); + count.put(curSum, count.getOrDefault(curSum, 0) + 1); + } + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int numSubmatrixSumTarget(vector>& matrix, int target) { + int ROWS = matrix.size(), COLS = matrix[0].size(); + vector> subSum(ROWS, vector(COLS, 0)); + + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + int top = (r > 0) ? subSum[r - 1][c] : 0; + int left = (c > 0) ? subSum[r][c - 1] : 0; + int topLeft = (min(r, c) > 0) ? subSum[r - 1][c - 1] : 0; + subSum[r][c] = matrix[r][c] + top + left - topLeft; + } + } + + int res = 0; + for (int r1 = 0; r1 < ROWS; r1++) { + for (int r2 = r1; r2 < ROWS; r2++) { + unordered_map count; + count[0] = 1; + for (int c = 0; c < COLS; c++) { + int curSum = subSum[r2][c] - (r1 > 0 ? subSum[r1 - 1][c] : 0); + res += count[curSum - target]; + count[curSum]++; + } + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} matrix + * @param {number} target + * @return {number} + */ + numSubmatrixSumTarget(matrix, target) { + let ROWS = matrix.length, COLS = matrix[0].length; + let subSum = Array.from({ length: ROWS }, () => Array(COLS).fill(0)); + + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + let top = r > 0 ? subSum[r - 1][c] : 0; + let left = c > 0 ? subSum[r][c - 1] : 0; + let topLeft = Math.min(r, c) > 0 ? subSum[r - 1][c - 1] : 0; + subSum[r][c] = matrix[r][c] + top + left - topLeft; + } + } + + let res = 0; + for (let r1 = 0; r1 < ROWS; r1++) { + for (let r2 = r1; r2 < ROWS; r2++) { + let count = new Map(); + count.set(0, 1); + for (let c = 0; c < COLS; c++) { + let curSum = subSum[r2][c] - (r1 > 0 ? subSum[r1 - 1][c] : 0); + res += count.get(curSum - target) || 0; + count.set(curSum, (count.get(curSum) || 0) + 1); + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m ^ 2 * n)$ +* Space complexity: $O(m * n)$ + +> Where $m$ is the number of rows and $n$ is the number of columns of the given matrix. + +--- + +## 4. Vertical 1D Prefix Sum + +::tabs-start + +```python +class Solution: + def numSubmatrixSumTarget(self, matrix: List[List[int]], target: int) -> int: + ROWS, COLS = len(matrix), len(matrix[0]) + res = 0 + + for c1 in range(COLS): + row_prefix = [0] * ROWS + for c2 in range(c1, COLS): + for r in range(ROWS): + row_prefix[r] += matrix[r][c2] + + count = defaultdict(int) + count[0] = 1 + cur_sum = 0 + for r in range(ROWS): + cur_sum += row_prefix[r] + res += count[cur_sum - target] + count[cur_sum] += 1 + + return res +``` + +```java +public class Solution { + public int numSubmatrixSumTarget(int[][] matrix, int target) { + int ROWS = matrix.length, COLS = matrix[0].length, res = 0; + + for (int c1 = 0; c1 < COLS; c1++) { + int[] rowPrefix = new int[ROWS]; + for (int c2 = c1; c2 < COLS; c2++) { + for (int r = 0; r < ROWS; r++) { + rowPrefix[r] += matrix[r][c2]; + } + + Map count = new HashMap<>(); + count.put(0, 1); + int curSum = 0; + + for (int r = 0; r < ROWS; r++) { + curSum += rowPrefix[r]; + res += count.getOrDefault(curSum - target, 0); + count.put(curSum, count.getOrDefault(curSum, 0) + 1); + } + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int numSubmatrixSumTarget(vector>& matrix, int target) { + int ROWS = matrix.size(), COLS = matrix[0].size(), res = 0; + + for (int c1 = 0; c1 < COLS; c1++) { + vector rowPrefix(ROWS, 0); + for (int c2 = c1; c2 < COLS; c2++) { + for (int r = 0; r < ROWS; r++) { + rowPrefix[r] += matrix[r][c2]; + } + + unordered_map count; + count[0] = 1; + int curSum = 0; + for (int r = 0; r < ROWS; r++) { + curSum += rowPrefix[r]; + res += count[curSum - target]; + count[curSum]++; + } + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} matrix + * @param {number} target + * @return {number} + */ + numSubmatrixSumTarget(matrix, target) { + let ROWS = matrix.length, COLS = matrix[0].length, res = 0; + + for (let c1 = 0; c1 < COLS; c1++) { + let rowPrefix = new Array(ROWS).fill(0); + for (let c2 = c1; c2 < COLS; c2++) { + for (let r = 0; r < ROWS; r++) { + rowPrefix[r] += matrix[r][c2]; + } + + let count = new Map(); + count.set(0, 1); + let curSum = 0; + + for (let r = 0; r < ROWS; r++) { + curSum += rowPrefix[r]; + res += count.get(curSum - target) || 0; + count.set(curSum, (count.get(curSum) || 0) + 1); + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * n ^ 2)$ +* Space complexity: $O(m)$ + +> Where $m$ is the number of rows and $n$ is the number of columns of the given matrix. \ No newline at end of file diff --git a/articles/text-justification.md b/articles/text-justification.md new file mode 100644 index 000000000..fb48dcabe --- /dev/null +++ b/articles/text-justification.md @@ -0,0 +1,181 @@ +## 1. Iteration + +::tabs-start + +```python +class Solution: + def fullJustify(self, words: List[str], maxWidth: int) -> List[str]: + res = [] + line, length = [], 0 + i = 0 + + while i < len(words): + if length + len(words[i]) + len(line) <= maxWidth: + line.append(words[i]) + length += len(words[i]) + i += 1 + else: + # Line complete + extra_space = maxWidth - length + remainder = extra_space % max(1, (len(line) - 1)) + space = extra_space // max(1, (len(line) - 1)) + for j in range(max(1, len(line) - 1)): + line[j] += " " * space + if remainder: + line[j] += " " + remainder -= 1 + res.append("".join(line)) + line, length = [], 0 + + # Handling last line + last_line = " ".join(line) + trail_space = maxWidth - len(last_line) + res.append(last_line + " " * trail_space) + return res +``` + +```java +public class Solution { + public List fullJustify(String[] words, int maxWidth) { + List res = new ArrayList<>(); + List line = new ArrayList<>(); + int length = 0, i = 0; + + while (i < words.length) { + // If the current word can fit in the line + if (length + words[i].length() + line.size() <= maxWidth) { + line.add(words[i]); + length += words[i].length(); + i++; + } else { + // Line complete + int extra_space = maxWidth - length; + int remainder = extra_space % Math.max(1, (line.size() - 1)); + int space = extra_space / Math.max(1, (line.size() - 1)); + + for (int j = 0; j < Math.max(1, line.size() - 1); j++) { + line.set(j, line.get(j) + " ".repeat(space)); + if (remainder > 0) { + line.set(j, line.get(j) + " "); + remainder--; + } + } + + res.add(String.join("", line)); + line.clear(); + length = 0; + } + } + + // Handling last line + String last_line = String.join(" ", line); + int trail_space = maxWidth - last_line.length(); + res.add(last_line + " ".repeat(trail_space)); + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector fullJustify(vector& words, int maxWidth) { + vector res; + vector line; + int length = 0, i = 0; + + while (i < words.size()) { + if (length + words[i].size() + line.size() <= maxWidth) { + line.push_back(words[i]); + length += words[i].size(); + i++; + } else { + // Line complete + int extra_space = maxWidth - length; + int remainder = extra_space % max(1, (int)(line.size() - 1)); + int space = extra_space / max(1, (int)(line.size() - 1)); + + for (int j = 0; j < max(1, (int)line.size() - 1); j++) { + line[j] += string(space, ' '); + if (remainder > 0) { + line[j] += " "; + remainder--; + } + } + + string justified_line = accumulate(line.begin(), line.end(), string()); + res.push_back(justified_line); + line.clear(); + length = 0; + } + } + + // Handling last line + string last_line = accumulate(line.begin(), line.end(), string(), + [](string a, string b) { + return a.empty() ? b : a + " " + b; + }); + int trail_space = maxWidth - last_line.size(); + last_line += string(trail_space, ' '); + res.push_back(last_line); + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} words + * @param {number} maxWidth + * @return {string[]} + */ + fullJustify(words, maxWidth) { + let res = []; + let line = [], length = 0, i = 0; + + while (i < words.length) { + if (length + words[i].length + line.length <= maxWidth) { + line.push(words[i]); + length += words[i].length; + i++; + } else { + // Line complete + let extra_space = maxWidth - length; + let remainder = extra_space % Math.max(1, line.length - 1); + let space = Math.floor(extra_space / Math.max(1, line.length - 1)); + + for (let j = 0; j < Math.max(1, line.length - 1); j++) { + line[j] += " ".repeat(space); + if (remainder > 0) { + line[j] += " "; + remainder--; + } + } + + res.push(line.join("")); + line = []; + length = 0; + } + } + + // Handling last line + let last_line = line.join(" "); + let trail_space = maxWidth - last_line.length; + res.push(last_line + " ".repeat(trail_space)); + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * m)$ +* Space complexity: $O(n * m)$ + +> Where $n$ is the number of words and $m$ is the average length of the words. \ No newline at end of file From 3a66f0820a308bf11c8d9ed606e5865d2796d6ed Mon Sep 17 00:00:00 2001 From: Sri Hari <94112314+Srihari2222@users.noreply.github.com> Date: Fri, 28 Feb 2025 09:30:41 +0530 Subject: [PATCH 03/12] Sri Hari: Batch-5/Neetcode-ALL/Added-articles (#3854) * Batch-5/Neetcode-ALL/Added-articles * Batch-5/Neetcode-ALL/Added-articles * Batch-5/Neetcode-ALL/Added-articles --- articles/constrained-subsequence-sum.md | 701 ++++++++++++++ ...nd-the-kth-largest-integer-in-the-array.md | 543 +++++++++++ ...-valid-obstacle-course-at-each-position.md | 387 ++++++++ ...ber-of-unique-integers-after-k-removals.md | 343 +++++++ articles/maximum-performance-of-a-team.md | 238 +++++ articles/maximum-profit-in-job-scheduling.md | 655 ++++++++++++++ articles/maximum-subsequence-score.md | 412 +++++++++ articles/minimize-deviation-in-array.md | 468 ++++++++++ articles/minimum-cost-to-hire-k-workers.md | 144 +++ articles/number-of-flowers-in-full-bloom.md | 675 ++++++++++++++ articles/paint-house.md | 445 +++++++++ articles/process-tasks-using-servers.md | 501 ++++++++++ articles/seat-reservation-manager.md | 407 +++++++++ articles/student-attendance-record-ii.md | 854 ++++++++++++++++++ 14 files changed, 6773 insertions(+) create mode 100644 articles/constrained-subsequence-sum.md create mode 100644 articles/find-the-kth-largest-integer-in-the-array.md create mode 100644 articles/find-the-longest-valid-obstacle-course-at-each-position.md create mode 100644 articles/least-number-of-unique-integers-after-k-removals.md create mode 100644 articles/maximum-performance-of-a-team.md create mode 100644 articles/maximum-profit-in-job-scheduling.md create mode 100644 articles/maximum-subsequence-score.md create mode 100644 articles/minimize-deviation-in-array.md create mode 100644 articles/minimum-cost-to-hire-k-workers.md create mode 100644 articles/number-of-flowers-in-full-bloom.md create mode 100644 articles/paint-house.md create mode 100644 articles/process-tasks-using-servers.md create mode 100644 articles/seat-reservation-manager.md create mode 100644 articles/student-attendance-record-ii.md diff --git a/articles/constrained-subsequence-sum.md b/articles/constrained-subsequence-sum.md new file mode 100644 index 000000000..1c04624df --- /dev/null +++ b/articles/constrained-subsequence-sum.md @@ -0,0 +1,701 @@ +## 1. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def constrainedSubsetSum(self, nums: List[int], k: int) -> int: + memo = [None] * len(nums) + + def dfs(i): + if memo[i] != None: + return memo[i] + + res = nums[i] + for j in range(i + 1, len(nums)): + if j - i > k: + break + res = max(res, nums[i] + dfs(j)) + + memo[i] = res + return res + + ans = float('-inf') + for i in range(len(nums)): + ans = max(ans, dfs(i)) + return ans +``` + +```java +public class Solution { + private int[] nums; + private Integer[] memo; + private int k; + + public int constrainedSubsetSum(int[] nums, int k) { + this.nums = nums; + this.memo = new Integer[nums.length]; + this.k = k; + + int ans = Integer.MIN_VALUE; + for (int i = 0; i < nums.length; i++) { + ans = Math.max(ans, dfs(i)); + } + return ans; + } + + private int dfs(int i) { + if (memo[i] != null) { + return memo[i]; + } + + int res = nums[i]; + for (int j = i + 1; j < nums.length && j - i <= k; j++) { + res = Math.max(res, nums[i] + dfs(j)); + } + + memo[i] = res; + return res; + } +} +``` + +```cpp +class Solution { +public: + int constrainedSubsetSum(vector& nums, int k) { + vector memo(nums.size(), INT_MIN); + int ans = INT_MIN; + for (int i = 0; i < nums.size(); i++) { + ans = max(ans, dfs(nums, memo, k, i)); + } + return ans; + } + +private: + int dfs(vector& nums, vector& memo, int k, int i) { + if (memo[i] != INT_MIN) { + return memo[i]; + } + + int res = nums[i]; + for (int j = i + 1; j < nums.size() && j - i <= k; j++) { + res = max(res, nums[i] + dfs(nums, memo, k, j)); + } + + memo[i] = res; + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + constrainedSubsetSum(nums, k) { + const memo = new Array(nums.length).fill(null); + + const dfs = (i) => { + if (memo[i] !== null) { + return memo[i]; + } + + let res = nums[i]; + for (let j = i + 1; j < nums.length && j - i <= k; j++) { + res = Math.max(res, nums[i] + dfs(j)); + } + + memo[i] = res; + return res; + }; + + let ans = -Infinity; + for (let i = 0; i < nums.length; i++) { + ans = Math.max(ans, dfs(i)); + } + return ans; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * k)$ +* Space complexity: $O(n)$ + +--- + +## 2. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def constrainedSubsetSum(self, nums: List[int], k: int) -> int: + dp = [num for num in nums] + + for i in range(1, len(nums)): + for j in range(max(0, i - k), i): + dp[i] = max(dp[i], nums[i] + dp[j]) + + return max(dp) +``` + +```java +public class Solution { + public int constrainedSubsetSum(int[] nums, int k) { + int n = nums.length; + int[] dp = new int[n]; + System.arraycopy(nums, 0, dp, 0, n); + + for (int i = 1; i < n; i++) { + for (int j = Math.max(0, i - k); j < i; j++) { + dp[i] = Math.max(dp[i], nums[i] + dp[j]); + } + } + + int res = Integer.MIN_VALUE; + for (int val : dp) { + res = Math.max(res, val); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int constrainedSubsetSum(vector& nums, int k) { + int n = nums.size(); + vector dp(nums.begin(), nums.end()); + + for (int i = 1; i < n; i++) { + for (int j = max(0, i - k); j < i; j++) { + dp[i] = max(dp[i], nums[i] + dp[j]); + } + } + + return *max_element(dp.begin(), dp.end()); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + constrainedSubsetSum(nums, k) { + const n = nums.length; + const dp = [...nums]; + + for (let i = 1; i < n; i++) { + for (let j = Math.max(0, i - k); j < i; j++) { + dp[i] = Math.max(dp[i], nums[i] + dp[j]); + } + } + + return Math.max(...dp); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * k)$ +* Space complexity: $O(n)$ + +--- + +## 3. Dynamic Programming + Segment Tree + +::tabs-start + +```python +class SegmentTree: + def __init__(self, N): + self.n = N + while (self.n & (self.n - 1)) != 0: + self.n += 1 + self.tree = [float('-inf')] * (2 * self.n) + + def update(self, i, val): + i += self.n + self.tree[i] = val + while i > 1: + i >>= 1 + self.tree[i] = max(self.tree[i << 1], self.tree[i << 1 | 1]) + + def query(self, l, r): + res = float('-inf') + l += self.n + r += self.n + 1 + while l < r: + if l & 1: + res = max(res, self.tree[l]) + l += 1 + if r & 1: + r -= 1 + res = max(res, self.tree[r]) + l >>= 1 + r >>= 1 + return max(0, res) + +class Solution: + def constrainedSubsetSum(self, nums: List[int], k: int) -> int: + n = len(nums) + maxSegTree = SegmentTree(n) + maxSegTree.update(0, nums[0]) + res = nums[0] + + for i in range(1, n): + cur = nums[i] + maxSegTree.query(max(0, i - k), i - 1) + maxSegTree.update(i, cur) + res = max(res, cur) + + return res +``` + +```java +class SegmentTree { + int n; + int[] tree; + + public SegmentTree(int N) { + this.n = N; + while ((this.n & (this.n - 1)) != 0) { + this.n++; + } + tree = new int[2 * this.n]; + for (int i = 0; i < 2 * this.n; i++) { + tree[i] = Integer.MIN_VALUE; + } + } + + public void update(int i, int val) { + i += n; + tree[i] = val; + while (i > 1) { + i >>= 1; + tree[i] = Math.max(tree[i << 1], tree[(i << 1) | 1]); + } + } + + public int query(int l, int r) { + int res = Integer.MIN_VALUE; + l += n; + r += n + 1; + while (l < r) { + if ((l & 1) == 1) { + res = Math.max(res, tree[l]); + l++; + } + if ((r & 1) == 1) { + r--; + res = Math.max(res, tree[r]); + } + l >>= 1; + r >>= 1; + } + return Math.max(0, res); + } +} + +public class Solution { + public int constrainedSubsetSum(int[] nums, int k) { + int n = nums.length; + SegmentTree maxSegTree = new SegmentTree(n); + maxSegTree.update(0, nums[0]); + int res = nums[0]; + + for (int i = 1; i < n; i++) { + int cur = nums[i] + maxSegTree.query(Math.max(0, i - k), i - 1); + maxSegTree.update(i, cur); + res = Math.max(res, cur); + } + + return res; + } +} +``` + +```cpp +class SegmentTree { +public: + int n; + vector tree; + + SegmentTree(int N) { + n = N; + while ((n & (n - 1)) != 0) { + n++; + } + tree.assign(2 * n, INT_MIN); + } + + void update(int i, int val) { + i += n; + tree[i] = val; + while (i > 1) { + i >>= 1; + tree[i] = max(tree[i << 1], tree[i << 1 | 1]); + } + } + + int query(int l, int r) { + int res = INT_MIN; + l += n; + r += n + 1; + while (l < r) { + if (l & 1) { + res = max(res, tree[l]); + l++; + } + if (r & 1) { + r--; + res = max(res, tree[r]); + } + l >>= 1; + r >>= 1; + } + return max(0, res); + } +}; + +class Solution { +public: + int constrainedSubsetSum(vector& nums, int k) { + int n = nums.size(); + SegmentTree maxSegTree(n); + maxSegTree.update(0, nums[0]); + int res = nums[0]; + + for (int i = 1; i < n; i++) { + int cur = nums[i] + maxSegTree.query(max(0, i - k), i - 1); + maxSegTree.update(i, cur); + res = max(res, cur); + } + + return res; + } +}; +``` + +```javascript +class SegmentTree { + /** + * @constructor + * @param {number} N + */ + constructor(N) { + this.n = N; + while ((this.n & (this.n - 1)) !== 0) { + this.n++; + } + this.tree = new Array(2 * this.n).fill(-Infinity); + } + + /** + * @param {number} i + * @param {number} val + * @return {void} + */ + update(i, val) { + i += this.n; + this.tree[i] = val; + while (i > 1) { + i >>= 1; + this.tree[i] = Math.max(this.tree[i << 1], this.tree[i << 1 | 1]); + } + } + + /** + * @param {number} l + * @param {number} r + * @return {number} + */ + query(l, r) { + let res = -Infinity; + l += this.n; + r += this.n + 1; + while (l < r) { + if (l & 1) { + res = Math.max(res, this.tree[l]); + l++; + } + if (r & 1) { + r--; + res = Math.max(res, this.tree[r]); + } + l >>= 1; + r >>= 1; + } + return Math.max(0, res); + } +} + +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + constrainedSubsetSum(nums, k) { + const n = nums.length; + const maxSegTree = new SegmentTree(n); + maxSegTree.update(0, nums[0]); + let res = nums[0]; + + for (let i = 1; i < n; i++) { + let cur = nums[i] + maxSegTree.query(Math.max(0, i - k), i - 1); + maxSegTree.update(i, cur); + res = Math.max(res, cur); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(n)$ + +--- + +## 4. Max-Heap + +::tabs-start + +```python +class Solution: + def constrainedSubsetSum(self, nums: List[int], k: int) -> int: + res = nums[0] + max_heap = [(-nums[0], 0)] # max_sum, index + + for i in range(1, len(nums)): + while i - max_heap[0][1] > k: + heapq.heappop(max_heap) + + cur_max = max(nums[i], nums[i] - max_heap[0][0]) + res = max(res, cur_max) + heapq.heappush(max_heap, (-cur_max, i)) + + return res +``` + +```java +public class Solution { + public int constrainedSubsetSum(int[] nums, int k) { + int res = nums[0]; + PriorityQueue maxHeap = new PriorityQueue<>( + (a, b) -> b[0] - a[0] // max_sum, index + ); + maxHeap.offer(new int[]{nums[0], 0}); + + for (int i = 1; i < nums.length; i++) { + while (i - maxHeap.peek()[1] > k) { + maxHeap.poll(); + } + + int curMax = Math.max(nums[i], nums[i] + maxHeap.peek()[0]); + res = Math.max(res, curMax); + maxHeap.offer(new int[]{curMax, i}); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int constrainedSubsetSum(vector& nums, int k) { + int res = nums[0]; + priority_queue> maxHeap; // max_sum, index + maxHeap.emplace(nums[0], 0); + + for (int i = 1; i < nums.size(); i++) { + while (i - maxHeap.top().second > k) { + maxHeap.pop(); + } + + int curMax = max(nums[i], nums[i] + maxHeap.top().first); + res = max(res, curMax); + maxHeap.emplace(curMax, i); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + constrainedSubsetSum(nums, k) { + let res = nums[0]; + const maxHeap = new PriorityQueue( + (a, b) => b[0] - a[0] // max_sum, index + ); + maxHeap.enqueue([nums[0], 0]); + + for (let i = 1; i < nums.length; i++) { + while (i - maxHeap.front()[1] > k) { + maxHeap.dequeue(); + } + + let curMax = Math.max(nums[i], nums[i] + maxHeap.front()[0]); + res = Math.max(res, curMax); + maxHeap.enqueue([curMax, i]); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(n)$ + +--- + +## 5. Monotonic Deque + +::tabs-start + +```python +class Solution: + def constrainedSubsetSum(self, nums: List[int], k: int) -> int: + n = len(nums) + dq = deque([(0, nums[0])]) + res = nums[0] + + for i in range(1, n): + if dq and dq[0][0] < i - k: + dq.popleft() + + cur = max(0, dq[0][1]) + nums[i] + while dq and cur > dq[-1][1]: + dq.pop() + + dq.append((i, cur)) + res = max(res, cur) + + return res +``` + +```java +public class Solution { + public int constrainedSubsetSum(int[] nums, int k) { + int n = nums.length; + Deque dq = new ArrayDeque<>(); + dq.offer(new int[]{0, nums[0]}); + int res = nums[0]; + + for (int i = 1; i < n; i++) { + if (!dq.isEmpty() && dq.peekFirst()[0] < i - k) { + dq.pollFirst(); + } + + int cur = Math.max(0, dq.peekFirst()[1]) + nums[i]; + while (!dq.isEmpty() && cur > dq.peekLast()[1]) { + dq.pollLast(); + } + + dq.offer(new int[]{i, cur}); + res = Math.max(res, cur); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int constrainedSubsetSum(vector& nums, int k) { + int n = nums.size(); + deque> dq{{0, nums[0]}}; + int res = nums[0]; + + for (int i = 1; i < n; i++) { + if (!dq.empty() && dq.front().first < i - k) { + dq.pop_front(); + } + + int cur = max(0, dq.front().second) + nums[i]; + while (!dq.empty() && cur > dq.back().second) { + dq.pop_back(); + } + + dq.emplace_back(i, cur); + res = max(res, cur); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + constrainedSubsetSum(nums, k) { + const n = nums.length; + const dq = new Deque([[0, nums[0]]]); + let res = nums[0]; + + for (let i = 1; i < n; i++) { + if (!dq.isEmpty() && dq.front()[0] < i - k) { + dq.popFront(); + } + + let cur = Math.max(0, dq.front()[1]) + nums[i]; + while (!dq.isEmpty() && cur > dq.back()[1]) { + dq.popBack(); + } + + dq.pushBack([i, cur]); + res = Math.max(res, cur); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(k)$ \ No newline at end of file diff --git a/articles/find-the-kth-largest-integer-in-the-array.md b/articles/find-the-kth-largest-integer-in-the-array.md new file mode 100644 index 000000000..ba70f2ed8 --- /dev/null +++ b/articles/find-the-kth-largest-integer-in-the-array.md @@ -0,0 +1,543 @@ +## 1. Sorting + +::tabs-start + +```python +class Solution: + def kthLargestNumber(self, nums: List[str], k: int) -> str: + return sorted(nums, key=lambda x: (len(x), x), reverse=True)[k - 1] +``` + +```java +public class Solution { + public String kthLargestNumber(String[] nums, int k) { + Arrays.sort(nums, + (a, b) -> a.length() == b.length() ? b.compareTo(a) : b.length() - a.length() + ); + return nums[k - 1]; + } +} +``` + +```cpp +class Solution { +public: + string kthLargestNumber(vector& nums, int k) { + sort(nums.begin(), nums.end(), [](const string& a, const string& b) { + return a.size() == b.size() ? a > b : a.size() > b.size(); + }); + return nums[k - 1]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} nums + * @param {number} k + * @return {string} + */ + kthLargestNumber(nums, k) { + nums.sort( + (a, b) => a.length === b.length ? b.localeCompare(a) : b.length - a.length + ); + return nums[k - 1]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * n \log n)$ +* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. + +> Where $n$ is the number of strings and $m$ is the average length of a string. + +--- + +## 2. Max-Heap + +::tabs-start + +```python +class Num: + def __init__(self, s: str): + self.s = s + + def __lt__(self, other: "Num") -> bool: + if len(self.s) != len(other.s): + return len(self.s) > len(other.s) + return self.s > other.s + +class Solution: + def kthLargestNumber(self, nums: List[str], k: int) -> str: + maxHeap = [Num(s) for s in nums] + heapq.heapify(maxHeap) + + for _ in range(k - 1): + heapq.heappop(maxHeap) + + return heapq.heappop(maxHeap).s +``` + +```java +public class Solution { + public String kthLargestNumber(String[] nums, int k) { + PriorityQueue maxHeap = new PriorityQueue<>((a, b) -> + a.length() == b.length() ? b.compareTo(a) : Integer.compare(b.length(), a.length()) + ); + + for (String num : nums) { + maxHeap.offer(num); + } + + while (--k > 0) { + maxHeap.poll(); + } + + return maxHeap.poll(); + } +} +``` + +```cpp +class Solution { +public: + string kthLargestNumber(vector& nums, int k) { + auto cmp = [](const string& a, const string& b) { + return a.size() == b.size() ? a < b : a.size() < b.size(); + }; + + priority_queue, decltype(cmp)> maxHeap(cmp); + + for (const string& num : nums) { + maxHeap.push(num); + } + + while (--k > 0) { + maxHeap.pop(); + } + + return maxHeap.top(); + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} nums + * @param {number} k + * @return {string} + */ + kthLargestNumber(nums, k) { + const maxHeap = new PriorityQueue( + (a, b) => a.length === b.length ? b.localeCompare(a) : b.length - a.length + ); + + for (const num of nums) { + maxHeap.enqueue(num); + } + + while (--k > 0) { + maxHeap.dequeue(); + } + + return maxHeap.dequeue(); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * (n + k) * \log n)$ +* Space complexity: $O(n)$ + +> Where $n$ is the number of strings and $m$ is the average length of a string. + +--- + +## 3. Min-Heap + +::tabs-start + +```python +class Num: + def __init__(self, s: str): + self.s = s + + def __lt__(self, other: "Num") -> bool: + if len(self.s) != len(other.s): + return len(self.s) < len(other.s) + return self.s < other.s + +class Solution: + def kthLargestNumber(self, nums: List[str], k: int) -> str: + minHeap = [] + for num in nums: + heapq.heappush(minHeap, Num(num)) + if len(minHeap) > k: + heapq.heappop(minHeap) + return minHeap[0].s +``` + +```java +public class Solution { + public String kthLargestNumber(String[] nums, int k) { + PriorityQueue minHeap = new PriorityQueue<>((a, b) -> + a.length() == b.length() ? a.compareTo(b) : Integer.compare(a.length(), b.length()) + ); + + for (String num : nums) { + minHeap.offer(num); + if (minHeap.size() > k) { + minHeap.poll(); + } + } + + return minHeap.peek(); + } +} +``` + +```cpp +class Solution { +public: + string kthLargestNumber(vector& nums, int k) { + auto cmp = [](const string& a, const string& b) { + return a.size() == b.size() ? a > b : a.size() > b.size(); + }; + + priority_queue, decltype(cmp)> minHeap(cmp); + + for (const string& num : nums) { + minHeap.push(num); + if (minHeap.size() > k) { + minHeap.pop(); + } + } + + return minHeap.top(); + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} nums + * @param {number} k + * @return {string} + */ + kthLargestNumber(nums, k) { + const minHeap = new PriorityQueue( + (a, b) => a.length === b.length ? a.localeCompare(b) : a.length - b.length + ); + + for (const num of nums) { + minHeap.enqueue(num); + if (minHeap.size() > k) { + minHeap.dequeue(); + } + } + + return minHeap.front(); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * n * \log k)$ +* Space complexity: $O(k)$ + +> Where $n$ is the number of strings and $m$ is the average length of a string. + +--- + +## 4. Quick Select + +::tabs-start + +```python +class Solution: + def greater(self, x: str, y: str) -> bool: + if len(x) != len(y): + return len(x) > len(y) + return x > y + + def less(self, x: str, y: str) -> bool: + if len(x) != len(y): + return len(x) < len(y) + return x < y + + def partition(self, nums: List[str], left: int, right: int) -> int: + mid = (left + right) >> 1 + nums[mid], nums[left + 1] = nums[left + 1], nums[mid] + + if self.less(nums[left], nums[right]): + nums[left], nums[right] = nums[right], nums[left] + if self.less(nums[left + 1], nums[right]): + nums[left + 1], nums[right] = nums[right], nums[left + 1] + if self.less(nums[left], nums[left + 1]): + nums[left], nums[left + 1] = nums[left + 1], nums[left] + + pivot = nums[left + 1] + i = left + 1 + j = right + + while True: + while True: + i += 1 + if not self.greater(nums[i], pivot): + break + while True: + j -= 1 + if not self.less(nums[j], pivot): + break + if i > j: + break + nums[i], nums[j] = nums[j], nums[i] + + nums[left + 1], nums[j] = nums[j], nums[left + 1] + return j + + def quickSelect(self, nums: List[str], k: int) -> str: + left = 0 + right = len(nums) - 1 + + while True: + if right <= left + 1: + if right == left + 1 and self.greater(nums[right], nums[left]): + nums[left], nums[right] = nums[right], nums[left] + return nums[k] + + j = self.partition(nums, left, right) + if j >= k: + right = j - 1 + if j <= k: + left = j + 1 + + def kthLargestNumber(self, nums: List[str], k: int) -> str: + return self.quickSelect(nums, k - 1) +``` + +```java +public class Solution { + public String kthLargestNumber(String[] nums, int k) { + return quickSelect(nums, k - 1); + } + + private boolean greater(String x, String y) { + if (x.length() != y.length()) { + return x.length() > y.length(); + } + return x.compareTo(y) > 0; + } + + private boolean less(String x, String y) { + if (x.length() != y.length()) { + return x.length() < y.length(); + } + return x.compareTo(y) < 0; + } + + private int partition(String[] nums, int left, int right) { + int mid = (left + right) >> 1; + swap(nums, mid, left + 1); + + if (less(nums[left], nums[right])) { + swap(nums, left, right); + } + if (less(nums[left + 1], nums[right])) { + swap(nums, left + 1, right); + } + if (less(nums[left], nums[left + 1])) { + swap(nums, left, left + 1); + } + + String pivot = nums[left + 1]; + int i = left + 1, j = right; + + while (true) { + while (greater(nums[++i], pivot)); + while (less(nums[--j], pivot)); + if (i > j) break; + swap(nums, i, j); + } + + swap(nums, left + 1, j); + return j; + } + + private String quickSelect(String[] nums, int k) { + int left = 0, right = nums.length - 1; + + while (true) { + if (right <= left + 1) { + if (right == left + 1 && greater(nums[right], nums[left])) { + swap(nums, left, right); + } + return nums[k]; + } + + int j = partition(nums, left, right); + if (j >= k) { + right = j - 1; + } + if (j <= k) { + left = j + 1; + } + } + } + + private void swap(String[] nums, int i, int j) { + String temp = nums[i]; + nums[i] = nums[j]; + nums[j] = temp; + } +} +``` + +```cpp +class Solution { +public: + string kthLargestNumber(vector& nums, int k) { + return quickSelect(nums, k - 1); + } + +private: + bool greater(const string& x, const string& y) { + if (x.size() != y.size()) { + return x.size() > y.size(); + } + return x > y; + } + + bool less(const string& x, const string& y) { + if (x.size() != y.size()) { + return x.size() < y.size(); + } + return x < y; + } + + int partition(vector& nums, int left, int right) { + int mid = (left + right) >> 1; + swap(nums[mid], nums[left + 1]); + + if (less(nums[left], nums[right])) { + swap(nums[left], nums[right]); + } + if (less(nums[left + 1], nums[right])) { + swap(nums[left + 1], nums[right]); + } + if (less(nums[left], nums[left + 1])) { + swap(nums[left], nums[left + 1]); + } + + string pivot = nums[left + 1]; + int i = left + 1, j = right; + + while (true) { + while (greater(nums[++i], pivot)); + while (less(nums[--j], pivot)); + if (i > j) break; + swap(nums[i], nums[j]); + } + + swap(nums[left + 1], nums[j]); + return j; + } + + string quickSelect(vector& nums, int k) { + int left = 0, right = nums.size() - 1; + + while (true) { + if (right <= left + 1) { + if (right == left + 1 && greater(nums[right], nums[left])) { + swap(nums[left], nums[right]); + } + return nums[k]; + } + + int j = partition(nums, left, right); + if (j >= k) { + right = j - 1; + } + if (j <= k) { + left = j + 1; + } + } + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} nums + * @param {number} k + * @return {string} + */ + kthLargestNumber(nums, k) { + const greater = (x, y) => x.length !== y.length ? x.length > y.length : x > y; + const less = (x, y) => x.length !== y.length ? x.length < y.length : x < y; + const swap = (arr, i, j) => [arr[i], arr[j]] = [arr[j], arr[i]]; + + const partition = (nums, left, right) => { + const mid = Math.floor((left + right) / 2); + swap(nums, mid, left + 1); + + if (less(nums[left], nums[right])) swap(nums, left, right); + if (less(nums[left + 1], nums[right])) swap(nums, left + 1, right); + if (less(nums[left], nums[left + 1])) swap(nums, left, left + 1); + + const pivot = nums[left + 1]; + let i = left + 1, j = right; + + while (true) { + while (greater(nums[++i], pivot)); + while (less(nums[--j], pivot)); + if (i > j) break; + swap(nums, i, j); + } + + swap(nums, left + 1, j); + return j; + }; + + const quickSelect = (nums, k) => { + let left = 0, right = nums.length - 1; + + while (true) { + if (right <= left + 1) { + if (right === left + 1 && greater(nums[right], nums[left])) { + swap(nums, left, right); + } + return nums[k]; + } + + const j = partition(nums, left, right); + if (j >= k) right = j - 1; + if (j <= k) left = j + 1; + } + }; + + return quickSelect(nums, k - 1); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * n)$ in average case, $O(m * n ^ 2)$ in worst case. +* Space complexity: $O(1)$ \ No newline at end of file diff --git a/articles/find-the-longest-valid-obstacle-course-at-each-position.md b/articles/find-the-longest-valid-obstacle-course-at-each-position.md new file mode 100644 index 000000000..ff2346555 --- /dev/null +++ b/articles/find-the-longest-valid-obstacle-course-at-each-position.md @@ -0,0 +1,387 @@ +## 1. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def longestObstacleCourseAtEachPosition(self, obstacles: List[int]) -> List[int]: + n = len(obstacles) + dp = [[-1] * (n + 1) for _ in range(n)] + + def dfs(i, prev): + if i < 0: + return 0 + if dp[i][prev] != -1: + return dp[i][prev] + + res = dfs(i - 1, prev) + if prev == n or obstacles[prev] >= obstacles[i]: + res = max(res, 1 + dfs(i - 1, i)) + dp[i][prev] = res + return res + + dfs(n - 1, n) + return [1] + [1 + dp[i - 1][i] for i in range(1, n)] +``` + +```java +public class Solution { + private int[][] dp; + + public int[] longestObstacleCourseAtEachPosition(int[] obstacles) { + int n = obstacles.length; + this.dp = new int[n][n + 1]; + for (int[] row : dp) { + Arrays.fill(row, -1); + } + + dfs(n - 1, n, obstacles); + + int[] res = new int[n]; + res[0] = 1; + for (int i = 1; i < n; i++) { + res[i] = 1 + dp[i - 1][i]; + } + return res; + } + + private int dfs(int i, int prev, int[] obstacles) { + if (i < 0) { + return 0; + } + if (dp[i][prev] != -1) { + return dp[i][prev]; + } + + int res = dfs(i - 1, prev, obstacles); + if (prev == obstacles.length || obstacles[prev] >= obstacles[i]) { + res = Math.max(res, 1 + dfs(i - 1, i, obstacles)); + } + return dp[i][prev] = res; + } +} +``` + +```cpp +class Solution { +public: + vector> dp; + + vector longestObstacleCourseAtEachPosition(vector& obstacles) { + int n = obstacles.size(); + this->dp = vector>(n, vector(n + 1, -1)); + + dfs(n - 1, n, obstacles); + + vector res(n, 1); + for (int i = 1; i < n; i++) { + res[i] = 1 + dp[i - 1][i]; + } + return res; + } + +private: + int dfs(int i, int prev, vector& obstacles) { + if (i < 0) { + return 0; + } + if (dp[i][prev] != -1) { + return dp[i][prev]; + } + + int res = dfs(i - 1, prev, obstacles); + if (prev == obstacles.size() || obstacles[prev] >= obstacles[i]) { + res = max(res, 1 + dfs(i - 1, i, obstacles)); + } + return dp[i][prev] = res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} obstacles + * @return {number[]} + */ + longestObstacleCourseAtEachPosition(obstacles) { + const n = obstacles.length; + const dp = Array.from({ length: n }, () => new Array(n + 1).fill(-1)); + + const dfs = (i, prev) => { + if (i < 0) { + return 0; + } + if (dp[i][prev] !== -1) { + return dp[i][prev]; + } + + let res = dfs(i - 1, prev); + if (prev === n || obstacles[prev] >= obstacles[i]) { + res = Math.max(res, 1 + dfs(i - 1, i)); + } + dp[i][prev] = res; + return res; + }; + + dfs(n - 1, n); + + const res = new Array(n).fill(1); + for (let i = 1; i < n; i++) { + res[i] = 1 + dp[i - 1][i]; + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n ^ 2)$ + +--- + +## 2. Dynamic Programming (Binary Search) - I + +::tabs-start + +```python +class Solution: + def longestObstacleCourseAtEachPosition(self, obstacles: List[int]) -> List[int]: + res = [] + dp = [10**8] * (len(obstacles) + 1) + + for num in obstacles: + index = bisect.bisect(dp, num) + res.append(index + 1) + dp[index] = num + + return res +``` + +```java +public class Solution { + public int[] longestObstacleCourseAtEachPosition(int[] obstacles) { + int n = obstacles.length; + int[] res = new int[n]; + int[] dp = new int[n + 1]; + Arrays.fill(dp, (int) 1e8); + + for (int i = 0; i < n; i++) { + int index = upperBound(dp, obstacles[i]); + res[i] = index + 1; + dp[index] = obstacles[i]; + } + + return res; + } + + private int upperBound(int[] dp, int target) { + int left = 0, right = dp.length; + while (left < right) { + int mid = left + (right - left) / 2; + if (dp[mid] > target) { + right = mid; + } else { + left = mid + 1; + } + } + return left; + } +} +``` + +```cpp +class Solution { +public: + vector longestObstacleCourseAtEachPosition(vector& obstacles) { + int n = obstacles.size(); + vector res(n); + vector dp(n + 1, 1e8); + + for (int i = 0; i < n; i++) { + int index = upper_bound(dp.begin(), dp.end(), obstacles[i]) - dp.begin(); + res[i] = index + 1; + dp[index] = obstacles[i]; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} obstacles + * @return {number[]} + */ + longestObstacleCourseAtEachPosition(obstacles) { + let n = obstacles.length; + let res = new Array(n).fill(0); + let dp = new Array(n + 1).fill(1e8); + + const upperBound = (dp, target) => { + let left = 0, right = dp.length; + while (left < right) { + let mid = Math.floor((left + right) / 2); + if (dp[mid] > target) { + right = mid; + } else { + left = mid + 1; + } + } + return left; + }; + + for (let i = 0; i < n; i++) { + let index = upperBound(dp, obstacles[i]); + res[i] = index + 1; + dp[index] = obstacles[i]; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(n)$ + +--- + +## 3. Dynamic Programming (Binary Search) - II + +::tabs-start + +```python +class Solution: + def longestObstacleCourseAtEachPosition(self, obstacles: List[int]) -> List[int]: + res = [] + dp = [] + + for num in obstacles: + index = bisect.bisect_right(dp, num) + res.append(index + 1) + + if index == len(dp): + dp.append(num) + else: + dp[index] = num + + return res +``` + +```java +public class Solution { + public int[] longestObstacleCourseAtEachPosition(int[] obstacles) { + int n = obstacles.length; + int[] res = new int[n]; + List dp = new ArrayList<>(); + + for (int i = 0; i < n; i++) { + int index = upperBound(dp, obstacles[i]); + res[i] = index + 1; + + if (index == dp.size()) { + dp.add(obstacles[i]); + } else { + dp.set(index, obstacles[i]); + } + } + + return res; + } + + private int upperBound(List dp, int target) { + int left = 0, right = dp.size(); + while (left < right) { + int mid = left + (right - left) / 2; + if (dp.get(mid) > target) { + right = mid; + } else { + left = mid + 1; + } + } + return left; + } +} +``` + +```cpp +class Solution { +public: + vector longestObstacleCourseAtEachPosition(vector& obstacles) { + int n = obstacles.size(); + vector res(n); + vector dp; + + for (int i = 0; i < n; i++) { + int index = upper_bound(dp.begin(), dp.end(), obstacles[i]) - dp.begin(); + res[i] = index + 1; + + if (index == dp.size()) { + dp.push_back(obstacles[i]); + } else { + dp[index] = obstacles[i]; + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} obstacles + * @return {number[]} + */ + longestObstacleCourseAtEachPosition(obstacles) { + let n = obstacles.length; + let res = new Array(n).fill(0); + let dp = []; + + const upperBound = (dp, target) => { + let left = 0, right = dp.length; + while (left < right) { + let mid = Math.floor((left + right) / 2); + if (dp[mid] > target) { + right = mid; + } else { + left = mid + 1; + } + } + return left; + }; + + for (let i = 0; i < n; i++) { + let index = upperBound(dp, obstacles[i]); + res[i] = index + 1; + + if (index === dp.length) { + dp.push(obstacles[i]); + } else { + dp[index] = obstacles[i]; + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(n)$ \ No newline at end of file diff --git a/articles/least-number-of-unique-integers-after-k-removals.md b/articles/least-number-of-unique-integers-after-k-removals.md new file mode 100644 index 000000000..ddffbfb03 --- /dev/null +++ b/articles/least-number-of-unique-integers-after-k-removals.md @@ -0,0 +1,343 @@ +## 1. Sorting + +::tabs-start + +```python +class Solution: + def findLeastNumOfUniqueInts(self, arr: List[int], k: int) -> int: + freq = sorted(Counter(arr).values()) + n = len(freq) + for i in range(n): + if k >= freq[i]: + k -= freq[i] + else: + return n - i + return 0 +``` + +```java +public class Solution { + public int findLeastNumOfUniqueInts(int[] arr, int k) { + Map freqMap = new HashMap<>(); + for (int num : arr) { + freqMap.put(num, freqMap.getOrDefault(num, 0) + 1); + } + + List freq = new ArrayList<>(freqMap.values()); + Collections.sort(freq); + + int n = freq.size(); + for (int i = 0; i < n; i++) { + if (k >= freq.get(i)) { + k -= freq.get(i); + } else { + return n - i; + } + } + return 0; + } +} +``` + +```cpp +class Solution { +public: + int findLeastNumOfUniqueInts(vector& arr, int k) { + unordered_map freqMap; + for (int num : arr) { + freqMap[num]++; + } + + vector freq; + for (auto& [_, count] : freqMap) { + freq.push_back(count); + } + + sort(freq.begin(), freq.end()); + + int n = freq.size(); + for (int i = 0; i < n; i++) { + if (k >= freq[i]) { + k -= freq[i]; + } else { + return n - i; + } + } + return 0; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr + * @param {number} k + * @return {number} + */ + findLeastNumOfUniqueInts(arr, k) { + let freqMap = new Map(); + for (let num of arr) { + freqMap.set(num, (freqMap.get(num) || 0) + 1); + } + + let freq = Array.from(freqMap.values()).sort((a, b) => a - b); + + let n = freq.length; + for (let i = 0; i < n; i++) { + if (k >= freq[i]) { + k -= freq[i]; + } else { + return n - i; + } + } + return 0; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(n)$ + +--- + +## 2. Min-Heap + +::tabs-start + +```python +class Solution: + def findLeastNumOfUniqueInts(self, arr: List[int], k: int) -> int: + freq = Counter(arr) + heap = list(freq.values()) + heapq.heapify(heap) + + res = len(heap) + while k > 0 and heap: + f = heapq.heappop(heap) + if k >= f: + k -= f + res -= 1 + return res +``` + +```java +public class Solution { + public int findLeastNumOfUniqueInts(int[] arr, int k) { + Map freqMap = new HashMap<>(); + for (int num : arr) { + freqMap.put(num, freqMap.getOrDefault(num, 0) + 1); + } + + PriorityQueue minHeap = new PriorityQueue<>(freqMap.values()); + + int res = minHeap.size(); + while (k > 0 && !minHeap.isEmpty()) { + int f = minHeap.poll(); + if (k >= f) { + k -= f; + res--; + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int findLeastNumOfUniqueInts(vector& arr, int k) { + unordered_map freqMap; + for (int num : arr) { + freqMap[num]++; + } + + priority_queue, greater> minHeap; + for (auto& [_, count] : freqMap) { + minHeap.push(count); + } + + int res = minHeap.size(); + while (k > 0 && !minHeap.empty()) { + int f = minHeap.top(); + minHeap.pop(); + if (k >= f) { + k -= f; + res--; + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr + * @param {number} k + * @return {number} + */ + findLeastNumOfUniqueInts(arr, k) { + let freqMap = new Map(); + for (let num of arr) { + freqMap.set(num, (freqMap.get(num) || 0) + 1); + } + + const minHeap = MinPriorityQueue.fromArray([...freqMap.values()]); + + let res = minHeap.size(); + while (k > 0 && !minHeap.isEmpty()) { + let f = minHeap.pop(); + if (k >= f) { + k -= f; + res--; + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(n)$ + +--- + +## 3. Bucket Sort + +::tabs-start + +```python +class Solution: + def findLeastNumOfUniqueInts(self, arr: List[int], k: int) -> int: + freq = Counter(arr) + freq_list = [0] * (len(arr) + 1) + + for n, f in freq.items(): + freq_list[f] += 1 + + res = len(freq) + for f in range(1, len(freq_list)): + remove = freq_list[f] + if k >= f * remove: + k -= f * remove + res -= remove + else: + remove = k // f + res -= remove + break + return res +``` + +```java +public class Solution { + public int findLeastNumOfUniqueInts(int[] arr, int k) { + Map freqMap = new HashMap<>(); + for (int num : arr) { + freqMap.put(num, freqMap.getOrDefault(num, 0) + 1); + } + + int[] freqList = new int[arr.length + 1]; + for (int f : freqMap.values()) { + freqList[f]++; + } + + int res = freqMap.size(); + for (int f = 1; f < freqList.length; f++) { + int remove = freqList[f]; + if (k >= f * remove) { + k -= f * remove; + res -= remove; + } else { + remove = k / f; + res -= remove; + break; + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int findLeastNumOfUniqueInts(vector& arr, int k) { + unordered_map freqMap; + for (int num : arr) { + freqMap[num]++; + } + + vector freqList(arr.size() + 1, 0); + for (auto& [_, f] : freqMap) { + freqList[f]++; + } + + int res = freqMap.size(); + for (int f = 1; f < freqList.size(); f++) { + int remove = freqList[f]; + if (k >= f * remove) { + k -= f * remove; + res -= remove; + } else { + remove = k / f; + res -= remove; + break; + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr + * @param {number} k + * @return {number} + */ + findLeastNumOfUniqueInts(arr, k) { + let freqMap = new Map(); + for (let num of arr) { + freqMap.set(num, (freqMap.get(num) || 0) + 1); + } + + let freqList = new Array(arr.length + 1).fill(0); + for (let f of freqMap.values()) { + freqList[f]++; + } + + let res = freqMap.size; + for (let f = 1; f < freqList.length; f++) { + let remove = freqList[f]; + if (k >= f * remove) { + k -= f * remove; + res -= remove; + } else { + remove = Math.floor(k / f); + res -= remove; + break; + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ \ No newline at end of file diff --git a/articles/maximum-performance-of-a-team.md b/articles/maximum-performance-of-a-team.md new file mode 100644 index 000000000..3fc63e969 --- /dev/null +++ b/articles/maximum-performance-of-a-team.md @@ -0,0 +1,238 @@ +## 1. Brute Force (Recursion) + +::tabs-start + +```python +class Solution: + def maxPerformance(self, n: int, speed: List[int], efficiency: List[int], k: int) -> int: + MOD = 1000000007 + res = 0 + + def dfs(i, k, speedSum, minEff): + nonlocal res + res = max(res, speedSum * minEff) + if i == n or k == 0: + return + + dfs(i + 1, k, speedSum, minEff) + dfs(i + 1, k - 1, speedSum + speed[i], min(minEff, efficiency[i])) + + dfs(0, k, 0, float("inf")) + return res % MOD +``` + +```java +public class Solution { + private static final int MOD = 1000000007; + private int[] speed, efficiency; + private int n; + private long res; + + public int maxPerformance(int n, int[] speed, int[] efficiency, int k) { + this.n = n; + this.speed = speed; + this.efficiency = efficiency; + this.res = 0; + + dfs(0, k, Integer.MAX_VALUE, 0); + return (int) (res % MOD); + } + + private void dfs(int i, int k, int minEff, long speedSum) { + res = Math.max(res, speedSum * minEff); + if (i == n || k == 0) return; + + dfs(i + 1, k, minEff, speedSum); + dfs(i + 1, k - 1, Math.min(minEff, efficiency[i]), speedSum + speed[i]); + } +} +``` + +```cpp +class Solution { +private: + static constexpr int MOD = 1000000007; + vector speed, efficiency; + int n; + long long res; + +public: + int maxPerformance(int n, vector& speed, vector& efficiency, int k) { + this->n = n; + this->speed = speed; + this->efficiency = efficiency; + res = 0; + + dfs(0, k, INT_MAX, 0); + return int(res % MOD); + } + +private: + void dfs(int i, int k, int minEff, long long speedSum) { + res = max(res, speedSum * minEff); + if (i == n || k == 0) return; + + dfs(i + 1, k, minEff, speedSum); + dfs(i + 1, k - 1, min(minEff, efficiency[i]), speedSum + speed[i]); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number[]} speed + * @param {number[]} efficiency + * @param {number} k + * @return {number} + */ + maxPerformance(n, speed, efficiency, k) { + const MOD = 1000000007; + let res = 0; + + const dfs = (i, k, minEff, speedSum) => { + res = Math.max(res, minEff === Infinity ? 0 : speedSum * minEff); + if (i === n || k === 0) return; + + dfs(i + 1, k, minEff, speedSum); + dfs(i + 1, k - 1, Math.min(minEff, efficiency[i]), speedSum + speed[i]); + }; + + dfs(0, k, Infinity, 0); + return res % MOD; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(2 ^ n)$ +* Space complexity: $O(n)$ for recursion stack. + +--- + +## 2. Sorting + Min-Heap + +::tabs-start + +```python +class Solution: + def maxPerformance(self, n: int, speed: List[int], efficiency: List[int], k: int) -> int: + MOD = 10**9 + 7 + eng = sorted(zip(efficiency, speed), reverse=True) + + res = speedSum = 0 + minHeap = [] + + for eff, spd in eng: + if len(minHeap) == k: + speedSum -= heapq.heappop(minHeap) + speedSum += spd + heapq.heappush(minHeap, spd) + res = max(res, eff * speedSum) + + return res % MOD +``` + +```java +public class Solution { + public int maxPerformance(int n, int[] speed, int[] efficiency, int k) { + final int MOD = 1_000_000_007; + int[][] engineers = new int[n][2]; + + for (int i = 0; i < n; i++) { + engineers[i] = new int[]{efficiency[i], speed[i]}; + } + + Arrays.sort(engineers, (a, b) -> Integer.compare(b[0], a[0])); + + PriorityQueue minHeap = new PriorityQueue<>(); + long speedSum = 0, res = 0; + + for (int[] eng : engineers) { + if (minHeap.size() == k) { + speedSum -= minHeap.poll(); + } + speedSum += eng[1]; + minHeap.offer(eng[1]); + res = Math.max(res, speedSum * eng[0]); + } + + return (int) (res % MOD); + } +} +``` + +```cpp +class Solution { +public: + int maxPerformance(int n, vector& speed, vector& efficiency, int k) { + constexpr int MOD = 1'000'000'007; + vector> engineers; + + for (int i = 0; i < n; i++) { + engineers.emplace_back(efficiency[i], speed[i]); + } + + sort(engineers.rbegin(), engineers.rend()); + + priority_queue, greater> minHeap; + long long speedSum = 0, res = 0; + + for (const auto& [eff, spd] : engineers) { + if (minHeap.size() == k) { + speedSum -= minHeap.top(); + minHeap.pop(); + } + speedSum += spd; + minHeap.push(spd); + res = max(res, speedSum * eff); + } + + return res % MOD; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number[]} speed + * @param {number[]} efficiency + * @param {number} k + * @return {number} + */ + maxPerformance(n, speed, efficiency, k) { + const MOD = BigInt(1e9 + 7); + const engineers = efficiency.map((eff, i) => [eff, speed[i]]); + engineers.sort((a, b) => b[0] - a[0]); + + const minHeap = new MinPriorityQueue(); + let speedSum = BigInt(0), res = BigInt(0); + + for (const [eff, spd] of engineers) { + if (minHeap.size() === k) { + speedSum -= BigInt(minHeap.dequeue()); + } + speedSum += BigInt(spd); + minHeap.enqueue(spd); + res = res > speedSum * BigInt(eff) ? res : speedSum * BigInt(eff); + } + + return Number(res % MOD); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * (\log n + \log k))$ +* Space complexity: $O(n + k)$ + +> Where $n$ is the number of engineers and $k$ is the maximum number of engineers that can be selected. \ No newline at end of file diff --git a/articles/maximum-profit-in-job-scheduling.md b/articles/maximum-profit-in-job-scheduling.md new file mode 100644 index 000000000..181614b62 --- /dev/null +++ b/articles/maximum-profit-in-job-scheduling.md @@ -0,0 +1,655 @@ +## 1. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def jobScheduling(self, startTime: List[int], endTime: List[int], profit: List[int]) -> int: + intervals = sorted(zip(startTime, endTime, profit)) + cache = {} + + def dfs(i): + if i == len(intervals): + return 0 + if i in cache: + return cache[i] + + # don't include + res = dfs(i + 1) + + # include + j = i + 1 + while j < len(intervals): + if intervals[i][1] <= intervals[j][0]: + break + j += 1 + + cache[i] = res = max(res, intervals[i][2] + dfs(j)) + return res + + return dfs(0) +``` + +```java +public class Solution { + private int[][] intervals; + private int[] cache; + + public int jobScheduling(int[] startTime, int[] endTime, int[] profit) { + int n = startTime.length; + intervals = new int[n][3]; + cache = new int[n]; + Arrays.fill(cache, -1); + + for (int i = 0; i < n; i++) { + intervals[i] = new int[]{startTime[i], endTime[i], profit[i]}; + } + Arrays.sort(intervals, Comparator.comparingInt(a -> a[0])); + + return dfs(0); + } + + private int dfs(int i) { + if (i == intervals.length) { + return 0; + } + if (cache[i] != -1) { + return cache[i]; + } + + // Don't include + int res = dfs(i + 1); + + // Include + int j = i + 1; + while (j < intervals.length && intervals[i][1] > intervals[j][0]) { + j++; + } + + return cache[i] = Math.max(res, intervals[i][2] + dfs(j)); + } +} +``` + +```cpp +class Solution { +public: + vector> intervals; + vector cache; + + int jobScheduling(vector& startTime, vector& endTime, vector& profit) { + int n = startTime.size(); + intervals.resize(n, vector(3)); + cache.assign(n, -1); + + for (int i = 0; i < n; i++) { + intervals[i] = {startTime[i], endTime[i], profit[i]}; + } + sort(intervals.begin(), intervals.end()); + + return dfs(0); + } + +private: + int dfs(int i) { + if (i == intervals.size()) { + return 0; + } + if (cache[i] != -1) { + return cache[i]; + } + + // Don't include + int res = dfs(i + 1); + + // Include + int j = i + 1; + while (j < intervals.size() && intervals[i][1] > intervals[j][0]) { + j++; + } + + return cache[i] = max(res, intervals[i][2] + dfs(j)); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} startTime + * @param {number[]} endTime + * @param {number[]} profit + * @return {number} + */ + jobScheduling(startTime, endTime, profit) { + let n = startTime.length; + let intervals = new Array(n).fill(null).map((_, i) => + [startTime[i], endTime[i], profit[i]] + ); + intervals.sort((a, b) => a[0] - b[0]); + + let cache = new Array(n).fill(-1); + + const dfs = (i) => { + if (i === n) { + return 0; + } + if (cache[i] !== -1) { + return cache[i]; + } + + // Don't include + let res = dfs(i + 1); + + // Include + let j = i + 1; + while (j < n && intervals[i][1] > intervals[j][0]) { + j++; + } + + return (cache[i] = Math.max(res, intervals[i][2] + dfs(j))); + }; + + return dfs(0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n)$ + +--- + +## 2. Dynamic Programming (Top-Down) + Binary Search + +::tabs-start + +```python +class Solution: + def jobScheduling(self, startTime: List[int], endTime: List[int], profit: List[int]) -> int: + intervals = sorted(zip(startTime, endTime, profit)) + cache = {} + + def dfs(i): + if i == len(intervals): + return 0 + if i in cache: + return cache[i] + + # don't include + res = dfs(i + 1) + + # include + j = bisect.bisect(intervals, (intervals[i][1], -1, -1)) + cache[i] = res = max(res, intervals[i][2] + dfs(j)) + return res + + return dfs(0) +``` + +```java +public class Solution { + private int[][] intervals; + private int[] cache; + + public int jobScheduling(int[] startTime, int[] endTime, int[] profit) { + int n = startTime.length; + intervals = new int[n][3]; + cache = new int[n]; + Arrays.fill(cache, -1); + + for (int i = 0; i < n; i++) { + intervals[i] = new int[]{startTime[i], endTime[i], profit[i]}; + } + Arrays.sort(intervals, Comparator.comparingInt(a -> a[0])); + + return dfs(0); + } + + private int dfs(int i) { + if (i == intervals.length) { + return 0; + } + if (cache[i] != -1) { + return cache[i]; + } + + int res = dfs(i + 1); + + int left = i + 1, right = intervals.length, j = intervals.length; + while (left < right) { + int mid = left + (right - left) / 2; + if (intervals[mid][0] >= intervals[i][1]) { + j = mid; + right = mid; + } else { + left = mid + 1; + } + } + + return cache[i] = Math.max(res, intervals[i][2] + dfs(j)); + } +} +``` + +```cpp +class Solution { +public: + vector> intervals; + vector cache; + + int jobScheduling(vector& startTime, vector& endTime, vector& profit) { + int n = startTime.size(); + intervals.resize(n, vector(3)); + cache.assign(n, -1); + + for (int i = 0; i < n; i++) { + intervals[i] = {startTime[i], endTime[i], profit[i]}; + } + sort(intervals.begin(), intervals.end()); + + return dfs(0); + } + +private: + int dfs(int i) { + if (i == intervals.size()) { + return 0; + } + if (cache[i] != -1) { + return cache[i]; + } + + int res = dfs(i + 1); + + int left = i + 1, right = intervals.size(), j = intervals.size(); + while (left < right) { + int mid = left + (right - left) / 2; + if (intervals[mid][0] >= intervals[i][1]) { + j = mid; + right = mid; + } else { + left = mid + 1; + } + } + + return cache[i] = max(res, intervals[i][2] + dfs(j)); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} startTime + * @param {number[]} endTime + * @param {number[]} profit + * @return {number} + */ + jobScheduling(startTime, endTime, profit) { + let n = startTime.length; + let intervals = new Array(n).fill(null).map((_, i) => + [startTime[i], endTime[i], profit[i]] + ); + intervals.sort((a, b) => a[0] - b[0]); + + let cache = new Array(n).fill(-1); + + const dfs = (i) => { + if (i === n) { + return 0; + } + if (cache[i] !== -1) { + return cache[i]; + } + + let res = dfs(i + 1); + + let left = i + 1, right = n, j = n; + while (left < right) { + let mid = Math.floor((left + right) / 2); + if (intervals[mid][0] >= intervals[i][1]) { + j = mid; + right = mid; + } else { + left = mid + 1; + } + } + + return (cache[i] = Math.max(res, intervals[i][2] + dfs(j))); + }; + + return dfs(0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(n)$ + +--- + +## 3. Dynamic Programming (Top-Down) + Binary Search (Optimal) + +::tabs-start + +```python +class Solution: + def jobScheduling(self, startTime: List[int], endTime: List[int], profit: List[int]) -> int: + n = len(startTime) + index = list(range(n)) + index.sort(key=lambda i: startTime[i]) + + cache = [-1] * n + + def dfs(i): + if i == n: + return 0 + if cache[i] != -1: + return cache[i] + + res = dfs(i + 1) + + left, right, j = i + 1, n, n + while left < right: + mid = (left + right) // 2 + if startTime[index[mid]] >= endTime[index[i]]: + j = mid + right = mid + else: + left = mid + 1 + + cache[i] = res = max(res, profit[index[i]] + dfs(j)) + return res + + return dfs(0) +``` + +```java +public class Solution { + private int[] startTime, endTime, profit, cache; + private Integer[] index; + private int n; + + public int jobScheduling(int[] startTime, int[] endTime, int[] profit) { + this.n = startTime.length; + this.startTime = startTime; + this.endTime = endTime; + this.profit = profit; + this.index = new Integer[n]; + this.cache = new int[n]; + Arrays.fill(cache, -1); + + for (int i = 0; i < n; i++) { + index[i] = i; + } + Arrays.sort(index, Comparator.comparingInt(i -> startTime[i])); + + return dfs(0); + } + + private int dfs(int i) { + if (i == n) { + return 0; + } + if (cache[i] != -1) { + return cache[i]; + } + + int res = dfs(i + 1); + + int left = i + 1, right = n, j = n; + while (left < right) { + int mid = left + (right - left) / 2; + if (startTime[index[mid]] >= endTime[index[i]]) { + j = mid; + right = mid; + } else { + left = mid + 1; + } + } + + return cache[i] = Math.max(res, profit[index[i]] + dfs(j)); + } +} +``` + +```cpp +class Solution { +public: + vector startTime, endTime, profit, index, cache; + int n; + + int jobScheduling(vector& startTime, vector& endTime, vector& profit) { + this->n = startTime.size(); + this->startTime = startTime; + this->endTime = endTime; + this->profit = profit; + this->index.resize(n); + this->cache.assign(n, -1); + + for (int i = 0; i < n; i++) { + index[i] = i; + } + sort(index.begin(), index.end(), [&](int i, int j) { + return startTime[i] < startTime[j]; + }); + + return dfs(0); + } + +private: + int dfs(int i) { + if (i == n) { + return 0; + } + if (cache[i] != -1) { + return cache[i]; + } + + int res = dfs(i + 1); + + int left = i + 1, right = n, j = n; + while (left < right) { + int mid = left + (right - left) / 2; + if (startTime[index[mid]] >= endTime[index[i]]) { + j = mid; + right = mid; + } else { + left = mid + 1; + } + } + + return cache[i] = max(res, profit[index[i]] + dfs(j)); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} startTime + * @param {number[]} endTime + * @param {number[]} profit + * @return {number} + */ + jobScheduling(startTime, endTime, profit) { + let n = startTime.length; + let index = Array.from({ length: n }, (_, i) => i); + index.sort((a, b) => startTime[a] - startTime[b]); + + let cache = new Array(n).fill(-1); + + const dfs = (i) => { + if (i === n) { + return 0; + } + if (cache[i] !== -1) { + return cache[i]; + } + + let res = dfs(i + 1); + + let left = i + 1, right = n, j = n; + while (left < right) { + let mid = Math.floor((left + right) / 2); + if (startTime[index[mid]] >= endTime[index[i]]) { + j = mid; + right = mid; + } else { + left = mid + 1; + } + } + + return (cache[i] = Math.max(res, profit[index[i]] + dfs(j))); + }; + + return dfs(0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(n)$ + +--- + +## 4. Dynamic Programming (Bottom-Up) + Binary Search + +::tabs-start + +```python +class Solution: + def jobScheduling(self, startTime: List[int], endTime: List[int], profit: List[int]) -> int: + n = len(startTime) + index = list(range(n)) + index.sort(key=lambda i: startTime[i]) + + dp = [0] * (n + 1) + + for i in range(n - 1, -1, -1): + left, right, j = i + 1, n, n + while left < right: + mid = (left + right) // 2 + if startTime[index[mid]] >= endTime[index[i]]: + j = mid + right = mid + else: + left = mid + 1 + + dp[i] = max(dp[i + 1], profit[index[i]] + dp[j]) + + return dp[0] +``` + +```java +public class Solution { + public int jobScheduling(int[] startTime, int[] endTime, int[] profit) { + int n = startTime.length; + Integer[] index = new Integer[n]; + for (int i = 0; i < n; i++) index[i] = i; + Arrays.sort(index, Comparator.comparingInt(i -> startTime[i])); + + int[] dp = new int[n + 1]; + + for (int i = n - 1; i >= 0; i--) { + int left = i + 1, right = n, j = n; + while (left < right) { + int mid = left + (right - left) / 2; + if (startTime[index[mid]] >= endTime[index[i]]) { + j = mid; + right = mid; + } else { + left = mid + 1; + } + } + dp[i] = Math.max(dp[i + 1], profit[index[i]] + dp[j]); + } + + return dp[0]; + } +} +``` + +```cpp +class Solution { +public: + int jobScheduling(vector& startTime, vector& endTime, vector& profit) { + int n = startTime.size(); + vector index(n), dp(n + 1, 0); + for (int i = 0; i < n; i++) index[i] = i; + sort(index.begin(), index.end(), [&](int i, int j) { + return startTime[i] < startTime[j]; + }); + + for (int i = n - 1; i >= 0; i--) { + int left = i + 1, right = n, j = n; + while (left < right) { + int mid = left + (right - left) / 2; + if (startTime[index[mid]] >= endTime[index[i]]) { + j = mid; + right = mid; + } else { + left = mid + 1; + } + } + dp[i] = max(dp[i + 1], profit[index[i]] + dp[j]); + } + + return dp[0]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} startTime + * @param {number[]} endTime + * @param {number[]} profit + * @return {number} + */ + jobScheduling(startTime, endTime, profit) { + let n = startTime.length; + let index = Array.from({ length: n }, (_, i) => i); + index.sort((a, b) => startTime[a] - startTime[b]); + + let dp = new Array(n + 1).fill(0); + + for (let i = n - 1; i >= 0; i--) { + let left = i + 1, right = n, j = n; + while (left < right) { + let mid = Math.floor((left + right) / 2); + if (startTime[index[mid]] >= endTime[index[i]]) { + j = mid; + right = mid; + } else { + left = mid + 1; + } + } + dp[i] = Math.max(dp[i + 1], profit[index[i]] + dp[j]); + } + + return dp[0]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(n)$ \ No newline at end of file diff --git a/articles/maximum-subsequence-score.md b/articles/maximum-subsequence-score.md new file mode 100644 index 000000000..97c461caa --- /dev/null +++ b/articles/maximum-subsequence-score.md @@ -0,0 +1,412 @@ +## 1. Brute Force (Recursion) + +::tabs-start + +```python +class Solution: + def maxScore(self, nums1: List[int], nums2: List[int], k: int) -> int: + n = len(nums1) + + def dfs(i, k, minVal, curSum): + if k == 0: + return curSum * minVal + if i == n or (n - i) < k: + return float("-inf") + if minVal == 0: + return 0 + + res = dfs(i + 1, k, minVal, curSum) + res = max(res, dfs(i + 1, k - 1, min(minVal, nums2[i]), curSum + nums1[i])) + return res + + return dfs(0, k, float("inf"), 0) +``` + +```java +public class Solution { + private int[] nums1, nums2; + private int n; + + public long maxScore(int[] nums1, int[] nums2, int k) { + this.nums1 = nums1; + this.nums2 = nums2; + this.n = nums1.length; + return dfs(0, k, Integer.MAX_VALUE, 0); + } + + private long dfs(int i, int k, int minVal, long curSum) { + if (k == 0) { + return curSum * minVal; + } + if (i == n || (n - i) < k) { + return Integer.MIN_VALUE; + } + if (minVal == 0) { + return 0; + } + + long res = dfs(i + 1, k, minVal, curSum); + res = Math.max( + res, + dfs(i + 1, k - 1, Math.min(minVal, nums2[i]), curSum + nums1[i]) + ); + return res; + } +} +``` + +```cpp +class Solution { +private: + vector nums1, nums2; + int n; + +public: + long long maxScore(vector& nums1, vector& nums2, int k) { + this->nums1 = nums1; + this->nums2 = nums2; + this->n = nums1.size(); + return dfs(0, k, INT_MAX, 0); + } + +private: + long long dfs(int i, int k, int minVal, long long curSum) { + if (k == 0) { + return curSum * minVal; + } + if (i == n || (n - i) < k) { + return INT_MIN; + } + if (minVal == 0) { + return 0; + } + + long long res = dfs(i + 1, k, minVal, curSum); + res = max(res, dfs(i + 1, k - 1, min(minVal, nums2[i]), curSum + nums1[i])); + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @param {number} k + * @return {number} + */ + maxScore(nums1, nums2, k) { + const n = nums1.length; + + const dfs = (i, k, minVal, curSum) => { + if (k === 0) { + return curSum * minVal; + } + if (i === n || (n - i) < k) { + return -Infinity; + } + if (minVal === 0) { + return 0; + } + + let res = dfs(i + 1, k, minVal, curSum); + res = Math.max( + res, + dfs(i + 1, k - 1, Math.min(minVal, nums2[i]), curSum + nums1[i]) + ); + return res; + }; + + return dfs(0, k, Infinity, 0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(2 ^ n)$ +* Space complexity: $O(n)$ for recursion stack. + +--- + +## 2. Min-Heap - I + +::tabs-start + +```python +class Solution: + def maxScore(self, nums1: List[int], nums2: List[int], k: int) -> int: + pairs = sorted(zip(nums1, nums2), key=lambda p: p[1], reverse=True) + + minHeap = [] + n1Sum = 0 + res = 0 + + for n1, n2 in pairs: + n1Sum += n1 + heapq.heappush(minHeap, n1) + + if len(minHeap) > k: + n1Sum -= heapq.heappop(minHeap) + + if len(minHeap) == k: + res = max(res, n1Sum * n2) + + return res +``` + +```java +public class Solution { + public long maxScore(int[] nums1, int[] nums2, int k) { + int n = nums1.length; + int[][] pairs = new int[n][2]; + + for (int i = 0; i < n; i++) { + pairs[i][0] = nums1[i]; + pairs[i][1] = nums2[i]; + } + + Arrays.sort(pairs, (a, b) -> Integer.compare(b[1], a[1])); + + PriorityQueue minHeap = new PriorityQueue<>(); + long n1Sum = 0, res = 0; + + for (int[] pair : pairs) { + n1Sum += pair[0]; + minHeap.offer(pair[0]); + + if (minHeap.size() > k) { + n1Sum -= minHeap.poll(); + } + + if (minHeap.size() == k) { + res = Math.max(res, n1Sum * pair[1]); + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + long long maxScore(vector& nums1, vector& nums2, int k) { + int n = nums1.size(); + vector> pairs(n); + + for (int i = 0; i < n; i++) { + pairs[i] = {nums1[i], nums2[i]}; + } + + sort(pairs.begin(), pairs.end(), [](const auto& a, const auto& b) { + return b.second < a.second; + }); + + priority_queue, greater> minHeap; + long long n1Sum = 0, res = 0; + + for (auto& pair : pairs) { + n1Sum += pair.first; + minHeap.push(pair.first); + + if (minHeap.size() > k) { + n1Sum -= minHeap.top(); + minHeap.pop(); + } + + if (minHeap.size() == k) { + res = max(res, n1Sum * (long long)pair.second); + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @param {number} k + * @return {number} + */ + maxScore(nums1, nums2, k) { + let pairs = nums1.map((n1, i) => [n1, nums2[i]]); + pairs.sort((a, b) => b[1] - a[1]); + + let minHeap = new MinPriorityQueue(); + let n1Sum = 0, res = 0; + + for (let [n1, n2] of pairs) { + n1Sum += n1; + minHeap.enqueue(n1); + + if (minHeap.size() > k) { + n1Sum -= minHeap.dequeue(); + } + + if (minHeap.size() === k) { + res = Math.max(res, n1Sum * n2); + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(n)$ + +--- + +## 3. Min-Heap - II + +::tabs-start + +```python +class Solution: + def maxScore(self, nums1: List[int], nums2: List[int], k: int) -> int: + n = len(nums1) + arr = [(nums2[i] << 30) | nums1[i] for i in range(n)] + arr.sort(reverse=True) + + minHeap = [] + n1Sum = 0 + res = 0 + + for num in arr: + n1, n2 = num & ((1 << 30) - 1), num >> 30 + n1Sum += n1 + heapq.heappush(minHeap, n1) + + if len(minHeap) > k: + n1Sum -= heapq.heappop(minHeap) + + if len(minHeap) == k: + res = max(res, n1Sum * n2) + + return res +``` + +```java +public class Solution { + public long maxScore(int[] nums1, int[] nums2, int k) { + int n = nums1.length; + long[] arr = new long[n]; + for (int i = 0; i < n; i++) { + arr[i] = ((long) nums2[i] << 30) | nums1[i]; + } + + Arrays.sort(arr); + PriorityQueue minHeap = new PriorityQueue<>(); + long n1Sum = 0, res = 0; + + for (int i = n - 1; i >= 0; i--) { + int n1 = (int) (arr[i] & ((1L << 30) - 1)); + int n2 = (int) (arr[i] >> 30); + n1Sum += n1; + minHeap.offer(n1); + + if (minHeap.size() > k) { + n1Sum -= minHeap.poll(); + } + if (minHeap.size() == k) { + res = Math.max(res, n1Sum * (long) n2); + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + long long maxScore(vector& nums1, vector& nums2, int k) { + int n = nums1.size(); + vector arr(n); + for (int i = 0; i < n; i++) { + arr[i] = ((long long) nums2[i] << 30) | nums1[i]; + } + + sort(arr.rbegin(), arr.rend()); + priority_queue, greater> minHeap; + long long n1Sum = 0, res = 0; + + for (long long& num : arr) { + int n1 = num & ((1LL << 30) - 1); + int n2 = num >> 30; + n1Sum += n1; + minHeap.push(n1); + + if (minHeap.size() > k) { + n1Sum -= minHeap.top(); + minHeap.pop(); + } + if (minHeap.size() == k) { + res = max(res, n1Sum * (long long)n2); + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @param {number} k + * @return {number} + */ + maxScore(nums1, nums2, k) { + const n = nums1.length; + const arr = []; + for (let i = 0; i < n; i++) { + arr.push((BigInt(nums2[i]) << BigInt(30)) | BigInt(nums1[i])); + } + + arr.sort((a, b) => Number(b - a)); + const minHeap = new MinPriorityQueue(); + let n1Sum = 0n, res = 0n; + + for (let num of arr) { + let n1 = Number(num & ((1n << 30n) - 1n)); + let n2 = Number(num >> 30n); + n1Sum += BigInt(n1); + minHeap.enqueue(n1); + + if (minHeap.size() > k) { + n1Sum -= BigInt(minHeap.dequeue()); + } + if (minHeap.size() === k) { + res = BigInt(Math.max(Number(res), Number(n1Sum * BigInt(n2)))); + } + } + + return Number(res); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(n)$ \ No newline at end of file diff --git a/articles/minimize-deviation-in-array.md b/articles/minimize-deviation-in-array.md new file mode 100644 index 000000000..34f231a21 --- /dev/null +++ b/articles/minimize-deviation-in-array.md @@ -0,0 +1,468 @@ +## 1. Sorting + Sliding Window + +::tabs-start + +```python +class Solution: + def minimumDeviation(self, nums: List[int]) -> int: + n = len(nums) + arr = [] + for i, num in enumerate(nums): + if num & 1: + arr.append((num, i)) + arr.append((num * 2, i)) + else: + while num % 2 == 0: + arr.append((num, i)) + num //= 2 + arr.append((num, i)) + + arr.sort() + res = float("inf") + + seen = [0] * n + count = i = 0 + for j in range(len(arr)): + seen[arr[j][1]] += 1 + if seen[arr[j][1]] == 1: + count += 1 + while count == n: + res = min(res, arr[j][0] - arr[i][0]) + seen[arr[i][1]] -= 1 + if seen[arr[i][1]] == 0: + count -= 1 + i += 1 + + return res +``` + +```java +public class Solution { + public int minimumDeviation(int[] nums) { + int n = nums.length; + List arr = new ArrayList<>(); + + for (int i = 0; i < n; i++) { + int num = nums[i]; + if (num % 2 == 1) { + arr.add(new int[]{num, i}); + arr.add(new int[]{num * 2, i}); + } else { + while (num % 2 == 0) { + arr.add(new int[]{num, i}); + num /= 2; + } + arr.add(new int[]{num, i}); + } + } + + arr.sort(Comparator.comparingInt(a -> a[0])); + int res = Integer.MAX_VALUE; + + int[] seen = new int[n]; + int count = 0, i = 0; + + for (int j = 0; j < arr.size(); j++) { + seen[arr.get(j)[1]]++; + if (seen[arr.get(j)[1]] == 1) { + count++; + while (count == n) { + res = Math.min(res, arr.get(j)[0] - arr.get(i)[0]); + seen[arr.get(i)[1]]--; + if (seen[arr.get(i)[1]] == 0) { + count--; + } + i++; + } + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int minimumDeviation(vector& nums) { + int n = nums.size(); + vector> arr; + + for (int i = 0; i < n; i++) { + int num = nums[i]; + if (num % 2 == 1) { + arr.emplace_back(num, i); + arr.emplace_back(num * 2, i); + } else { + while (num % 2 == 0) { + arr.emplace_back(num, i); + num /= 2; + } + arr.emplace_back(num, i); + } + } + + sort(arr.begin(), arr.end()); + int res = INT_MAX; + + vector seen(n, 0); + int count = 0, i = 0; + + for (int j = 0; j < arr.size(); j++) { + seen[arr[j].second]++; + if (seen[arr[j].second] == 1) { + count++; + while (count == n) { + res = min(res, arr[j].first - arr[i].first); + seen[arr[i].second]--; + if (seen[arr[i].second] == 0) { + count--; + } + i++; + } + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + minimumDeviation(nums) { + let n = nums.length; + let arr = []; + + for (let i = 0; i < n; i++) { + let num = nums[i]; + if (num % 2 === 1) { + arr.push([num, i]); + arr.push([num * 2, i]); + } else { + while (num % 2 === 0) { + arr.push([num, i]); + num /= 2; + } + arr.push([num, i]); + } + } + + arr.sort((a, b) => a[0] - b[0]); + let res = Infinity; + + let seen = new Array(n).fill(0); + let count = 0, i = 0; + + for (let j = 0; j < arr.length; j++) { + seen[arr[j][1]]++; + if (seen[arr[j][1]] === 1) { + count++; + while (count === n) { + res = Math.min(res, arr[j][0] - arr[i][0]); + seen[arr[i][1]]--; + if (seen[arr[i][1]] === 0) { + count--; + } + i++; + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O((n \log m) * \log (n \log m))$ +* Space complexity: $O(n \log m)$ + +> Where $n$ is the size of the array $nums$ and $m$ is the maximum element in $nums$. + +--- + +## 2. Min-Heap + +::tabs-start + +```python +class Solution: + def minimumDeviation(self, nums: List[int]) -> int: + minHeap, heapMax = [], 0 + + for n in nums: + tmp = n + while n % 2 == 0: + n //= 2 + minHeap.append((n, max(tmp, 2 * n))) + heapMax = max(heapMax, n) + + res = float("inf") + heapq.heapify(minHeap) + + while len(minHeap) == len(nums): + n, nMax = heapq.heappop(minHeap) + res = min(res, heapMax - n) + + if n < nMax: + heapq.heappush(minHeap, (n * 2, nMax)) + heapMax = max(heapMax, n * 2) + + return res +``` + +```java +public class Solution { + public int minimumDeviation(int[] nums) { + PriorityQueue minHeap = new PriorityQueue<>((a, b) -> a[0] - b[0]); + int heapMax = 0; + + for (int num : nums) { + int tmp = num; + while (num % 2 == 0) { + num /= 2; + } + minHeap.offer(new int[]{num, Math.max(tmp, 2 * num)}); + heapMax = Math.max(heapMax, num); + } + + int res = Integer.MAX_VALUE; + + while (minHeap.size() == nums.length) { + int[] minElement = minHeap.poll(); + int n = minElement[0], nMax = minElement[1]; + res = Math.min(res, heapMax - n); + + if (n < nMax) { + minHeap.offer(new int[]{n * 2, nMax}); + heapMax = Math.max(heapMax, n * 2); + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int minimumDeviation(vector& nums) { + priority_queue, vector>, greater<>> minHeap; + int heapMax = 0; + + for (int num : nums) { + int tmp = num; + while (num % 2 == 0) { + num /= 2; + } + minHeap.push({num, max(tmp, 2 * num)}); + heapMax = max(heapMax, num); + } + + int res = INT_MAX; + + while (minHeap.size() == nums.size()) { + auto [n, nMax] = minHeap.top(); + minHeap.pop(); + res = min(res, heapMax - n); + + if (n < nMax) { + minHeap.push({n * 2, nMax}); + heapMax = max(heapMax, n * 2); + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + minimumDeviation(nums) { + const minHeap = new MinPriorityQueue(x => x[0]); + let heapMax = 0; + + for (let num of nums) { + let tmp = num; + while (num % 2 === 0) { + num /= 2; + } + minHeap.enqueue([num, Math.max(tmp, num * 2)]); + heapMax = Math.max(heapMax, num); + } + + let res = Infinity; + + while (minHeap.size() === nums.length) { + let [n, nMax] = minHeap.dequeue(); + res = Math.min(res, heapMax - n); + + if (n < nMax) { + minHeap.enqueue([n * 2, nMax]); + heapMax = Math.max(heapMax, n * 2); + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n *\log n * \log m)$ +* Space complexity: $O(n)$ + +> Where $n$ is the size of the array $nums$ and $m$ is the maximum element in $nums$. + +--- + +## 3. Max-Heap + +::tabs-start + +```python +class Solution: + def minimumDeviation(self, nums: List[int]) -> int: + maxHeap = [] + minVal = float("inf") + + for num in nums: + if num % 2 == 1: + num *= 2 + heapq.heappush(maxHeap, -num) + minVal = min(minVal, num) + + res = float("inf") + + while maxHeap: + maxVal = -heapq.heappop(maxHeap) + res = min(res, maxVal - minVal) + if maxVal % 2 == 1: + break + + nextVal = maxVal // 2 + heapq.heappush(maxHeap, -nextVal) + minVal = min(minVal, nextVal) + + return res +``` + +```java +public class Solution { + public int minimumDeviation(int[] nums) { + PriorityQueue maxHeap = new PriorityQueue<>((a, b) -> b - a); + int minVal = Integer.MAX_VALUE; + + for (int num : nums) { + if (num % 2 == 1) num *= 2; + maxHeap.offer(num); + minVal = Math.min(minVal, num); + } + + int res = Integer.MAX_VALUE; + + while (!maxHeap.isEmpty()) { + int maxVal = maxHeap.poll(); + res = Math.min(res, maxVal - minVal); + + if (maxVal % 2 == 1) break; + + int nextVal = maxVal / 2; + maxHeap.offer(nextVal); + minVal = Math.min(minVal, nextVal); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int minimumDeviation(vector& nums) { + priority_queue maxHeap; + int minVal = INT_MAX; + + for (int num : nums) { + if (num % 2 == 1) num *= 2; + maxHeap.push(num); + minVal = min(minVal, num); + } + + int res = INT_MAX; + + while (!maxHeap.empty()) { + int maxVal = maxHeap.top(); + maxHeap.pop(); + res = min(res, maxVal - minVal); + + if (maxVal % 2 == 1) break; + + int nextVal = maxVal / 2; + maxHeap.push(nextVal); + minVal = min(minVal, nextVal); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + minimumDeviation(nums) { + const maxHeap = new MaxPriorityQueue(); + let minVal = Infinity; + + for (let num of nums) { + if (num % 2 === 1) num *= 2; + maxHeap.enqueue(num); + minVal = Math.min(minVal, num); + } + + let res = Infinity; + + while (!maxHeap.isEmpty()) { + let maxVal = maxHeap.dequeue(); + res = Math.min(res, maxVal - minVal); + + if (maxVal % 2 === 1) break; + + let nextVal = maxVal / 2; + maxHeap.enqueue(nextVal); + minVal = Math.min(minVal, nextVal); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n *\log n * \log m)$ +* Space complexity: $O(n)$ + +> Where $n$ is the size of the array $nums$ and $m$ is the maximum element in $nums$. \ No newline at end of file diff --git a/articles/minimum-cost-to-hire-k-workers.md b/articles/minimum-cost-to-hire-k-workers.md new file mode 100644 index 000000000..f205b01e7 --- /dev/null +++ b/articles/minimum-cost-to-hire-k-workers.md @@ -0,0 +1,144 @@ +## 1. Greedy + Max-Heap + +::tabs-start + +```python +class Solution: + def mincostToHireWorkers(self, quality: List[int], wage: List[int], k: int) -> float: + pairs = sorted([(w / q, q) for q, w in zip(quality, wage)], key=lambda p: p[0]) + + maxHeap = [] + total_quality = 0 + res = float("inf") + + for rate, q in pairs: + heapq.heappush(maxHeap, -q) + total_quality += q + + if len(maxHeap) > k: + total_quality += heapq.heappop(maxHeap) + + if len(maxHeap) == k: + res = min(res, total_quality * rate) + + return res +``` + +```java +public class Solution { + public double mincostToHireWorkers(int[] quality, int[] wage, int k) { + int n = quality.length; + double res = Double.MAX_VALUE; + double totalQuality = 0; + + double[][] workers = new double[n][2]; + for (int i = 0; i < n; i++) { + workers[i] = new double[]{ + (double) wage[i] / quality[i], (double) quality[i] + }; + } + + Arrays.sort(workers, Comparator.comparingDouble(a -> a[0])); + PriorityQueue maxHeap = new PriorityQueue<>(Collections.reverseOrder()); + + for (double[] worker : workers) { + double ratio = worker[0]; + int q = (int) worker[1]; + + maxHeap.add(q); + totalQuality += q; + + if (maxHeap.size() > k) { + totalQuality -= maxHeap.poll(); + } + + if (maxHeap.size() == k) { + res = Math.min(res, totalQuality * ratio); + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + double mincostToHireWorkers(vector& quality, vector& wage, int k) { + int n = quality.size(); + vector> workers(n); + for (int i = 0; i < n; i++) { + workers[i] = { (double)wage[i] / quality[i], quality[i] }; + } + + sort(workers.begin(), workers.end()); + priority_queue maxHeap; + double totalQuality = 0, res = DBL_MAX; + + for (auto& worker : workers) { + double ratio = worker.first; + int q = worker.second; + maxHeap.push(q); + totalQuality += q; + + if (maxHeap.size() > k) { + totalQuality -= maxHeap.top(); + maxHeap.pop(); + } + + if (maxHeap.size() == k) { + res = min(res, totalQuality * ratio); + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} quality + * @param {number[]} wage + * @param {number} k + * @return {number} + */ + mincostToHireWorkers(quality, wage, k) { + const n = quality.length; + const workers = []; + for (let i = 0; i < n; i++) { + workers.push([wage[i] / quality[i], quality[i]]); + } + + workers.sort((a, b) => a[0] - b[0]); + const maxHeap = new MaxPriorityQueue(); + let totalQuality = 0, res = Number.MAX_VALUE; + + for (let [ratio, q] of workers) { + maxHeap.enqueue(q); + totalQuality += q; + + if (maxHeap.size() > k) { + totalQuality -= maxHeap.dequeue(); + } + + if (maxHeap.size() === k) { + res = Math.min(res, totalQuality * ratio); + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * (\log n + \log k))$ +* Space complexity: $O(n)$ + +> Where $n$ is the number of workers, and $k$ is the number of workers to be hired. \ No newline at end of file diff --git a/articles/number-of-flowers-in-full-bloom.md b/articles/number-of-flowers-in-full-bloom.md new file mode 100644 index 000000000..2b60ec927 --- /dev/null +++ b/articles/number-of-flowers-in-full-bloom.md @@ -0,0 +1,675 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def fullBloomFlowers(self, flowers: List[List[int]], people: List[int]) -> List[int]: + res = [] + + for time in people: + cnt = 0 + for start, end in flowers: + if start <= time <= end: + cnt += 1 + res.append(cnt) + + return res +``` + +```java +public class Solution { + public int[] fullBloomFlowers(int[][] flowers, int[] people) { + int m = people.length; + int[] res = new int[m]; + + for (int i = 0; i < m; i++) { + int count = 0; + for (int[] flower : flowers) { + if (flower[0] <= people[i] && people[i] <= flower[1]) { + count++; + } + } + res[i] = count; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector fullBloomFlowers(vector>& flowers, vector& people) { + int m = people.size(); + vector res(m); + + for (int i = 0; i < m; i++) { + int count = 0; + for (auto& flower : flowers) { + if (flower[0] <= people[i] && people[i] <= flower[1]) { + count++; + } + } + res[i] = count; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} flowers + * @param {number[]} people + * @return {number[]} + */ + fullBloomFlowers(flowers, people) { + let res = new Array(people.length).fill(0); + + for (let i = 0; i < people.length; i++) { + let count = 0; + for (let [start, end] of flowers) { + if (start <= people[i] && people[i] <= end) { + count++; + } + } + res[i] = count; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * n)$ +* Space complexity: $O(m)$ for the output array. + +> Where $n$ is the size of the array $flowers$, and $m$ is the size of the array $people$. + +--- + +## 2. Two Min-Heaps + +::tabs-start + +```python +class Solution: + def fullBloomFlowers(self, flowers: List[List[int]], people: List[int]) -> List[int]: + people = sorted((p, i) for i, p in enumerate(people)) + res = [0] * len(people) + count = 0 + + start = [f[0] for f in flowers] + end = [f[1] for f in flowers] + + heapq.heapify(start) + heapq.heapify(end) + + for p, i in people: + while start and start[0] <= p: + heapq.heappop(start) + count += 1 + while end and end[0] < p: + heapq.heappop(end) + count -= 1 + res[i] = count + + return res +``` + +```java +public class Solution { + public int[] fullBloomFlowers(int[][] flowers, int[] people) { + int m = people.length; + int[] res = new int[m]; + + List sortedPeople = new ArrayList<>(); + for (int i = 0; i < m; i++) { + sortedPeople.add(new int[]{people[i], i}); + } + sortedPeople.sort(Comparator.comparingInt(a -> a[0])); + + PriorityQueue startHeap = new PriorityQueue<>(); + PriorityQueue endHeap = new PriorityQueue<>(); + for (int[] f : flowers) { + startHeap.offer(f[0]); + endHeap.offer(f[1]); + } + + int count = 0; + for (int[] person : sortedPeople) { + int p = person[0], index = person[1]; + + while (!startHeap.isEmpty() && startHeap.peek() <= p) { + startHeap.poll(); + count++; + } + while (!endHeap.isEmpty() && endHeap.peek() < p) { + endHeap.poll(); + count--; + } + + res[index] = count; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector fullBloomFlowers(vector>& flowers, vector& people) { + int m = people.size(); + vector res(m); + + vector> sortedPeople; + for (int i = 0; i < m; i++) { + sortedPeople.push_back({people[i], i}); + } + sort(sortedPeople.begin(), sortedPeople.end()); + + priority_queue, greater> startHeap, endHeap; + for (const auto& f : flowers) { + startHeap.push(f[0]); + endHeap.push(f[1]); + } + + int count = 0; + for (const auto& person : sortedPeople) { + int p = person.first, index = person.second; + + while (!startHeap.empty() && startHeap.top() <= p) { + startHeap.pop(); + count++; + } + while (!endHeap.empty() && endHeap.top() < p) { + endHeap.pop(); + count--; + } + + res[index] = count; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} flowers + * @param {number[]} people + * @return {number[]} + */ + fullBloomFlowers(flowers, people) { + const m = people.length; + const res = new Array(m).fill(0); + + const sortedPeople = people.map((p, i) => [p, i]); + sortedPeople.sort((a, b) => a[0] - b[0]); + + const startHeap = new MinPriorityQueue(); + const endHeap = new MinPriorityQueue(); + for (const [s, e] of flowers) { + startHeap.enqueue(s); + endHeap.enqueue(e); + } + + let count = 0; + for (const [p, index] of sortedPeople) { + while (!startHeap.isEmpty() && startHeap.front() <= p) { + startHeap.dequeue(); + count++; + } + while (!endHeap.isEmpty() && endHeap.front() < p) { + endHeap.dequeue(); + count--; + } + res[index] = count; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m \log m + n \log n)$ +* Space complexity: $O(m + n)$ + +> Where $n$ is the size of the array $flowers$, and $m$ is the size of the array $people$. + +--- + +## 3. Min-Heap + +::tabs-start + +```python +class Solution: + def fullBloomFlowers(self, flowers: List[List[int]], people: List[int]) -> List[int]: + people = sorted((p, i) for i, p in enumerate(people)) + res = [0] * len(people) + flowers.sort() + end = [] + + j = 0 + for p, i in people: + while j < len(flowers) and flowers[j][0] <= p: + heapq.heappush(end, flowers[j][1]) + j += 1 + while end and end[0] < p: + heapq.heappop(end) + res[i] = len(end) + + return res +``` + +```java +public class Solution { + public int[] fullBloomFlowers(int[][] flowers, int[] people) { + int m = people.length; + int[] res = new int[m]; + int[][] indexedPeople = new int[m][2]; + + for (int i = 0; i < m; i++) { + indexedPeople[i] = new int[]{people[i], i}; + } + Arrays.sort(indexedPeople, Comparator.comparingInt(a -> a[0])); + Arrays.sort(flowers, Comparator.comparingInt(a -> a[0])); + + PriorityQueue endHeap = new PriorityQueue<>(); + int j = 0, n = flowers.length; + + for (int[] person : indexedPeople) { + int p = person[0], index = person[1]; + + while (j < n && flowers[j][0] <= p) { + endHeap.offer(flowers[j][1]); + j++; + } + while (!endHeap.isEmpty() && endHeap.peek() < p) { + endHeap.poll(); + } + res[index] = endHeap.size(); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + vector fullBloomFlowers(vector>& flowers, vector& people) { + int m = people.size(); + vector res(m); + vector> indexedPeople; + + for (int i = 0; i < m; i++) { + indexedPeople.emplace_back(people[i], i); + } + sort(indexedPeople.begin(), indexedPeople.end()); + sort(flowers.begin(), flowers.end()); + + priority_queue, greater> endHeap; + int j = 0, n = flowers.size(); + + for (auto [p, index] : indexedPeople) { + while (j < n && flowers[j][0] <= p) { + endHeap.push(flowers[j][1]); + j++; + } + while (!endHeap.empty() && endHeap.top() < p) { + endHeap.pop(); + } + res[index] = endHeap.size(); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} flowers + * @param {number[]} people + * @return {number[]} + */ + fullBloomFlowers(flowers, people) { + const m = people.length; + const res = new Array(m).fill(0); + const indexedPeople = people.map((p, i) => [p, i]); + + indexedPeople.sort((a, b) => a[0] - b[0]); + flowers.sort((a, b) => a[0] - b[0]); + + const endHeap = new MinPriorityQueue(); + let j = 0, n = flowers.length; + + for (const [p, index] of indexedPeople) { + while (j < n && flowers[j][0] <= p) { + endHeap.enqueue(flowers[j][1]); + j++; + } + while (!endHeap.isEmpty() && endHeap.front() < p) { + endHeap.dequeue(); + } + res[index] = endHeap.size(); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m \log m + n \log n)$ +* Space complexity: $O(m + n)$ + +> Where $n$ is the size of the array $flowers$, and $m$ is the size of the array $people$. + +--- + +## 4. Sorting + Two Pointers + +::tabs-start + +```python +class Solution: + def fullBloomFlowers(self, flowers: List[List[int]], people: List[int]) -> List[int]: + start = sorted(f[0] for f in flowers) + end = sorted(f[1] for f in flowers) + + res = [0] * len(people) + peopleIndex = sorted((p, i) for i, p in enumerate(people)) + + i = j = count = 0 + for p, index in peopleIndex: + while i < len(start) and start[i] <= p: + count += 1 + i += 1 + while j < len(end) and end[j] < p: + count -= 1 + j += 1 + res[index] = count + + return res +``` + +```java +public class Solution { + public int[] fullBloomFlowers(int[][] flowers, int[] people) { + int m = people.length; + int[] res = new int[m]; + List start = new ArrayList<>(), end = new ArrayList<>(); + for (int[] f : flowers) { + start.add(f[0]); + end.add(f[1]); + } + + Collections.sort(start); + Collections.sort(end); + + int count = 0, i = 0, j = 0; + List peopleIndex = new ArrayList<>(); + for (int k = 0; k < m; k++) { + peopleIndex.add(new int[]{people[k], k}); + } + peopleIndex.sort(Comparator.comparingInt(a -> a[0])); + + for (int[] p : peopleIndex) { + int time = p[0], index = p[1]; + + while (i < start.size() && start.get(i) <= time) { + count++; + i++; + } + while (j < end.size() && end.get(j) < time) { + count--; + j++; + } + res[index] = count; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector fullBloomFlowers(vector>& flowers, vector& people) { + int m = people.size(); + vector res(m), start, end; + for (auto& f : flowers) { + start.push_back(f[0]); + end.push_back(f[1]); + } + + sort(start.begin(), start.end()); + sort(end.begin(), end.end()); + + int count = 0, i = 0, j = 0; + vector> peopleIndex; + for (int k = 0; k < m; k++) { + peopleIndex.emplace_back(people[k], k); + } + sort(peopleIndex.begin(), peopleIndex.end()); + + for (auto& [p, index] : peopleIndex) { + while (i < start.size() && start[i] <= p) { + count++; + i++; + } + while (j < end.size() && end[j] < p) { + count--; + j++; + } + res[index] = count; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} flowers + * @param {number[]} people + * @return {number[]} + */ + fullBloomFlowers(flowers, people) { + const start = [], end = []; + for (let f of flowers) { + start.push(f[0]); + end.push(f[1]); + } + + start.sort((a, b) => a - b); + end.sort((a, b) => a - b); + + let count = 0, i = 0, j = 0; + const peopleIndex = people.map((p, idx) => [p, idx]); + peopleIndex.sort((a, b) => a[0] - b[0]); + + const res = new Array(people.length); + + for (let [p, index] of peopleIndex) { + while (i < start.length && start[i] <= p) { + count++; + i++; + } + while (j < end.length && end[j] < p) { + count--; + j++; + } + res[index] = count; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m \log m + n \log n)$ +* Space complexity: $O(m + n)$ + +> Where $n$ is the size of the array $flowers$, and $m$ is the size of the array $people$. + +--- + +## 5. Line Sweep + +::tabs-start + +```python +class Solution: + def fullBloomFlowers(self, flowers: List[List[int]], people: List[int]) -> List[int]: + events = [] + for start, end in flowers: + events.append((start, 1)) + events.append((end + 1, -1)) + + events.sort() + queries = sorted((p, i) for i, p in enumerate(people)) + res = [0] * len(people) + + count = j = 0 + for time, index in queries: + while j < len(events) and events[j][0] <= time: + count += events[j][1] + j += 1 + res[index] = count + + return res +``` + +```java +public class Solution { + public int[] fullBloomFlowers(int[][] flowers, int[] people) { + List events = new ArrayList<>(); + for (int[] f : flowers) { + events.add(new int[]{f[0], 1}); + events.add(new int[]{f[1] + 1, -1}); + } + + Collections.sort(events, (a, b) -> a[0] - b[0]); + int[][] queries = new int[people.length][2]; + for (int i = 0; i < people.length; i++) { + queries[i] = new int[]{people[i], i}; + } + Arrays.sort(queries, (a, b) -> Integer.compare(a[0], b[0])); + + int[] res = new int[people.length]; + int count = 0, j = 0; + for (int[] query : queries) { + int time = query[0], index = query[1]; + while (j < events.size() && events.get(j)[0] <= time) { + count += events.get(j)[1]; + j++; + } + res[index] = count; + } + return res; + } +} +``` + +```cpp +class Solution { +public: + vector fullBloomFlowers(vector>& flowers, vector& people) { + vector> events; + for (auto& f : flowers) { + events.emplace_back(f[0], 1); + events.emplace_back(f[1] + 1, -1); + } + + sort(events.begin(), events.end()); + vector> queries; + for (int i = 0; i < people.size(); i++) { + queries.emplace_back(people[i], i); + } + + sort(queries.begin(), queries.end()); + vector res(people.size()); + int count = 0, j = 0; + + for (auto& [time, index] : queries) { + while (j < events.size() && events[j].first <= time) { + count += events[j++].second; + } + res[index] = count; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} flowers + * @param {number[]} people + * @return {number[]} + */ + fullBloomFlowers(flowers, people) { + let events = []; + for (let [start, end] of flowers) { + events.push([start, 1]); + events.push([end + 1, -1]); + } + + events.sort((a, b) => a[0] - b[0]); + let queries = people.map((p, i) => [p, i]).sort((a, b) => a[0] - b[0]); + let res = new Array(people.length).fill(0); + + let count = 0, j = 0; + for (let [time, index] of queries) { + while (j < events.length && events[j][0] <= time) { + count += events[j][1]; + j++; + } + res[index] = count; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m \log m + n \log n)$ +* Space complexity: $O(m + n)$ + +> Where $n$ is the size of the array $flowers$, and $m$ is the size of the array $people$. \ No newline at end of file diff --git a/articles/paint-house.md b/articles/paint-house.md new file mode 100644 index 000000000..91b9896cd --- /dev/null +++ b/articles/paint-house.md @@ -0,0 +1,445 @@ +## 1. Recursion + +::tabs-start + +```python +class Solution: + def min_cost(self, costs: List[List[int]]) -> int: + n = len(costs) + + def dfs(i, prevColor): + if i == n: + return 0 + + res = float("inf") + for c in range(3): + if c == prevColor: + continue + res = min(res, costs[i][c] + dfs(i + 1, c)) + return res + + return dfs(0, -1) +``` + +```java +public class Solution { + private int[][] costs; + private int n; + + public int minCost(int[][] costs) { + this.costs = costs; + this.n = costs.length; + return dfs(0, -1); + } + + private int dfs(int i, int prevColor) { + if (i == n) { + return 0; + } + + int res = Integer.MAX_VALUE; + for (int c = 0; c < 3; c++) { + if (c == prevColor) { + continue; + } + res = Math.min(res, costs[i][c] + dfs(i + 1, c)); + } + return res; + } +} +``` + +```cpp +class Solution { +private: + vector> costs; + int n; + + int dfs(int i, int prevColor) { + if (i == n) { + return 0; + } + + int res = INT_MAX; + for (int c = 0; c < 3; c++) { + if (c == prevColor) { + continue; + } + res = min(res, costs[i][c] + dfs(i + 1, c)); + } + return res; + } + +public: + int minCost(vector>& costs) { + this->costs = costs; + this->n = costs.size(); + return dfs(0, -1); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} costs + * @return {number} + */ + minCost(costs) { + const n = costs.length; + + const dfs = (i, prevColor) => { + if (i === n) return 0; + + let res = Infinity; + for (let c = 0; c < 3; c++) { + if (c === prevColor) continue; + res = Math.min(res, costs[i][c] + dfs(i + 1, c)); + } + return res; + }; + + return dfs(0, -1); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(2 ^ n)$ +* Space complexity: $O(n)$ for recursion stack. + +--- + +## 2. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def min_cost(self, costs: List[List[int]]) -> int: + n = len(costs) + dp = [[-1] * 4 for _ in range(n)] + + def dfs(i, prevColor): + if i == n: + return 0 + if dp[i][prevColor + 1] != -1: + return dp[i][prevColor + 1] + + res = float("inf") + for c in range(3): + if c == prevColor: + continue + res = min(res, costs[i][c] + dfs(i + 1, c)) + + dp[i][prevColor + 1] = res + return res + + return dfs(0, -1) +``` + +```java +public class Solution { + private int[][] dp; + private int[][] costs; + + public int minCost(int[][] costs) { + int n = costs.length; + this.costs = costs; + this.dp = new int[n][4]; + + for (int i = 0; i < n; i++) { + Arrays.fill(dp[i], -1); + } + + return dfs(0, -1); + } + + private int dfs(int i, int prevColor) { + if (i == costs.length) { + return 0; + } + if (dp[i][prevColor + 1] != -1) { + return dp[i][prevColor + 1]; + } + + int res = Integer.MAX_VALUE; + for (int c = 0; c < 3; c++) { + if (c == prevColor) continue; + res = Math.min(res, costs[i][c] + dfs(i + 1, c)); + } + + return dp[i][prevColor + 1] = res; + } +} +``` + +```cpp +class Solution { +public: + vector> dp; + vector> costs; + + int minCost(vector>& costs) { + int n = costs.size(); + this->costs = costs; + dp.assign(n, vector(4, -1)); + return dfs(0, -1); + } + +private: + int dfs(int i, int prevColor) { + if (i == costs.size()) { + return 0; + } + if (dp[i][prevColor + 1] != -1) { + return dp[i][prevColor + 1]; + } + + int res = INT_MAX; + for (int c = 0; c < 3; c++) { + if (c == prevColor) continue; + res = min(res, costs[i][c] + dfs(i + 1, c)); + } + + return dp[i][prevColor + 1] = res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} costs + * @return {number} + */ + minCost(costs) { + const n = costs.length; + const dp = Array.from({ length: n }, () => Array(4).fill(-1)); + + const dfs = (i, prevColor) => { + if (i === n) { + return 0; + } + if (dp[i][prevColor + 1] !== -1) { + return dp[i][prevColor + 1]; + } + + let res = Infinity; + for (let c = 0; c < 3; c++) { + if (c === prevColor) continue; + res = Math.min(res, costs[i][c] + dfs(i + 1, c)); + } + + return (dp[i][prevColor + 1] = res); + }; + + return dfs(0, -1); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 3. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def min_cost(self, costs: List[List[int]]) -> int: + n = len(costs) + if n == 0: + return 0 + + dp = [[0] * 3 for _ in range(n)] + for c in range(3): + dp[0][c] = costs[0][c] + + for i in range(1, n): + for c in range(3): + dp[i][c] = ( + costs[i][c] + + min(dp[i - 1][(c + 1) % 3], dp[i - 1][(c + 2) % 3]) + ) + + return min(dp[n - 1]) +``` + +```java +public class Solution { + public int minCost(int[][] costs) { + int n = costs.length; + if (n == 0) return 0; + + int[][] dp = new int[n][3]; + for (int c = 0; c < 3; c++) { + dp[0][c] = costs[0][c]; + } + + for (int i = 1; i < n; i++) { + for (int c = 0; c < 3; c++) { + dp[i][c] = costs[i][c] + + Math.min(dp[i - 1][(c + 1) % 3], dp[i - 1][(c + 2) % 3]); + } + } + + return Math.min(dp[n - 1][0], Math.min(dp[n - 1][1], dp[n - 1][2])); + } +} +``` + +```cpp +class Solution { +public: + int minCost(vector>& costs) { + int n = costs.size(); + if (n == 0) return 0; + + vector> dp(n, vector(3, 0)); + for (int c = 0; c < 3; c++) { + dp[0][c] = costs[0][c]; + } + + for (int i = 1; i < n; i++) { + for (int c = 0; c < 3; c++) { + dp[i][c] = costs[i][c] + + min(dp[i - 1][(c + 1) % 3], dp[i - 1][(c + 2) % 3]); + } + } + + return min({dp[n - 1][0], dp[n - 1][1], dp[n - 1][2]}); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} costs + * @return {number} + */ + minCost(costs) { + let n = costs.length; + if (n === 0) return 0; + + let dp = Array.from({ length: n }, () => Array(3).fill(0)); + for (let c = 0; c < 3; c++) { + dp[0][c] = costs[0][c]; + } + + for (let i = 1; i < n; i++) { + for (let c = 0; c < 3; c++) { + dp[i][c] = costs[i][c] + + Math.min(dp[i - 1][(c + 1) % 3], dp[i - 1][(c + 2) % 3]); + } + } + + return Math.min(dp[n - 1][0], dp[n - 1][1], dp[n - 1][2]); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 4. Dynamic Programming (Space Optimized) + +::tabs-start + +```python +class Solution: + def minCost(self, costs: List[List[int]]) -> int: + dp = [0, 0, 0] + + for i in range(len(costs)): + dp0 = costs[i][0] + min(dp[1], dp[2]) + dp1 = costs[i][1] + min(dp[0], dp[2]) + dp2 = costs[i][2] + min(dp[0], dp[1]) + dp = [dp0, dp1, dp2] + + return min(dp) +``` + +```java +public class Solution { + public int minCost(int[][] costs) { + int dp0 = 0, dp1 = 0, dp2 = 0; + + for (int i = 0; i < costs.length; i++) { + int newDp0 = costs[i][0] + Math.min(dp1, dp2); + int newDp1 = costs[i][1] + Math.min(dp0, dp2); + int newDp2 = costs[i][2] + Math.min(dp0, dp1); + dp0 = newDp0; + dp1 = newDp1; + dp2 = newDp2; + } + + return Math.min(dp0, Math.min(dp1, dp2)); + } +} +``` + +```cpp +class Solution { +public: + int minCost(vector>& costs) { + int dp0 = 0, dp1 = 0, dp2 = 0; + + for (const auto& cost : costs) { + int newDp0 = cost[0] + min(dp1, dp2); + int newDp1 = cost[1] + min(dp0, dp2); + int newDp2 = cost[2] + min(dp0, dp1); + dp0 = newDp0; + dp1 = newDp1; + dp2 = newDp2; + } + + return min({dp0, dp1, dp2}); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} costs + * @return {number} + */ + minCost(costs) { + let dp = [0, 0, 0]; + + for (let i = 0; i < costs.length; i++) { + let dp0 = costs[i][0] + Math.min(dp[1], dp[2]); + let dp1 = costs[i][1] + Math.min(dp[0], dp[2]); + let dp2 = costs[i][2] + Math.min(dp[0], dp[1]); + dp = [dp0, dp1, dp2]; + } + + return Math.min(dp[0], dp[1], dp[2]); + } +} +``` + +::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/process-tasks-using-servers.md b/articles/process-tasks-using-servers.md new file mode 100644 index 000000000..f79a9c753 --- /dev/null +++ b/articles/process-tasks-using-servers.md @@ -0,0 +1,501 @@ +## 1. Brute Force (Simulation) + +::tabs-start + +```python +class Solution: + def assignTasks(self, servers: List[int], tasks: List[int]) -> List[int]: + n, m = len(servers), len(tasks) + available = [True] * n + finishTime = [0] * n + res = [] + time = 0 + + for t in range(m): + time = max(time, t) + + for i in range(n): + if finishTime[i] <= time: + available[i] = True + + if not any(available): + time = min(finishTime) + for i in range(n): + if finishTime[i] <= time: + available[i] = True + + minIdx = -1 + for i in range(n): + if (available[i] and + (minIdx == -1 or servers[i] < servers[minIdx] or + (servers[i] == servers[minIdx] and i < minIdx)) + ): + minIdx = i + + res.append(minIdx) + available[minIdx] = False + finishTime[minIdx] = time + tasks[t] + + return res +``` + +```java +public class Solution { + public int[] assignTasks(int[] servers, int[] tasks) { + int n = servers.length, m = tasks.length; + boolean[] available = new boolean[n]; + Arrays.fill(available, true); + int[] finishTime = new int[n]; + int[] res = new int[m]; + int time = 0; + + for (int t = 0; t < m; t++) { + time = Math.max(time, t); + for (int i = 0; i < n; i++) { + if (finishTime[i] <= time) { + available[i] = true; + } + } + + if (!anyAvailable(available)) { + time = Arrays.stream(finishTime).min().getAsInt(); + for (int i = 0; i < n; i++) { + if (finishTime[i] <= time) { + available[i] = true; + } + } + } + + int minIdx = -1; + for (int i = 0; i < n; i++) { + if (available[i] && (minIdx == -1 || servers[i] < servers[minIdx] || + (servers[i] == servers[minIdx] && i < minIdx))) { + minIdx = i; + } + } + + res[t] = minIdx; + available[minIdx] = false; + finishTime[minIdx] = time + tasks[t]; + } + return res; + } + + private boolean anyAvailable(boolean[] available) { + for (boolean v : available) { + if (v) return true; + } + return false; + } +} +``` + +```cpp +class Solution { +public: + vector assignTasks(vector& servers, vector& tasks) { + int n = servers.size(), m = tasks.size(); + vector available(n, true); + vector finishTime(n, 0), res(m); + int time = 0; + + for (int t = 0; t < m; t++) { + time = max(time, t); + + for (int i = 0; i < n; i++) { + if (finishTime[i] <= time) { + available[i] = true; + } + } + + if (!any_of(available.begin(), available.end(), [](bool v) { return v; })) { + time = *min_element(finishTime.begin(), finishTime.end()); + for (int i = 0; i < n; i++) { + if (finishTime[i] <= time) { + available[i] = true; + } + } + } + + int minIdx = -1; + for (int i = 0; i < n; i++) { + if (available[i] && (minIdx == -1 || servers[i] < servers[minIdx] || + (servers[i] == servers[minIdx] && i < minIdx))) { + minIdx = i; + } + } + + res[t] = minIdx; + available[minIdx] = false; + finishTime[minIdx] = time + tasks[t]; + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} servers + * @param {number[]} tasks + * @return {number[]} + */ + assignTasks(servers, tasks) { + const n = servers.length, m = tasks.length; + const available = Array(n).fill(true); + const finishTime = Array(n).fill(0); + const res = []; + let time = 0; + + for (let t = 0; t < m; t++) { + time = Math.max(time, t); + + for (let i = 0; i < n; i++) { + if (finishTime[i] <= time) { + available[i] = true; + } + } + + if (!available.some(v => v)) { + time = Math.min(...finishTime); + for (let i = 0; i < n; i++) { + if (finishTime[i] <= time) { + available[i] = true; + } + } + } + + let minIdx = -1; + for (let i = 0; i < n; i++) { + if (available[i] && (minIdx === -1 || servers[i] < servers[minIdx] || + (servers[i] === servers[minIdx] && i < minIdx))) { + minIdx = i; + } + } + + res.push(minIdx); + available[minIdx] = false; + finishTime[minIdx] = time + tasks[t]; + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * n)$ +* Space complexity: + * $O(n)$ extra space. + * $O(m)$ space for the output array. + +> Where $m$ is the number of tasks and $n$ is the number of servers. + +--- + +## 2. Two Min-Heaps - I + +::tabs-start + +```python +class Solution: + def assignTasks(self, servers: List[int], tasks: List[int]) -> List[int]: + res = [0] * len(tasks) + available = [(servers[i], i) for i in range(len(servers))] + heapq.heapify(available) + unavailable = [] + + t = 0 + for i in range(len(tasks)): + t = max(t, i) + + if not available: + t = unavailable[0][0] + + while unavailable and t >= unavailable[0][0]: + timeFree, weight, index = heapq.heappop(unavailable) + heapq.heappush(available, (weight, index)) + + weight, index = heapq.heappop(available) + res[i] = index + heapq.heappush(unavailable, (t + tasks[i], weight, index)) + + return res +``` + +```java +public class Solution { + public int[] assignTasks(int[] servers, int[] tasks) { + int n = servers.length, m = tasks.length; + int[] res = new int[m]; + + PriorityQueue available = new PriorityQueue<>( + (a, b) -> a[0] == b[0] ? Integer.compare(a[1], b[1]) : Integer.compare(a[0], b[0]) + ); + PriorityQueue unavailable = new PriorityQueue<>( + Comparator.comparingInt(a -> a[0]) + ); + + for (int i = 0; i < n; i++) { + available.offer(new int[]{servers[i], i}); + } + + int time = 0; + for (int i = 0; i < m; i++) { + time = Math.max(time, i); + + if (available.isEmpty()) { + time = unavailable.peek()[0]; + } + + while (!unavailable.isEmpty() && unavailable.peek()[0] <= time) { + int[] server = unavailable.poll(); + available.offer(new int[]{server[1], server[2]}); + } + + int[] bestServer = available.poll(); + res[i] = bestServer[1]; + unavailable.offer(new int[]{time + tasks[i], bestServer[0], bestServer[1]}); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector assignTasks(vector& servers, vector& tasks) { + int n = servers.size(), m = tasks.size(); + vector res(m); + + priority_queue, vector>, greater<>> available; + priority_queue, vector>, greater<>> unavailable; + + for (int i = 0; i < n; i++) { + available.emplace(servers[i], i); + } + + int time = 0; + for (int i = 0; i < m; i++) { + time = max(time, i); + + if (available.empty()) { + time = unavailable.top()[0]; + } + + while (!unavailable.empty() && unavailable.top()[0] <= time) { + auto server = unavailable.top(); unavailable.pop(); + available.emplace(server[1], server[2]); + } + + auto [weight, index] = available.top(); available.pop(); + res[i] = index; + unavailable.push({time + tasks[i], weight, index}); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} servers + * @param {number[]} tasks + * @return {number[]} + */ + assignTasks(servers, tasks) { + const n = servers.length; + const available = new PriorityQueue( + (a, b) => a[0] === b[0] ? a[1] - b[1] : a[0] - b[0] + ); + const unavailable = new PriorityQueue((a, b) => a[0] - b[0]); + const res = new Array(tasks.length); + + for (let i = 0; i < n; i++) { + available.enqueue([servers[i], i]); + } + + let time = 0; + for (let i = 0; i < tasks.length; i++) { + time = Math.max(time, i); + if (available.isEmpty()) { + time = unavailable.front()[0]; + } + while (!unavailable.isEmpty() && unavailable.front()[0] <= time) { + const [timeFree, weight, index] = unavailable.dequeue(); + available.enqueue([weight, index]); + } + const [weight, index] = available.dequeue(); + res[i] = index; + unavailable.enqueue([time + tasks[i], weight, index]); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O((n + m) \log n)$ +* Space complexity: + * $O(n)$ extra space. + * $O(m)$ space for the output array. + +> Where $m$ is the number of tasks and $n$ is the number of servers. + +--- + +## 3. Two Min-Heaps - II + +::tabs-start + +```python +class Solution: + def assignTasks(self, servers: List[int], tasks: List[int]) -> List[int]: + res = [] + available = [[weight, i, 0] for i, weight in enumerate(servers)] + unavailable = [] + heapq.heapify(available) + + for i, task in enumerate(tasks): + while unavailable and unavailable[0][0] <= i or not available: + timeFree, weight, index = heapq.heappop(unavailable) + heapq.heappush(available, [weight, index, timeFree]) + + weight, index, timeFree = heapq.heappop(available) + res.append(index) + heapq.heappush(unavailable, [max(timeFree, i) + task, weight, index]) + + return res +``` + +```java +public class Solution { + public int[] assignTasks(int[] servers, int[] tasks) { + int m = tasks.length, n = servers.length; + int[] res = new int[m]; + + PriorityQueue available = new PriorityQueue<>((a, b) -> { + if(a[0] != b[0]) return Integer.compare(a[0], b[0]); + if(a[1] != b[1]) return Integer.compare(a[1], b[1]); + return Integer.compare(a[2], b[2]); + }); + + PriorityQueue unavailable = new PriorityQueue<>((a, b) -> { + if(a[0] != b[0]) return Integer.compare(a[0], b[0]); + if(a[1] != b[1]) return Integer.compare(a[1], b[1]); + return Integer.compare(a[2], b[2]); + }); + + for (int i = 0; i < n; i++) { + available.offer(new int[]{servers[i], i, 0}); + } + + for (int i = 0; i < m; i++) { + while ((!unavailable.isEmpty() && unavailable.peek()[0] <= i) || + available.isEmpty()) { + int[] server = unavailable.poll(); + available.offer(new int[]{server[1], server[2], server[0]}); + } + int[] server = available.poll(); + res[i] = server[1]; + unavailable.offer(new int[]{ + Math.max(server[2], i) + tasks[i], server[0], server[1]} + ); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector assignTasks(vector& servers, vector& tasks) { + int n = servers.size(), m = tasks.size(); + vector res(m); + + priority_queue, vector>, greater<>> available; + priority_queue, vector>, greater<>> unavailable; + + for (int i = 0; i < n; ++i) { + available.push({servers[i], i, 0}); + } + + for (int i = 0; i < m; ++i) { + while (!unavailable.empty() && (unavailable.top()[0] <= i || + available.empty())) { + auto [timeFree, weight, index] = unavailable.top(); + unavailable.pop(); + available.push({weight, index, timeFree}); + } + + auto [weight, index, timeFree] = available.top(); + available.pop(); + res[i] = index; + unavailable.push({max(timeFree, i) + tasks[i], weight, index}); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} servers + * @param {number[]} tasks + * @return {number[]} + */ + assignTasks(servers, tasks) { + const res = new Array(tasks.length); + const available = new PriorityQueue( + (a, b) => a[0] === b[0] ? (a[1] === b[1] ? a[2] - b[2] : a[1] - b[1]) : a[0] - b[0] + ); + const unavailable = new PriorityQueue( + (a, b) => a[0] === b[0] ? (a[1] === b[1] ? a[2] - b[2] : a[1] - b[1]) : a[0] - b[0] + ); + + for (let i = 0; i < servers.length; i++) { + available.enqueue([servers[i], i, 0]); + } + + for (let i = 0; i < tasks.length; i++) { + while ((!unavailable.isEmpty() && unavailable.front()[0] <= i) || + available.isEmpty()) { + const [timeFree, weight, index] = unavailable.dequeue(); + available.enqueue([weight, index, timeFree]); + } + + const [weight, index, timeFree] = available.dequeue(); + res[i] = index; + unavailable.enqueue([Math.max(timeFree, i) + tasks[i], weight, index]); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O((n + m) \log n)$ +* Space complexity: + * $O(n)$ extra space. + * $O(m)$ space for the output array. + +> Where $m$ is the number of tasks and $n$ is the number of servers. \ No newline at end of file diff --git a/articles/seat-reservation-manager.md b/articles/seat-reservation-manager.md new file mode 100644 index 000000000..c546e1be8 --- /dev/null +++ b/articles/seat-reservation-manager.md @@ -0,0 +1,407 @@ +## 1. Brute Force + +::tabs-start + +```python +class SeatManager: + + def __init__(self, n: int): + self.seats = [False] * n + + def reserve(self) -> int: + for i in range(len(self.seats)): + if not self.seats[i]: + self.seats[i] = True + return i + 1 + + def unreserve(self, seatNumber: int) -> None: + self.seats[seatNumber - 1] = False +``` + +```java +public class SeatManager { + private boolean[] seats; + + public SeatManager(int n) { + seats = new boolean[n]; + } + + public int reserve() { + for (int i = 0; i < seats.length; i++) { + if (!seats[i]) { + seats[i] = true; + return i + 1; + } + } + return -1; + } + + public void unreserve(int seatNumber) { + seats[seatNumber - 1] = false; + } +} +``` + +```cpp +class SeatManager { +private: + vector seats; + +public: + SeatManager(int n) : seats(n, false) {} + + int reserve() { + for (int i = 0; i < seats.size(); i++) { + if (!seats[i]) { + seats[i] = true; + return i + 1; + } + } + return -1; + } + + void unreserve(int seatNumber) { + seats[seatNumber - 1] = false; + } +}; +``` + +```javascript +class SeatManager { + /** + * @param {number} n + */ + constructor(n) { + this.seats = new Array(n).fill(false); + } + + /** + * @return {number} + */ + reserve() { + for (let i = 0; i < this.seats.length; i++) { + if (!this.seats[i]) { + this.seats[i] = true; + return i + 1; + } + } + } + + /** + * @param {number} seatNumber + * @return {void} + */ + unreserve(seatNumber) { + this.seats[seatNumber - 1] = false; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: + * $O(n)$ time for initialization. + * $O(n)$ time for each $reserve()$ function call. + * $O(1)$ time for each $unreserve()$ function call. +* Space complexity: $O(n)$ + +--- + +## 2. Min-Heap + +::tabs-start + +```python +class SeatManager: + def __init__(self, n: int): + self.unres = list(range(1, n + 1)) + heapq.heapify(self.unres) + + def reserve(self) -> int: + return heapq.heappop(self.unres) + + def unreserve(self, seatNumber: int) -> None: + heapq.heappush(self.unres, seatNumber) +``` + +```java +public class SeatManager { + private PriorityQueue unres; + + public SeatManager(int n) { + unres = new PriorityQueue<>(); + for (int i = 1; i <= n; i++) { + unres.offer(i); + } + } + + public int reserve() { + return unres.poll(); + } + + public void unreserve(int seatNumber) { + unres.offer(seatNumber); + } +} +``` + +```cpp +class SeatManager { +private: + priority_queue, greater> unres; + +public: + SeatManager(int n) { + for (int i = 1; i <= n; i++) { + unres.push(i); + } + } + + int reserve() { + int seat = unres.top(); + unres.pop(); + return seat; + } + + void unreserve(int seatNumber) { + unres.push(seatNumber); + } +}; +``` + +```javascript +class SeatManager { + /** + * @param {number} n + */ + constructor(n) { + this.unres = new MinPriorityQueue(); + for (let i = 1; i <= n; i++) { + this.unres.enqueue(i); + } + } + + /** + * @return {number} + */ + reserve() { + return this.unres.dequeue(); + } + + /** + * @param {number} seatNumber + * @return {void} + */ + unreserve(seatNumber) { + this.unres.enqueue(seatNumber); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: + * $O(n \log n)$ time for initialization. + * $O(\log n)$ time for each $reserve()$ function call. + * $O(\log n)$ time for each $unreserve()$ function call. +* Space complexity: $O(n)$ + +--- + +## 3. Min-Heap (Optimal) + +::tabs-start + +```python +class SeatManager: + def __init__(self, n: int): + self.minHeap = [] + self.nextSeat = 1 + + def reserve(self) -> int: + if self.minHeap: + return heapq.heappop(self.minHeap) + + seat = self.nextSeat + self.nextSeat += 1 + return seat + + def unreserve(self, seatNumber: int) -> None: + heapq.heappush(self.minHeap, seatNumber) +``` + +```java +public class SeatManager { + private PriorityQueue minHeap; + private int nextSeat; + + public SeatManager(int n) { + minHeap = new PriorityQueue<>(); + nextSeat = 1; + } + + public int reserve() { + if (!minHeap.isEmpty()) { + return minHeap.poll(); + } + return nextSeat++; + } + + public void unreserve(int seatNumber) { + minHeap.offer(seatNumber); + } +} +``` + +```cpp +class SeatManager { +private: + priority_queue, greater> minHeap; + int nextSeat; + +public: + SeatManager(int n) { + nextSeat = 1; + } + + int reserve() { + if (!minHeap.empty()) { + int seat = minHeap.top(); + minHeap.pop(); + return seat; + } + return nextSeat++; + } + + void unreserve(int seatNumber) { + minHeap.push(seatNumber); + } +}; +``` + +```javascript +class SeatManager { + /** + * @param {number} n + */ + constructor(n) { + this.minHeap = new MinPriorityQueue(); + this.nextSeat = 1; + } + + /** + * @return {number} + */ + reserve() { + if (!this.minHeap.isEmpty()) { + return this.minHeap.dequeue(); + } + return this.nextSeat++; + } + + /** + * @param {number} seatNumber + * @return {void} + */ + unreserve(seatNumber) { + this.minHeap.enqueue(seatNumber); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: + * $O(1)$ time for initialization. + * $O(\log n)$ time for each $reserve()$ function call. + * $O(\log n)$ time for each $unreserve()$ function call. +* Space complexity: $O(n)$ + +--- + +## 4. Ordered Set + +::tabs-start + +```python +class SeatManager: + def __init__(self, n: int): + self.available = SortedSet() + self.nextSeat = 1 + + def reserve(self) -> int: + if self.available: + return self.available.pop(0) + + seat = self.nextSeat + self.nextSeat += 1 + return seat + + def unreserve(self, seatNumber: int) -> None: + self.available.add(seatNumber) +``` + +```java +public class SeatManager { + private TreeSet available; + private int nextSeat; + + public SeatManager(int n) { + available = new TreeSet<>(); + nextSeat = 1; + } + + public int reserve() { + if (!available.isEmpty()) { + return available.pollFirst(); + } + return nextSeat++; + } + + public void unreserve(int seatNumber) { + available.add(seatNumber); + } +} +``` + +```cpp +class SeatManager { +private: + set available; + int nextSeat; + +public: + SeatManager(int n) { + nextSeat = 1; + } + + int reserve() { + if (!available.empty()) { + int seat = *available.begin(); + available.erase(available.begin()); + return seat; + } + return nextSeat++; + } + + void unreserve(int seatNumber) { + available.insert(seatNumber); + } +}; +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: + * $O(1)$ time for initialization. + * $O(\log n)$ time for each $reserve()$ function call. + * $O(\log n)$ time for each $unreserve()$ function call. +* Space complexity: $O(n)$ \ No newline at end of file diff --git a/articles/student-attendance-record-ii.md b/articles/student-attendance-record-ii.md new file mode 100644 index 000000000..b941f3076 --- /dev/null +++ b/articles/student-attendance-record-ii.md @@ -0,0 +1,854 @@ +## 1. Dynamic Programming (Top-Down) - I + +::tabs-start + +```python +class Solution: + def checkRecord(self, n: int) -> int: + MOD = 1000000007 + cache = [[[-1 for _ in range(3)] for _ in range(2)] for _ in range(n + 1)] + + def dfs(i, cntA, cntL): + if i == 0: + return 1 + if cache[i][cntA][cntL] != -1: + return cache[i][cntA][cntL] + + res = dfs(i - 1, cntA, 0) % MOD + + if cntA == 0: + res = (res + dfs(i - 1, 1, 0)) % MOD + + if cntL < 2: + res = (res + dfs(i - 1, cntA, cntL + 1)) % MOD + + cache[i][cntA][cntL] = res + return res + + return dfs(n, 0, 0) +``` + +```java +public class Solution { + private static final int MOD = 1000000007; + private int[][][] cache; + + public int checkRecord(int n) { + this.cache = new int[n + 1][2][3]; + for (int[][] matrix : cache) { + for (int[] row : matrix) { + Arrays.fill(row, -1); + } + } + return dfs(n, 0, 0); + } + + private int dfs(int i, int cntA, int cntL) { + if (i == 0) { + return 1; + } + if (cache[i][cntA][cntL] != -1) { + return cache[i][cntA][cntL]; + } + + int res = dfs(i - 1, cntA, 0) % MOD; + + if (cntA == 0) { + res = (res + dfs(i - 1, 1, 0)) % MOD; + } + + if (cntL < 2) { + res = (res + dfs(i - 1, cntA, cntL + 1)) % MOD; + } + + return cache[i][cntA][cntL] = res; + } +} +``` + +```cpp +class Solution { + const int MOD = 1000000007; + vector>> cache; + +public: + int checkRecord(int n) { + cache.assign(n + 1, vector>(2, vector(3, -1))); + return dfs(n, 0, 0); + } + +private: + int dfs(int i, int cntA, int cntL) { + if (i == 0) { + return 1; + } + if (cache[i][cntA][cntL] != -1) { + return cache[i][cntA][cntL]; + } + + int res = dfs(i - 1, cntA, 0) % MOD; + + if (cntA == 0) { + res = (res + dfs(i - 1, 1, 0)) % MOD; + } + + if (cntL < 2) { + res = (res + dfs(i - 1, cntA, cntL + 1)) % MOD; + } + + return cache[i][cntA][cntL] = res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + checkRecord(n) { + const MOD = 1000000007; + let cache = Array.from({ length: n + 1 }, () => + Array.from({ length: 2 }, () => new Array(3).fill(-1)) + ); + + const dfs = (i, cntA, cntL) => { + if (i === 0) return 1; + if (cache[i][cntA][cntL] !== -1) return cache[i][cntA][cntL]; + + let res = dfs(i - 1, cntA, 0) % MOD; + + if (cntA === 0) { + res = (res + dfs(i - 1, 1, 0)) % MOD; + } + + if (cntL < 2) { + res = (res + dfs(i - 1, cntA, cntL + 1)) % MOD; + } + + return (cache[i][cntA][cntL] = res); + }; + + return dfs(n, 0, 0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 2. Dynamic Programming (Top-Down) - II + +::tabs-start + +```python +class Solution: + def checkRecord(self, n: int) -> int: + MOD = 10**9 + 7 + cache = {} + + def count(n): + if n == 1: + # (A, L) + return { + (0, 0): 1, (0, 1): 1, (0, 2): 0, + (1, 0): 1, (1, 1): 0, (1, 2): 0 + } + + if n in cache: + return cache[n] + + tmp = count(n - 1) + res = defaultdict(int) + + # Choose P + res[(0, 0)] = ((tmp[(0, 0)] + tmp[(0, 1)]) % MOD + tmp[(0, 2)]) % MOD + res[(1, 0)] = ((tmp[(1, 0)] + tmp[(1, 1)]) % MOD + tmp[(1, 2)]) % MOD + + # Choose L + res[(0, 1)] = tmp[(0, 0)] + res[(0, 2)] = tmp[(0, 1)] + res[(1, 1)] = tmp[(1, 0)] + res[(1, 2)] = tmp[(1, 1)] + + # Choose A + res[(1, 0)] += ((tmp[(0, 0)] + tmp[(0, 1)]) % MOD + tmp[(0, 2)]) % MOD + + cache[n] = res + return res + + return sum(count(n).values()) % MOD +``` + +```java +public class Solution { + private static final int MOD = 1000000007; + private int[][][] cache; + private int[][] baseCase; + + public int checkRecord(int n) { + cache = new int[n + 1][2][3]; + baseCase = new int[][]{{1, 1, 0}, {1, 0, 0}}; + for (int[][] matrix : cache) { + for (int[] row : matrix) { + Arrays.fill(row, -1); + } + } + int[][] result = count(n); + int total = 0; + for (int[] row : result) { + for (int val : row) { + total = (total + val) % MOD; + } + } + return total; + } + + private int[][] count(int n) { + if (n == 1) { + // (A, L) + return baseCase; + } + + if (cache[n][0][0] != -1) { + return cache[n]; + } + + int[][] prev = count(n - 1); + int[][] res = cache[n]; + + // Choose P + res[0][0] = ((prev[0][0] + prev[0][1]) % MOD + prev[0][2]) % MOD; + res[1][0] = ((prev[1][0] + prev[1][1]) % MOD + prev[1][2]) % MOD; + + // Choose L + res[0][1] = prev[0][0]; + res[0][2] = prev[0][1]; + res[1][1] = prev[1][0]; + res[1][2] = prev[1][1]; + + // Choose A + res[1][0] = (res[1][0] + ((prev[0][0] + prev[0][1]) % MOD + prev[0][2]) % MOD) % MOD; + + return cache[n]; + } +} +``` + +```cpp +class Solution { +private: + static constexpr int MOD = 1000000007; + vector> baseCase = {{1, 1, 0}, {1, 0, 0}}; + vector>> cache; + +public: + int checkRecord(int n) { + cache.assign(n + 1, vector>(2, vector(3, -1))); + const vector>& result = count(n); + int total = 0; + for (const auto& row : result) { + for (int val : row) { + total = (total + val) % MOD; + } + } + return total; + } + +private: + const vector>& count(int n) { + if (n == 1) { + return baseCase; + } + + if (cache[n][0][0] != -1) { + return cache[n]; + } + + const vector>& prev = count(n - 1); + auto& res = cache[n]; + + // Choose P + res[0][0] = ((prev[0][0] + prev[0][1]) % MOD + prev[0][2]) % MOD; + res[1][0] = ((prev[1][0] + prev[1][1]) % MOD + prev[1][2]) % MOD; + + // Choose L + res[0][1] = prev[0][0]; + res[0][2] = prev[0][1]; + res[1][1] = prev[1][0]; + res[1][2] = prev[1][1]; + + // Choose A + res[1][0] = (res[1][0] + ((prev[0][0] + prev[0][1]) % MOD + prev[0][2]) % MOD) % MOD; + + return cache[n]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + checkRecord(n) { + const MOD = 1000000007; + const baseCase = [ + [1, 1, 0], // (A = 0, L = 0, 1, 2) + [1, 0, 0] // (A = 1, L = 0, 1, 2) + ]; + let cache = Array.from({ length: n + 1 }, () => + Array.from({ length: 2 }, () => new Array(3).fill(-1)) + ); + + const count = (n) => { + if (n === 1) return baseCase; + if (cache[n][0][0] !== -1) return cache[n]; + + const prev = count(n - 1); + const res = cache[n]; + + // Choose P + res[0][0] = ((prev[0][0] + prev[0][1]) % MOD + prev[0][2]) % MOD; + res[1][0] = ((prev[1][0] + prev[1][1]) % MOD + prev[1][2]) % MOD; + + // Choose L + res[0][1] = prev[0][0]; + res[0][2] = prev[0][1]; + res[1][1] = prev[1][0]; + res[1][2] = prev[1][1]; + + // Choose A + res[1][0] = (res[1][0] + ((prev[0][0] + prev[0][1]) % MOD + prev[0][2]) % MOD) % MOD; + + return res; + }; + + const result = count(n); + let total = 0; + for (const row of result) { + for (const val of row) { + total = (total + val) % MOD; + } + } + return total; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 3. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def checkRecord(self, n: int) -> int: + MOD = 1000000007 + dp = [[[0 for _ in range(3)] for _ in range(2)] for _ in range(n + 1)] + + dp[0][0][0] = 1 # Base case + + for i in range(1, n + 1): + for cntA in range(2): + for cntL in range(3): + # Choose P + dp[i][cntA][0] = (dp[i][cntA][0] + dp[i - 1][cntA][cntL]) % MOD + + # Choose A + if cntA > 0: + dp[i][cntA][0] = (dp[i][cntA][0] + dp[i - 1][cntA - 1][cntL]) % MOD + + # Choose L + if cntL > 0: + dp[i][cntA][cntL] = (dp[i][cntA][cntL] + dp[i - 1][cntA][cntL - 1]) % MOD + + return sum(dp[n][cntA][cntL] for cntA in range(2) for cntL in range(3)) % MOD +``` + +```java +public class Solution { + public int checkRecord(int n) { + final int MOD = 1000000007; + int[][][] dp = new int[n + 1][2][3]; + + dp[0][0][0] = 1; + + for (int i = 1; i <= n; i++) { + for (int cntA = 0; cntA < 2; cntA++) { + for (int cntL = 0; cntL < 3; cntL++) { + // Choose P + dp[i][cntA][0] = (dp[i][cntA][0] + dp[i - 1][cntA][cntL]) % MOD; + + // Choose A + if (cntA > 0) { + dp[i][cntA][0] = (dp[i][cntA][0] + dp[i - 1][cntA - 1][cntL]) % MOD; + } + + // Choose L + if (cntL > 0) { + dp[i][cntA][cntL] = (dp[i][cntA][cntL] + dp[i - 1][cntA][cntL - 1]) % MOD; + } + } + } + } + + int result = 0; + for (int cntA = 0; cntA < 2; cntA++) { + for (int cntL = 0; cntL < 3; cntL++) { + result = (result + dp[n][cntA][cntL]) % MOD; + } + } + + return result; + } +} +``` + +```cpp +class Solution { +public: + int checkRecord(int n) { + const int MOD = 1000000007; + vector>> dp(n + 1, vector>(2, vector(3, 0))); + + dp[0][0][0] = 1; + + for (int i = 1; i <= n; i++) { + for (int cntA = 0; cntA < 2; cntA++) { + for (int cntL = 0; cntL < 3; cntL++) { + // Choose P + dp[i][cntA][0] = (dp[i][cntA][0] + dp[i - 1][cntA][cntL]) % MOD; + + // Choose A + if (cntA > 0) { + dp[i][cntA][0] = (dp[i][cntA][0] + dp[i - 1][cntA - 1][cntL]) % MOD; + } + + // Choose L + if (cntL > 0) { + dp[i][cntA][cntL] = (dp[i][cntA][cntL] + dp[i - 1][cntA][cntL - 1]) % MOD; + } + } + } + } + + int result = 0; + for (int cntA = 0; cntA < 2; cntA++) { + for (int cntL = 0; cntL < 3; cntL++) { + result = (result + dp[n][cntA][cntL]) % MOD; + } + } + + return result; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + checkRecord(n) { + const MOD = 1000000007; + const dp = Array.from({ length: n + 1 }, () => + Array.from({ length: 2 }, () => new Array(3).fill(0)) + ); + + dp[0][0][0] = 1; + + for (let i = 1; i <= n; i++) { + for (let cntA = 0; cntA < 2; cntA++) { + for (let cntL = 0; cntL < 3; cntL++) { + // Choose P + dp[i][cntA][0] = (dp[i][cntA][0] + dp[i - 1][cntA][cntL]) % MOD; + + // Choose A + if (cntA > 0) { + dp[i][cntA][0] = (dp[i][cntA][0] + dp[i - 1][cntA - 1][cntL]) % MOD; + } + + // Choose L + if (cntL > 0) { + dp[i][cntA][cntL] = (dp[i][cntA][cntL] + dp[i - 1][cntA][cntL - 1]) % MOD; + } + } + } + } + + let result = 0; + for (let cntA = 0; cntA < 2; cntA++) { + for (let cntL = 0; cntL < 3; cntL++) { + result = (result + dp[n][cntA][cntL]) % MOD; + } + } + + return result; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 4. Dynamic Programming (Space Optimized) - I + +::tabs-start + +```python +class Solution: + def checkRecord(self, n: int) -> int: + if n == 1: + return 3 + + MOD = 10**9 + 7 + dp = { + (0, 0): 1, (0, 1): 1, (0, 2): 0, + (1, 0): 1, (1, 1): 0, (1, 2): 0 + } + + for i in range(n - 1): + ndp = defaultdict(int) + + # Choose P + ndp[(0, 0)] = ((dp[(0, 0)] + dp[(0, 1)]) % MOD + dp[(0, 2)]) % MOD + ndp[(1, 0)] = ((dp[(1, 0)] + dp[(1, 1)]) % MOD + dp[(1, 2)]) % MOD + + # Choose L + ndp[(0, 1)] = dp[(0, 0)] + ndp[(1, 1)] = dp[(1, 0)] + ndp[(0, 2)] = dp[(0, 1)] + ndp[(1, 2)] = dp[(1, 1)] + + # Choose A + ndp[(1, 0)] = (ndp[(1, 0)] + (((dp[(0, 0)] + dp[(0, 1)]) % MOD + dp[(0, 2)]) % MOD)) % MOD + + dp = ndp + + return sum(dp.values()) % MOD +``` + +```java +public class Solution { + public int checkRecord(int n) { + if (n == 1) return 3; + + final int MOD = 1000000007; + int[][] dp = {{1, 1, 0}, {1, 0, 0}}; + + for (int i = 0; i < n - 1; i++) { + int[][] ndp = new int[2][3]; + + // Choose P + ndp[0][0] = ((dp[0][0] + dp[0][1]) % MOD + dp[0][2]) % MOD; + ndp[1][0] = ((dp[1][0] + dp[1][1]) % MOD + dp[1][2]) % MOD; + + // Choose L + ndp[0][1] = dp[0][0]; + ndp[1][1] = dp[1][0]; + ndp[0][2] = dp[0][1]; + ndp[1][2] = dp[1][1]; + + // Choose A + ndp[1][0] = (ndp[1][0] + ((dp[0][0] + dp[0][1]) % MOD + dp[0][2]) % MOD) % MOD; + + dp = ndp; + } + + int total = 0; + for (int[] row : dp) { + for (int val : row) { + total = (total + val) % MOD; + } + } + return total; + } +} +``` + +```cpp +class Solution { +public: + int checkRecord(int n) { + if (n == 1) return 3; + + const int MOD = 1000000007; + vector> dp = {{1, 1, 0}, {1, 0, 0}}; + + for (int i = 0; i < n - 1; i++) { + vector> ndp(2, vector(3, 0)); + + // Choose P + ndp[0][0] = ((dp[0][0] + dp[0][1]) % MOD + dp[0][2]) % MOD; + ndp[1][0] = ((dp[1][0] + dp[1][1]) % MOD + dp[1][2]) % MOD; + + // Choose L + ndp[0][1] = dp[0][0]; + ndp[1][1] = dp[1][0]; + ndp[0][2] = dp[0][1]; + ndp[1][2] = dp[1][1]; + + // Choose A + ndp[1][0] = (ndp[1][0] + ((dp[0][0] + dp[0][1]) % MOD + dp[0][2]) % MOD) % MOD; + + swap(dp, ndp); + } + + int total = 0; + for (auto& row : dp) { + for (int val : row) { + total = (total + val) % MOD; + } + } + return total; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + checkRecord(n) { + if (n === 1) return 3; + + const MOD = 1000000007; + let dp = [[1, 1, 0], [1, 0, 0]]; + + for (let i = 0; i < n - 1; i++) { + let ndp = Array.from({ length: 2 }, () => new Array(3).fill(0)); + + // Choose P + ndp[0][0] = ((dp[0][0] + dp[0][1]) % MOD + dp[0][2]) % MOD; + ndp[1][0] = ((dp[1][0] + dp[1][1]) % MOD + dp[1][2]) % MOD; + + // Choose L + ndp[0][1] = dp[0][0]; + ndp[1][1] = dp[1][0]; + ndp[0][2] = dp[0][1]; + ndp[1][2] = dp[1][1]; + + // Choose A + ndp[1][0] = (ndp[1][0] + ((dp[0][0] + dp[0][1]) % MOD + dp[0][2]) % MOD) % MOD; + + [dp, ndp] = [ndp, dp]; + } + + let total = 0; + for (let row of dp) { + for (let val of row) { + total = (total + val) % MOD; + } + } + return total; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ + +--- + +## 5. Dynamic Programming (Space Optimized) - II + +::tabs-start + +```python +class Solution: + def checkRecord(self, n: int) -> int: + MOD = 1000000007 + dp = [[0] * 3 for _ in range(2)] + + dp[0][0] = 1 # Base case + + for i in range(1, n + 1): + next_dp = [[0] * 3 for _ in range(2)] + + for cntA in range(2): + for cntL in range(3): + # Choose P + next_dp[cntA][0] = (next_dp[cntA][0] + dp[cntA][cntL]) % MOD + + # Choose A + if cntA > 0: + next_dp[cntA][0] = (next_dp[cntA][0] + dp[cntA - 1][cntL]) % MOD + + # Choose L + if cntL > 0: + next_dp[cntA][cntL] = (next_dp[cntA][cntL] + dp[cntA][cntL - 1]) % MOD + + dp = next_dp + + return sum(dp[cntA][cntL] for cntA in range(2) for cntL in range(3)) % MOD +``` + +```java +public class Solution { + public int checkRecord(int n) { + final int MOD = 1000000007; + int[][] dp = new int[2][3]; + + dp[0][0] = 1; + + for (int i = 1; i <= n; i++) { + int[][] nextDp = new int[2][3]; + + for (int cntA = 0; cntA < 2; cntA++) { + for (int cntL = 0; cntL < 3; cntL++) { + // Choose P + nextDp[cntA][0] = (nextDp[cntA][0] + dp[cntA][cntL]) % MOD; + + // Choose A + if (cntA > 0) { + nextDp[cntA][0] = (nextDp[cntA][0] + dp[cntA - 1][cntL]) % MOD; + } + + // Choose L + if (cntL > 0) { + nextDp[cntA][cntL] = (nextDp[cntA][cntL] + dp[cntA][cntL - 1]) % MOD; + } + } + } + + dp = nextDp; + } + + int result = 0; + for (int cntA = 0; cntA < 2; cntA++) { + for (int cntL = 0; cntL < 3; cntL++) { + result = (result + dp[cntA][cntL]) % MOD; + } + } + return result; + } +} +``` + +```cpp +class Solution { +public: + int checkRecord(int n) { + const int MOD = 1000000007; + vector> dp(2, vector(3, 0)); + + dp[0][0] = 1; + + for (int i = 1; i <= n; i++) { + vector> nextDp(2, vector(3, 0)); + + for (int cntA = 0; cntA < 2; cntA++) { + for (int cntL = 0; cntL < 3; cntL++) { + // Choose P + nextDp[cntA][0] = (nextDp[cntA][0] + dp[cntA][cntL]) % MOD; + + // Choose A + if (cntA > 0) { + nextDp[cntA][0] = (nextDp[cntA][0] + dp[cntA - 1][cntL]) % MOD; + } + + // Choose L + if (cntL > 0) { + nextDp[cntA][cntL] = (nextDp[cntA][cntL] + dp[cntA][cntL - 1]) % MOD; + } + } + } + + dp = nextDp; + } + + int result = 0; + for (int cntA = 0; cntA < 2; cntA++) { + for (int cntL = 0; cntL < 3; cntL++) { + result = (result + dp[cntA][cntL]) % MOD; + } + } + + return result; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + checkRecord(n) { + const MOD = 1000000007; + let dp = Array.from({ length: 2 }, () => new Array(3).fill(0)); + + dp[0][0] = 1; + + for (let i = 1; i <= n; i++) { + let nextDp = Array.from({ length: 2 }, () => new Array(3).fill(0)); + + for (let cntA = 0; cntA < 2; cntA++) { + for (let cntL = 0; cntL < 3; cntL++) { + // Choose P + nextDp[cntA][0] = (nextDp[cntA][0] + dp[cntA][cntL]) % MOD; + + // Choose A + if (cntA > 0) { + nextDp[cntA][0] = (nextDp[cntA][0] + dp[cntA - 1][cntL]) % MOD; + } + + // Choose L + if (cntL > 0) { + nextDp[cntA][cntL] = (nextDp[cntA][cntL] + dp[cntA][cntL - 1]) % MOD; + } + } + } + + dp = nextDp; + } + + let result = 0; + for (let cntA = 0; cntA < 2; cntA++) { + for (let cntL = 0; cntL < 3; cntL++) { + result = (result + dp[cntA][cntL]) % MOD; + } + } + + return result; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ \ No newline at end of file From 822c53a55c4c99d8cc894bc2d3f27ee5fc9d79fb Mon Sep 17 00:00:00 2001 From: Sri Hari <94112314+Srihari2222@users.noreply.github.com> Date: Mon, 10 Mar 2025 19:58:58 +0530 Subject: [PATCH 04/12] Sri Hari: Batch-6/Neetcode-150/Added-hints (#3909) * Batch-6/Neetcode-150/Added-hints * Batch-6/Neetcode-150/Added-hints * Batch-6/Neetcode-150/Added-hints * Batch-6/Neetcode-150/Added-hints * Batch-6/Neetcode-150/Added-hints --- articles/counting-bits.md | 26 ++++++---- articles/insert-new-interval.md | 12 +++-- articles/merge-intervals.md | 4 +- articles/plus-one.md | 14 +++--- articles/set-zeroes-in-matrix.md | 2 +- articles/spiral-matrix.md | 12 +++-- articles/string-encode-and-decode.md | 8 ++-- .../subarrays-with-k-different-integers.md | 2 +- hints/burst-balloons.md | 39 +++++++++++++++ hints/buy-and-sell-crypto-with-cooldown.md | 39 +++++++++++++++ hints/coin-change-ii.md | 39 +++++++++++++++ hints/count-paths.md | 39 +++++++++++++++ hints/count-squares.md | 39 +++++++++++++++ hints/count-subsequences.md | 39 +++++++++++++++ hints/counting-bits.md | 31 ++++++++++++ hints/edit-distance.md | 39 +++++++++++++++ hints/gas-station.md | 31 ++++++++++++ hints/hand-of-straights.md | 31 ++++++++++++ hints/insert-new-interval.md | 31 ++++++++++++ hints/interleaving-string.md | 39 +++++++++++++++ hints/jump-game-ii.md | 39 +++++++++++++++ hints/jump-game.md | 39 +++++++++++++++ hints/longest-common-subsequence.md | 31 ++++++++++++ hints/longest-increasing-path-in-matrix.md | 23 +++++++++ hints/longest-increasing-subsequence.md | 47 +++++++++++++++++++ hints/maximum-product-subarray.md | 31 ++++++++++++ hints/maximum-subarray.md | 39 +++++++++++++++ hints/meeting-schedule-ii.md | 39 +++++++++++++++ hints/meeting-schedule.md | 31 ++++++++++++ hints/merge-intervals.md | 39 +++++++++++++++ hints/merge-triplets-to-form-target.md | 31 ++++++++++++ hints/minimum-interval-including-query.md | 31 ++++++++++++ hints/missing-number.md | 39 +++++++++++++++ hints/multiply-strings.md | 39 +++++++++++++++ hints/non-cyclical-number.md | 23 +++++++++ hints/non-overlapping-intervals.md | 39 +++++++++++++++ hints/number-of-one-bits.md | 31 ++++++++++++ hints/partition-equal-subset-sum.md | 39 +++++++++++++++ hints/partition-labels.md | 31 ++++++++++++ hints/plus-one.md | 23 +++++++++ hints/pow-x-n.md | 39 +++++++++++++++ hints/regular-expression-matching.md | 39 +++++++++++++++ hints/reverse-bits.md | 31 ++++++++++++ hints/reverse-integer.md | 31 ++++++++++++ hints/rotate-matrix.md | 31 ++++++++++++ hints/set-zeroes-in-matrix.md | 39 +++++++++++++++ hints/single-number.md | 39 +++++++++++++++ hints/spiral-matrix.md | 31 ++++++++++++ hints/string-encode-and-decode.md | 2 +- hints/sum-of-two-integers.md | 39 +++++++++++++++ hints/target-sum.md | 31 ++++++++++++ hints/valid-parenthesis-string.md | 39 +++++++++++++++ hints/word-break.md | 31 ++++++++++++ 53 files changed, 1594 insertions(+), 28 deletions(-) create mode 100644 hints/burst-balloons.md create mode 100644 hints/buy-and-sell-crypto-with-cooldown.md create mode 100644 hints/coin-change-ii.md create mode 100644 hints/count-paths.md create mode 100644 hints/count-squares.md create mode 100644 hints/count-subsequences.md create mode 100644 hints/counting-bits.md create mode 100644 hints/edit-distance.md create mode 100644 hints/gas-station.md create mode 100644 hints/hand-of-straights.md create mode 100644 hints/insert-new-interval.md create mode 100644 hints/interleaving-string.md create mode 100644 hints/jump-game-ii.md create mode 100644 hints/jump-game.md create mode 100644 hints/longest-common-subsequence.md create mode 100644 hints/longest-increasing-path-in-matrix.md create mode 100644 hints/longest-increasing-subsequence.md create mode 100644 hints/maximum-product-subarray.md create mode 100644 hints/maximum-subarray.md create mode 100644 hints/meeting-schedule-ii.md create mode 100644 hints/meeting-schedule.md create mode 100644 hints/merge-intervals.md create mode 100644 hints/merge-triplets-to-form-target.md create mode 100644 hints/minimum-interval-including-query.md create mode 100644 hints/missing-number.md create mode 100644 hints/multiply-strings.md create mode 100644 hints/non-cyclical-number.md create mode 100644 hints/non-overlapping-intervals.md create mode 100644 hints/number-of-one-bits.md create mode 100644 hints/partition-equal-subset-sum.md create mode 100644 hints/partition-labels.md create mode 100644 hints/plus-one.md create mode 100644 hints/pow-x-n.md create mode 100644 hints/regular-expression-matching.md create mode 100644 hints/reverse-bits.md create mode 100644 hints/reverse-integer.md create mode 100644 hints/rotate-matrix.md create mode 100644 hints/set-zeroes-in-matrix.md create mode 100644 hints/single-number.md create mode 100644 hints/spiral-matrix.md create mode 100644 hints/sum-of-two-integers.md create mode 100644 hints/target-sum.md create mode 100644 hints/valid-parenthesis-string.md create mode 100644 hints/word-break.md diff --git a/articles/counting-bits.md b/articles/counting-bits.md index 514bef953..ac8139aba 100644 --- a/articles/counting-bits.md +++ b/articles/counting-bits.md @@ -124,8 +124,10 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +* Time complexity: $O(n \log n)$ +* Space complexity: + * $O(1)$ extra space. + * $O(n)$ space for the output array. --- @@ -248,8 +250,10 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +* Time complexity: $O(n \log n)$ +* Space complexity: + * $O(1)$ extra space. + * $O(n)$ space for the output array. --- @@ -338,8 +342,10 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +* Time complexity: $O(n \log n)$ +* Space complexity: + * $O(1)$ extra space. + * $O(n)$ space for the output array. --- @@ -470,7 +476,9 @@ class Solution { ### Time & Space Complexity * Time complexity: $O(n)$ -* Space complexity: $O(1)$ +* Space complexity: + * $O(1)$ extra space. + * $O(n)$ space for the output array. --- @@ -567,4 +575,6 @@ class Solution { ### Time & Space Complexity * Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +* Space complexity: + * $O(1)$ extra space. + * $O(n)$ space for the output array. \ No newline at end of file diff --git a/articles/insert-new-interval.md b/articles/insert-new-interval.md index e35159e6e..367a09391 100644 --- a/articles/insert-new-interval.md +++ b/articles/insert-new-interval.md @@ -221,7 +221,9 @@ class Solution { ### Time & Space Complexity * Time complexity: $O(n)$ -* Space complexity: $O(1)$ +* Space complexity: + * $O(1)$ extra space. + * $O(n)$ space for the output list. --- @@ -515,7 +517,9 @@ class Solution { ### Time & Space Complexity * Time complexity: $O(n)$ -* Space complexity: $O(1)$ +* Space complexity: + * $O(1)$ extra space. + * $O(n)$ space for the output list. --- @@ -708,4 +712,6 @@ class Solution { ### Time & Space Complexity * Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +* Space complexity: + * $O(1)$ extra space. + * $O(n)$ space for the output list. \ No newline at end of file diff --git a/articles/merge-intervals.md b/articles/merge-intervals.md index 56f8a6313..4ff97b569 100644 --- a/articles/merge-intervals.md +++ b/articles/merge-intervals.md @@ -169,7 +169,9 @@ class Solution { ### Time & Space Complexity * Time complexity: $O(n \log n)$ -* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. +* Space complexity: + * $O(1)$ or $O(n)$ space depending on the sorting algorithm. + * $O(n)$ for the output list. --- diff --git a/articles/plus-one.md b/articles/plus-one.md index 242d171fb..4b51b5b0c 100644 --- a/articles/plus-one.md +++ b/articles/plus-one.md @@ -139,7 +139,7 @@ class Solution { --- -## 2. Iteration +## 2. Iteration - I ::tabs-start @@ -148,7 +148,7 @@ class Solution: def plusOne(self, digits: List[int]) -> List[int]: one = 1 i = 0 - digits = digits[::-1] + digits.reverse() while one: if i < len(digits): @@ -161,7 +161,9 @@ class Solution: digits.append(one) one = 0 i += 1 - return digits[::-1] + + digits.reverse() + return digits ``` ```java @@ -344,11 +346,11 @@ class Solution { ### Time & Space Complexity * Time complexity: $O(n)$ -* Space complexity: $O(1)$ +* Space complexity: $O(1)$ or $O(n)$ depending on the language. --- -## 3. Iteration (Optimal) +## 3. Iteration - II ::tabs-start @@ -479,4 +481,4 @@ class Solution { ### Time & Space Complexity * Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +* Space complexity: $O(n)$ \ No newline at end of file diff --git a/articles/set-zeroes-in-matrix.md b/articles/set-zeroes-in-matrix.md index 905883b5c..5a265e1f5 100644 --- a/articles/set-zeroes-in-matrix.md +++ b/articles/set-zeroes-in-matrix.md @@ -212,7 +212,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(m * n)$ +* Time complexity: $O((m * n) * (m + n))$ * Space complexity: $O(m * n)$ > Where $m$ is the number of rows and $n$ is the number of columns. diff --git a/articles/spiral-matrix.md b/articles/spiral-matrix.md index b9719b928..7935874fc 100644 --- a/articles/spiral-matrix.md +++ b/articles/spiral-matrix.md @@ -203,7 +203,9 @@ class Solution { ### Time & Space Complexity * Time complexity: $O(m * n)$ -* Space complexity: $O(min(m, n))$ +* Space complexity: + * $O(min(m, n))$ space for recursion stack. + * $O(m * n)$ space for the output list. > Where $m$ is the number of rows and $n$ is the number of columns. @@ -467,7 +469,9 @@ class Solution { ### Time & Space Complexity * Time complexity: $O(m * n)$ -* Space complexity: $O(1)$ +* Space complexity: + * $O(1)$ extra space. + * $O(m * n)$ space for the output list. > Where $m$ is the number of rows and $n$ is the number of columns. @@ -655,6 +659,8 @@ class Solution { ### Time & Space Complexity * Time complexity: $O(m * n)$ -* Space complexity: $O(1)$ +* Space complexity: + * $O(1)$ extra space. + * $O(m * n)$ space for the output list. > Where $m$ is the number of rows and $n$ is the number of columns. \ No newline at end of file diff --git a/articles/string-encode-and-decode.md b/articles/string-encode-and-decode.md index c0cad7e12..b60d5115e 100644 --- a/articles/string-encode-and-decode.md +++ b/articles/string-encode-and-decode.md @@ -286,8 +286,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(m)$ for $encode()$ and $decode()$. -* Space complexity: $O(n)$ for $encode()$ and $decode()$. +* Time complexity: $O(m)$ for each $encode()$ and $decode()$ function calls. +* Space complexity: $O(m + n)$ for each $encode()$ and $decode()$ function calls. > Where $m$ is the sum of lengths of all the strings and $n$ is the number of strings. @@ -510,7 +510,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(m)$ for $encode()$ and $decode()$. -* Space complexity: $O(1)$ for $encode()$ and $decode()$. +* Time complexity: $O(m)$ for each $encode()$ and $decode()$ function calls. +* Space complexity: $O(m + n)$ for each $encode()$ and $decode()$ function calls. > Where $m$ is the sum of lengths of all the strings and $n$ is the number of strings. \ No newline at end of file diff --git a/articles/subarrays-with-k-different-integers.md b/articles/subarrays-with-k-different-integers.md index 26328205c..a2e24a470 100644 --- a/articles/subarrays-with-k-different-integers.md +++ b/articles/subarrays-with-k-different-integers.md @@ -246,7 +246,7 @@ class Solution { --- -## 3. Slidingt Window (One Pass) - I +## 3. Sliding Window (One Pass) - I ::tabs-start diff --git a/hints/burst-balloons.md b/hints/burst-balloons.md new file mode 100644 index 000000000..c553a4f8e --- /dev/null +++ b/hints/burst-balloons.md @@ -0,0 +1,39 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(n ^ 3) time and O(n ^ 2) space, where n is the size of the input array. +

+
+ +
+
+ Hint 1 +

+ Try to simulate the process recursively by passing the array to the recursive function. At each step, iterate through the array, pop an element, and recursively apply the same process to the two subarrays on both sides of the popped element, returning the maximum result from all recursive paths. This approach is exponential. Can you think of a way to optimize it? Maybe you should consider observing the subproblems instead of modifying the array. +

+
+ +
+
+ Hint 2 +

+ Instead of passing the array, we can pass the range of indices l and r that need to be processed. We pad the input array with 1s on both sides for easier computation, but l and r represent the first and last indices of the original input array. Can you think of a reverse engineering approach for popping elements? +

+
+ +
+
+ Hint 3 +

+ We determine the result by considering each element as the last one to be popped in the current range. For each element, we calculate its value by multiplying it with the elements at l - 1 and r + 1, then recursively solve the subproblems for the ranges (l, i - 1) and (i + 1, r), where i is the current element in the given range. Can you think of a way to optimize and avoid redundant calculations? +

+
+ +
+
+ Hint 4 +

+ We can use memoization to cache the results of recursive calls and avoid redundant calculations. A hash map or a 2D array can be used to store results since the recursive function parameters l and r are within the range of the input array size. +

+
\ No newline at end of file diff --git a/hints/buy-and-sell-crypto-with-cooldown.md b/hints/buy-and-sell-crypto-with-cooldown.md new file mode 100644 index 000000000..84988bd54 --- /dev/null +++ b/hints/buy-and-sell-crypto-with-cooldown.md @@ -0,0 +1,39 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution as good or better than O(n) time and O(n) space, where n is the size of the input array. +

+
+ +
+
+ Hint 1 +

+ Try to think in terms of recursion and visualize it as a decision tree. Can you determine the possible decisions at each recursion step? Also, can you identify the base cases and the essential information that needs to be tracked during recursion? +

+
+ +
+
+ Hint 2 +

+ At each recursion step, we can buy only if we haven't already bought a coin, or we can sell if we own one. When buying, we subtract the coin value, and when selling, we add it. We explore all possible buying and selling options recursively, iterating through the coins from left to right using index i. For the cooldown condition, if we buy a coin, we increment the index i by two. +

+
+ +
+
+ Hint 3 +

+ We can use a boolean variable canBuy to indicate whether buying is allowed at the current recursive step. If we go out of bounds, we return 0. This approach is exponential. Can you think of a way to optimize it? +

+
+ +
+
+ Hint 4 +

+ We can use memoization to cache the results of recursive calls and avoid recalculations. A hash map or a 2D array can be used to store these results. +

+
\ No newline at end of file diff --git a/hints/coin-change-ii.md b/hints/coin-change-ii.md new file mode 100644 index 000000000..3f18a6318 --- /dev/null +++ b/hints/coin-change-ii.md @@ -0,0 +1,39 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution as good or better than O(n * a) time and O(n * a) space, where n is the number of coins and a is the given amount. +

+
+ +
+
+ Hint 1 +

+ As we need to find the total number of combinations, think in terms of recursion and visualize it as a decision tree where multiple coin choices are available at each recursion step. Can you determine a way to allow picking the same coin multiple times? Maybe you should consider the decisions made at each recursion step. +

+
+ +
+
+ Hint 2 +

+ The given coins are unique. We recursively iterate through the coins array using index i, tracking the collected amount along the current path. At each step, we can either skip the current coin or pick it, ensuring the total does not exceed the target. To allow picking the same coin multiple times, we recurse with the same index but an updated amount, generating different combinations. +

+
+ +
+
+ Hint 3 +

+ If we reach the target amount, we return 1. The recursion stops if the index goes out of bounds. We count all possible ways and return the total. This approach is exponential. Can you think of a way to optimize it? Maybe you should consider an approach to avoid redundant computations. +

+
+ +
+
+ Hint 4 +

+ We can use memoization to cache the results of recursive calls and avoid redundant computations. A hash map or a 2D array can be used to store these results. +

+
\ No newline at end of file diff --git a/hints/count-paths.md b/hints/count-paths.md new file mode 100644 index 000000000..299793547 --- /dev/null +++ b/hints/count-paths.md @@ -0,0 +1,39 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution as good or better than O(m * n) time and O(m * n) space, where m is the number of rows and n is the number of columns in the grid. +

+
+ +
+
+ Hint 1 +

+ Try to think in terms of recursion and visualize it as a decision tree, where we have two choices at each step. Can you determine the base condition and recurrence relation? +

+
+ +
+
+ Hint 2 +

+ We recursively traverse the grid using row i and column j. At each step, we explore both possibilities: moving down or moving right, ensuring we do not go out of bounds. If we reach the bottom-right cell, we return 1. +

+
+ +
+
+ Hint 3 +

+ This approach has exponential complexity. Can you think of a way to optimize the recursion? Maybe you should consider using a dynamic programming approach. +

+
+ +
+
+ Hint 4 +

+ We can use memoization to cache the results of recursive calls and avoid recalculations. A hash map or a 2D array can be used to store these results. +

+
\ No newline at end of file diff --git a/hints/count-squares.md b/hints/count-squares.md new file mode 100644 index 000000000..69b289bdb --- /dev/null +++ b/hints/count-squares.md @@ -0,0 +1,39 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(1) time for each add() call, O(n) time for each count() call, and O(n) space, where n is the total number of points. +

+
+ +
+
+ Hint 1 +

+ Initially, we can store the points in a global list for the add() call. For the count() call, a brute force approach would use three nested loops to check other points except for the query point, resulting in an O(n^3) time solution. Can you think of a better way? Maybe you should consider the observation that can be drawn from the diagonal of a square. +

+
+ +
+
+ Hint 2 +

+ In a square's diagonal, the absolute difference between the x-coordinates is equal to the absolute difference between the y-coordinates of the two endpoints, and neither difference can be zero. Using these two points, we can determine the other diagonal endpoints. +

+
+ +
+
+ Hint 3 +

+ We store points in a hash map instead of a list for O(1) lookups, treating duplicate points as one while tracking their frequencies. For the count() function, we iterate through points that, along with the query point, can form a diagonal. Let the query point be (qx, qy) and the other point be (x, y), ensuring they form a diagonal. What could be the other two points? Maybe you should consider the points forming a right-to-left diagonal, treating (qx, qy) as the top-right corner. +

+
+ +
+
+ Hint 4 +

+ The other two points are point1 (x, qy) and point2 (qx, y). For counting, we simply add count of point1 * count of point2 to the result res. +

+
\ No newline at end of file diff --git a/hints/count-subsequences.md b/hints/count-subsequences.md new file mode 100644 index 000000000..53a37dcee --- /dev/null +++ b/hints/count-subsequences.md @@ -0,0 +1,39 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution as good or better than O(m * n) time and O(m * n) space, where m is the length of the string s and n is the length of the string t. +

+
+ +
+
+ Hint 1 +

+ Try to think in terms of recursion and visualize it as a decision tree, as we need to explore all subsequences of s. Can you determine the possible decisions at each recursion step? +

+
+ +
+
+ Hint 2 +

+ We recursively iterate through the strings using indices i and j for s and t, respectively. At each recursion step, we can either skip the current character of s or include it in the current path if it matches the current character of t. Can you determine the base conditions for this recursive function? +

+
+ +
+
+ Hint 3 +

+ If index j goes out of bounds, we return 1 as a valid subsequence is found. If index i goes out of bounds first, we return 0. At each recursion step, we return the sum of both paths. This approach is exponential. Can you think of a way to optimize it? +

+
+ +
+
+ Hint 4 +

+ We can use memoization to cache the results of recursive calls and avoid redundant computations. A hash map or a 2D array can be used to store these results. +

+
\ No newline at end of file diff --git a/hints/counting-bits.md b/hints/counting-bits.md new file mode 100644 index 000000000..45188a165 --- /dev/null +++ b/hints/counting-bits.md @@ -0,0 +1,31 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(n) time and O(n) space, where n is the given integer. +

+
+ +
+
+ Hint 1 +

+ A straightforward approach would be to iterate from 0 to n using i, and for each i, iterate through its bits to count the number of set bits. This would result in an O(n \log n) approach. Can you think of a better way? Maybe you should try identifying a pattern by observing the bitwise representation of consecutive numbers. +

+
+ +
+
+ Hint 2 +

+ For example, to compute set bits for 7, add 1 to the count of set bits in 3, which was previously computed by adding 1 to the count of set bits in 1. Observing the pattern, for numbers less than 4, add 1 to the count from two positions before. For numbers less than 8, add 1 to the count from four positions before. Can you derive a dynamic programming relation from this? +

+
+ +
+
+ Hint 3 +

+ We find an offset for the current number based on the number before offset positions. The dynamic programming relation is dp[i] = 1 + dp[i - offset], where dp[i] represents the number of set bits in i. The offset starts at 1 and updates when encountering a power of 2. To simplify the power of 2 check, if offset * 2 equals the current number, we update offset to the current number. +

+
\ No newline at end of file diff --git a/hints/edit-distance.md b/hints/edit-distance.md new file mode 100644 index 000000000..277fa3cbe --- /dev/null +++ b/hints/edit-distance.md @@ -0,0 +1,39 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution as good or better than O(m * n) time and O(m * n) space, where m and n are the lengths of the strings word1 and word2, respectively. +

+
+ +
+
+ Hint 1 +

+ Try to think in terms of recursion and visualize it as a decision tree, as we have choices at each recursion step. Can you determine the recurrence relation and base cases? +

+
+ +
+
+ Hint 2 +

+ We recursively iterate through the strings using indices i and j for word1 and word2, respectively. If the characters at the current indices match, we increment both indices without counting an operation. Otherwise, we have three choices: insert the character at the current index of word1 (increment j), delete the current character of word1 (increment i), or replace the character at index i in word1 (increment both i and j). +

+
+ +
+
+ Hint 3 +

+ If index i goes out of bounds, we return the number of remaining characters in word2 (using insert operations). If index j goes out of bounds, we return the number of remaining characters in word1 (using delete operations). At each step, we return the minimum operation path. This approach is exponential. Can you think of a way to optimize it? +

+
+ +
+
+ Hint 4 +

+ We can use memoization to cache the results and avoid redundant calculations. A hash map or a 2D array can be used to store these results. +

+
\ No newline at end of file diff --git a/hints/gas-station.md b/hints/gas-station.md new file mode 100644 index 000000000..52464072d --- /dev/null +++ b/hints/gas-station.md @@ -0,0 +1,31 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(n) time and O(1) space, where n is the size of the input array. +

+
+ +
+
+ Hint 1 +

+ A brute force approach would be to start at each gas station, simulate the process, and return the index where completing the circuit is possible. This would be an O(n^2) time solution. Can you think of a better way? Maybe a greedy approach works. +

+
+ +
+
+ Hint 2 +

+ We can immediately return -1 if sum(gas) < sum(cost), as completing the circuit is impossible due to insufficient gas. Otherwise, a solution always exists because the total gas is sufficient to cover the total cost, meaning there must be a valid starting point that allows completing the circuit. +

+
+ +
+
+ Hint 3 +

+ We start with a variable total to track the gas balance and initialize the result index to 0. As we iterate through the array with index i, we accumulate the difference (gas[i] - cost[i]). If total becomes negative at any index, we reset it to 0 and update the result index to (i + 1). +

+
\ No newline at end of file diff --git a/hints/hand-of-straights.md b/hints/hand-of-straights.md new file mode 100644 index 000000000..1a35e0287 --- /dev/null +++ b/hints/hand-of-straights.md @@ -0,0 +1,31 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution as good or better than O(nlogn) time and O(n) space, where n is the size of the input array. +

+
+ +
+
+ Hint 1 +

+ It is observed that to form a group, the minimum value should be the starting value of the group. Additionally, the minimum value in the array serves as the starting value for one or more groups based on its frequency. Can you think of an efficient way to determine the frequencies of array elements? Maybe a specific data structure can be useful here. +

+
+ +
+
+ Hint 2 +

+ We can use a hash map to store the elements along with their frequencies. Additionally, we sort the given array. Then, we iterate through the sorted array and try to form groups by decrementing the frequency count. If we fail to form a group at any step, we immediately return false. Can you think why this works? +

+
+ +
+
+ Hint 3 +

+ Sorting ensures we start with the smallest available value, while the hash map helps track element availability using frequency counts. At each step, we pick the smallest available value x and attempt to form a group from x to x + groupSize - 1. If all elements are present based on their frequency counts, we decrement their counts as we iterate. If we successfully form all groups, we return true; otherwise, we return false. +

+
\ No newline at end of file diff --git a/hints/insert-new-interval.md b/hints/insert-new-interval.md new file mode 100644 index 000000000..a807b4c61 --- /dev/null +++ b/hints/insert-new-interval.md @@ -0,0 +1,31 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(n) time and O(1) extra space, where n is the size of the input array. +

+
+ +
+
+ Hint 1 +

+ The given intervals are non-overlapping and sorted in ascending order based on the start value. Try to visualize them as line segments and consider how a new interval can be inserted. Maybe you should analyze different cases of inserting a new interval. +

+
+ +
+
+ Hint 2 +

+ First, we append all intervals to the output list that have an end value smaller than the start value of the new interval. Then, we encounter one of three cases: we have appended all intervals, we reach an interval whose start value is greater than the new interval’s end, or we find an overlapping interval. Can you think of a way to handle these cases efficiently? +

+
+ +
+
+ Hint 3 +

+ We iterate through the remaining intervals, updating the new interval if its end value is greater than or equal to the current interval's start value. We adjust the start and end of the new interval to the minimum and maximum values, respectively. After this, any remaining intervals are appended to the output list, and we return the result. +

+
\ No newline at end of file diff --git a/hints/interleaving-string.md b/hints/interleaving-string.md new file mode 100644 index 000000000..16a8c100a --- /dev/null +++ b/hints/interleaving-string.md @@ -0,0 +1,39 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution as good or better than O(m * n) time and O(m * n) space, where m is the length of the string s1 and n is the length of the string s2. +

+
+ +
+
+ Hint 1 +

+ If the sum of the characters in s1 and s2 does not equal s3, we return false. Think in terms of recursion and visualize it as a decision tree, where we explore different combinations of portions from both strings. Can you determine the possible decisions at each recursion step? +

+
+ +
+
+ Hint 2 +

+ We recursively iterate through the strings using indices i, j, and k for s1, s2, and s3, respectively. At each step, we extend the current path in two directions based on whether the k-th character of s3 matches the current character of s1 or s2. If any path returns true, we immediately return true. If k goes out of bounds, it means we have successfully formed the interleaved string, so we return true. +

+
+ +
+
+ Hint 3 +

+ This approach is exponential. Can you think of a way to optimize it? Since k depends on i and j, it can be treated as a constant, as we can derive k using i + j. +

+
+ +
+
+ Hint 4 +

+ We can use memoization to cache the results of recursive calls and avoid redundant computations. Treating i and j as states, we can use a hash map or a 2D array to store the results. +

+
\ No newline at end of file diff --git a/hints/jump-game-ii.md b/hints/jump-game-ii.md new file mode 100644 index 000000000..4c7c41e30 --- /dev/null +++ b/hints/jump-game-ii.md @@ -0,0 +1,39 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(n) time and O(1) space, where n is the size of the input array. +

+
+ +
+
+ Hint 1 +

+ A brute force approach would be to recursively explore all paths from index 0 to its reachable indices, then process those indices similarly and return the minimum steps to reach the last index. This would be an exponential approach. Can you think of a better way? Maybe a greedy approach works. +

+
+ +
+
+ Hint 2 +

+ We maintain two pointers, l and r, initially set to 0, representing the range of reachable indices. At each step, we iterate through the indices in the range l to r and determine the farthest index that can be reached from the current range. +

+
+ +
+
+ Hint 3 +

+ We then update the pointers l and r to the next range, setting l to r + 1 and r to the farthest index reachable from the current range. We continue this process until the pointers go out of bounds. +

+
+ +
+
+ Hint 4 +

+ The number of steps taken represents the minimum steps required to reach the last index, as it is guaranteed that we can reach it. +

+
\ No newline at end of file diff --git a/hints/jump-game.md b/hints/jump-game.md new file mode 100644 index 000000000..91e7092c9 --- /dev/null +++ b/hints/jump-game.md @@ -0,0 +1,39 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(n) time and O(1) space, where n is the size of input array. +

+
+ +
+
+ Hint 1 +

+ A brute force approach would be to recursively explore all paths from index 0 to its reachable indices, then process those indices similarly, returning true if we reach the last index. This would be an exponential approach. Can you think of a better way? Maybe a greedy approach works. +

+
+ +
+
+ Hint 2 +

+ Instead of processing the array from index 0, start from the last index. Let the target index be goal = n - 1. Iterate in reverse from index n - 2. +

+
+ +
+
+ Hint 3 +

+ At each iteration, we check whether the current index can reach goal. If it can, we update goal to the current index, as reaching the current index means we can also reach the goal. +

+
+ +
+
+ Hint 4 +

+ To determine if we can reach the last index, the goal should be 0 after the iteration. Otherwise, reaching the last index is not possible. +

+
\ No newline at end of file diff --git a/hints/longest-common-subsequence.md b/hints/longest-common-subsequence.md new file mode 100644 index 000000000..d25df25e5 --- /dev/null +++ b/hints/longest-common-subsequence.md @@ -0,0 +1,31 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution as good or better than O(m * n) time and O(m * n) space, where m is the length of the string text1 and n is the length of the string text2. +

+
+ +
+
+ Hint 1 +

+ Try to think in terms of recursion and visualize it as a decision tree. Can you determine the possible decisions at each step? Maybe you should consider iterating through both strings recursively at the same time. +

+
+ +
+
+ Hint 2 +

+ At each recursion step, we have two choices: if the characters at the current indices of both strings match, we move both indices forward and extend the subsequence. Otherwise, we explore two paths by advancing one index at a time and recursively finding the longest subsequence. We return the maximum length between these two choices. This approach is exponential. Can you think of a way to optimize it? +

+
+ +
+
+ Hint 3 +

+ We return 0 if either index goes out of bounds. To optimize, we can use memoization to cache recursive call results and avoid redundant calculations. A hash map or a 2D array can be used to store these results. +

+
\ No newline at end of file diff --git a/hints/longest-increasing-path-in-matrix.md b/hints/longest-increasing-path-in-matrix.md new file mode 100644 index 000000000..8008fe73f --- /dev/null +++ b/hints/longest-increasing-path-in-matrix.md @@ -0,0 +1,23 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(m * n) time and O(m * n) space, where m is the number of rows and n is the number of columns in the given matrix. +

+
+ +
+
+ Hint 1 +

+ If we move from one cell to an adjacent cell with a greater value, we won't revisit a cell, as the path is strictly increasing. A brute force approach would be to run a dfs from every cell and return the longest path found. This approach is exponential. Can you think of a way to optimize it to avoid redundant calculations? +

+
+ +
+
+ Hint 2 +

+ We can use memoization to cache the results of recursive calls and avoid redundant computations. A hash map or a 2D array can be used to store these results. +

+
\ No newline at end of file diff --git a/hints/longest-increasing-subsequence.md b/hints/longest-increasing-subsequence.md new file mode 100644 index 000000000..36a4e3e78 --- /dev/null +++ b/hints/longest-increasing-subsequence.md @@ -0,0 +1,47 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution as good or better than O(n ^ 2) time and O(n ^ 2) space, where n is the size of the input array. +

+
+ +
+
+ Hint 1 +

+ A subsequence is formed by selecting elements while maintaining their order. Using recursion, we can generate all subsequences. The recursive function returns the length of the longest increasing subsequence up to index i, processing from left to right. At each step, we decide whether to include or exclude the current element. +

+
+ +
+
+ Hint 2 +

+ Since the sequence must be increasing, we represent choices by adding 1 when including an element and 0 when excluding it. In recursion, how can we ensure the current element is greater than the previous one? Perhaps additional information is needed to process it. +

+
+ +
+
+ Hint 3 +

+ We can store the index of the previously chosen element as j, making it easier to process the current element at index i. If and only if j == -1 or nums[i] > nums[j], we include the current element and extend the recursive path. Can you determine the recurrence relation? At most, two recursive calls are made at each recursion step. +

+
+ +
+
+ Hint 4 +

+ We stop the recursion when index i goes out of bounds and return 0 since no more elements can be added. The initial recursion call starts with j = -1. At each step, we include the current element if it is greater than the previous one and continue the recursion, or we exclude it and explore the next possibility. We return the maximum value obtained from both paths. +

+
+ +
+
+ Hint 5 +

+ The time complexity of this approach is exponential. We can use memoization to store results of recursive calls and avoid recalculations. A hash map or a 2D array can be used to cache these results. +

+
\ No newline at end of file diff --git a/hints/maximum-product-subarray.md b/hints/maximum-product-subarray.md new file mode 100644 index 000000000..d46997d32 --- /dev/null +++ b/hints/maximum-product-subarray.md @@ -0,0 +1,31 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(n) time and O(1) space, where n is the size of the input array. +

+
+ +
+
+ Hint 1 +

+ A brute force solution would be to find the product for every subarray and then return the maximum among all the products. This would be an O(n ^ 2) approach. Can you think of a better way? Maybe you should think of a dynamic programming approach. +

+
+ +
+
+ Hint 2 +

+ Try to identify a pattern by finding the maximum product for an array with two elements and determining what values are needed when increasing the array size to three. Perhaps you only need two values when introducing a new element. +

+
+ +
+
+ Hint 3 +

+ We maintain both the minimum and maximum product values and update them when introducing a new element by considering three cases: starting a new subarray, multiplying with the previous max product, or multiplying with the previous min product. The max product is updated to the maximum of these three, while the min product is updated to the minimum. We also track a global max product for the result. This approach is known as Kadane's algorithm. +

+
\ No newline at end of file diff --git a/hints/maximum-subarray.md b/hints/maximum-subarray.md new file mode 100644 index 000000000..f8071b628 --- /dev/null +++ b/hints/maximum-subarray.md @@ -0,0 +1,39 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(n) time and O(1) space, where n is the size of the input array. +

+
+ +
+
+ Hint 1 +

+ A brute force approach would be to compute the sum of every subarray and return the maximum among them. This would be an O(n^2) approach. Can you think of a better way? Maybe you should consider a dynamic programming-based approach. +

+
+ +
+
+ Hint 2 +

+ Instead of calculating the sum for every subarray, try maintaining a running sum. Maybe you should consider whether extending the previous sum or starting fresh with the current element gives a better result. Can you think of a way to track this efficiently? +

+
+ +
+
+ Hint 3 +

+ We use a variable curSum to track the sum of the elements. At each index, we have two choices: either add the current element to curSum or start a new subarray by resetting curSum to the current element. Maybe you should track the maximum sum at each step and update the global maximum accordingly. +

+
+ +
+
+ Hint 4 +

+ This algorithm is known as Kadane's algorithm. +

+
\ No newline at end of file diff --git a/hints/meeting-schedule-ii.md b/hints/meeting-schedule-ii.md new file mode 100644 index 000000000..1342e260f --- /dev/null +++ b/hints/meeting-schedule-ii.md @@ -0,0 +1,39 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(nlogn) time and O(n) space, where n is the size of the input array. +

+
+ +
+
+ Hint 1 +

+ Try to visualize the meetings as line segments on a number line representing start and end times. The number of rooms required is the maximum number of overlapping meetings at any point on the number line. Can you think of a way to determine this efficiently? +

+
+ +
+
+ Hint 2 +

+ We create two arrays, start and end, containing the start and end times of all meetings, respectively. After sorting both arrays, we use a two-pointer based approach. How do you implement this? +

+
+ +
+
+ Hint 3 +

+ We use two pointers, s and e, for the start and end arrays, respectively. We also maintain a variable count to track the current number of active meetings. At each iteration, we increment s while the start time is less than the current end time and increase count, as these meetings must begin before the earliest ongoing meeting ends. +

+
+ +
+
+ Hint 4 +

+ Then, we increment e and decrement count as a meeting has ended. At each step, we update the result with the maximum value of active meetings stored in count. +

+
\ No newline at end of file diff --git a/hints/meeting-schedule.md b/hints/meeting-schedule.md new file mode 100644 index 000000000..0216b7b66 --- /dev/null +++ b/hints/meeting-schedule.md @@ -0,0 +1,31 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(nlogn) time and O(n) space, where n is the size of the input array. +

+
+ +
+
+ Hint 1 +

+ If two intervals are sorted in ascending order by their start values, they overlap if the start value of the second interval is less than the end value of the first interval. And these are called overlapping intervals. +

+
+ +
+
+ Hint 2 +

+ A brute force approach would be to check every pair of intervals and return false if any overlap is found. This would be an O(n^2) solution. Can you think of a better way? Maybe you should visualize the given intervals as line segments. +

+
+ +
+
+ Hint 3 +

+ We should sort the given intervals based on their start values, as this makes it easier to check for overlaps by comparing adjacent intervals. We then iterate through the intervals from left to right and return false if any adjacent intervals overlap. +

+
\ No newline at end of file diff --git a/hints/merge-intervals.md b/hints/merge-intervals.md new file mode 100644 index 000000000..89af36fe5 --- /dev/null +++ b/hints/merge-intervals.md @@ -0,0 +1,39 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution as good or better than O(nlogn) time and O(n) space, where n is the size of the input array. +

+
+ +
+
+ Hint 1 +

+ Sorting the given intervals in ascending order based on their start values is beneficial, as it helps in identifying overlapping intervals efficiently. How can you determine if two intervals overlap? +

+
+ +
+
+ Hint 2 +

+ If two intervals are sorted in ascending order by their start values, they overlap if the start value of the second interval is less than or equal to the end value of the first interval. +

+
+ +
+
+ Hint 3 +

+ We iterate through the sorted intervals from left to right, starting with the first interval in the output list. From the second interval onward, we compare each interval with the last appended interval. Can you determine the possible cases for this comparison? +

+
+ +
+
+ Hint 4 +

+ The two cases are: if the current interval overlaps with the last appended interval, we update its end value to the maximum of both intervals' end values and continue. Otherwise, we append the current interval and proceed. +

+
\ No newline at end of file diff --git a/hints/merge-triplets-to-form-target.md b/hints/merge-triplets-to-form-target.md new file mode 100644 index 000000000..fd475aa48 --- /dev/null +++ b/hints/merge-triplets-to-form-target.md @@ -0,0 +1,31 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(n) time and O(1) space, where n is the size of the input array. +

+
+ +
+
+ Hint 1 +

+ An important observation is that we can ignore triplets with values greater than the target triplet. +

+
+ +
+
+ Hint 2 +

+ Specifically, if a triplet t has any element greater than the corresponding value in target (i.e., t[0] > target[0], t[1] > target[1], or t[2] > target[2]), we can discard it. This is because using such a triplet in operations would exceed the target values, making it invalid. +

+
+ +
+
+ Hint 3 +

+ Now, from the remaining valid triplets, we only need to check whether the target triplet values exist. Since all values in the valid triplets are less than or equal to the corresponding values in the target triplet, finding the target triplet among them guarantees that we can achieve it. +

+
\ No newline at end of file diff --git a/hints/minimum-interval-including-query.md b/hints/minimum-interval-including-query.md new file mode 100644 index 000000000..9b56faba2 --- /dev/null +++ b/hints/minimum-interval-including-query.md @@ -0,0 +1,31 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution as good or better than O(nlogn + mlogm) time and O(n + m) space, where m is the size of the array queries and n is the size of the array intervals. +

+
+ +
+
+ Hint 1 +

+ A brute force approach would be to iterate through each query and, for each query, check all intervals to find the result. This would be an O(m * n) solution. Can you think of a better way? Maybe processing the queries in sorted order could help. +

+
+ +
+
+ Hint 2 +

+ We sort the intervals by start value and process the queries in ascending order. Using a pointer i, we add intervals to a min-heap while their start values are less than or equal to the query, storing their end values and sizes. +

+
+ +
+
+ Hint 3 +

+ The min-heap is ordered by interval size. We remove elements from the heap while the top element’s end value is less than the current query. The result for the query is the top element’s size if the heap is non-empty; otherwise, it is -1. +

+
\ No newline at end of file diff --git a/hints/missing-number.md b/hints/missing-number.md new file mode 100644 index 000000000..2d5f6908b --- /dev/null +++ b/hints/missing-number.md @@ -0,0 +1,39 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(n) time and O(1) space, where n is the size of the input array. +

+
+ +
+
+ Hint 1 +

+ A brute force approach would iterate through the range of numbers from 0 to n, checking if each number is present in the given array. If a number is missing, it is returned. This results in an O(n^2) solution. Can you think of a better way? Maybe a data structure could help optimize this process. +

+
+ +
+
+ Hint 2 +

+ We can use a hash set by inserting the given array elements into it. Then, we iterate through the range of numbers from 0 to n and use the hash set for O(1) lookups to find the missing number. Can you think of a way to further optimize this? Maybe a bitwise operator could be useful. +

+
+ +
+
+ Hint 3 +

+ We can use bitwise XOR. When two identical numbers are XORed, the result is 0. Using this property, we can efficiently find the missing number. +

+
+ +
+
+ Hint 4 +

+ We first compute the bitwise XOR of numbers from 0 to n. Then, we iterate through the array and XOR its elements as well. The missing number remains in the final XOR result since all other numbers appear twice—once in the range and once in the array—while the missing number is XORed only once. +

+
\ No newline at end of file diff --git a/hints/multiply-strings.md b/hints/multiply-strings.md new file mode 100644 index 000000000..193cc4c27 --- /dev/null +++ b/hints/multiply-strings.md @@ -0,0 +1,39 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(m*n) time and O(m+n) space, where m is the length of the string num1 and n is the length of the string num2. +

+
+ +
+
+ Hint 1 +

+ Implement a helper function that takes two number strings and returns their sum. Ensure that the length of num1 is greater than num2, swapping them if necessary. Can you think of a way to multiply the strings? Maybe you should first consider basic multiplication, where num1 is multiplied by each digit of num2. +

+
+ +
+
+ Hint 2 +

+ When multiplying num1 with each digit of num2, we iterate through num2 in reverse order. Based on the digit's position, we pad zeros to the multiplication result accordingly—no padding for the last digit, one zero for the second last, and so on. What should be the next step after each multiplication? Maybe you should implement a helper function to handle this. +

+
+ +
+
+ Hint 3 +

+ We implement a helper function that takes num1, a digit, and a variable zeroes, returning the multiplication result with zeroes padded at the end. A global string res stores the final result. +

+
+ +
+
+ Hint 4 +

+ In the main function, we iterate through num2 in reverse order, calling the helper function to multiply num1 with the current digit and append the appropriate number of padding zeros. We then call another helper function that takes this multiplication result and the global result string res, adds them, and updates res. +

+
\ No newline at end of file diff --git a/hints/non-cyclical-number.md b/hints/non-cyclical-number.md new file mode 100644 index 000000000..6672425b9 --- /dev/null +++ b/hints/non-cyclical-number.md @@ -0,0 +1,23 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution as good or better than O(logn) time and O(logn) space, where n is the given integer. +

+
+ +
+
+ Hint 1 +

+ Create a helper function that returns the sum of the squares of a number's digits. Then, simulate the given process. If we reach 1, return true. However, we may get stuck in a cycle if a number is processed more than once. What data structure can be used to detect if a number has already been processed? +

+
+ +
+
+ Hint 2 +

+ We can use a hash set to detect if a number has already been processed. At each step, we update n with the return value of the helper function. If the result is 1, we return true. If n is already in the set, we return false. Otherwise, we add n to the hash set and continue. +

+
\ No newline at end of file diff --git a/hints/non-overlapping-intervals.md b/hints/non-overlapping-intervals.md new file mode 100644 index 000000000..1e07a9c0b --- /dev/null +++ b/hints/non-overlapping-intervals.md @@ -0,0 +1,39 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(nlogn) time and O(n) space, where n is the size of the input array. +

+
+ +
+
+ Hint 1 +

+ If two intervals are sorted in ascending order by their start values, they overlap if the start value of the second interval is less than the end value of the first interval. And these are called overlapping intervals. +

+
+ +
+
+ Hint 2 +

+ A brute force approach would be to sort the given intervals in ascending order based on their start values and recursively explore all possibilities. This would be an exponential approach. Can you think of a better way? Maybe a greedy approach works here. +

+
+ +
+
+ Hint 3 +

+ We first sort the given intervals based on their start values to efficiently check for overlaps by comparing adjacent intervals. We then iterate through the sorted intervals from left to right, keeping track of the previous interval’s end value as prevEnd, initially set to the end value of the first interval. +

+
+ +
+
+ Hint 4 +

+ We then iterate from the second interval. If the current interval doesn't overlap, we update prevEnd to the current interval's end and continue. Otherwise, we set prevEnd to the minimum of prevEnd and the current interval’s end, greedily removing the interval that ends last to retain as many intervals as possible. +

+
\ No newline at end of file diff --git a/hints/number-of-one-bits.md b/hints/number-of-one-bits.md new file mode 100644 index 000000000..788499e2b --- /dev/null +++ b/hints/number-of-one-bits.md @@ -0,0 +1,31 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(1) time and O(1) space. +

+
+ +
+
+ Hint 1 +

+ The given integer is a 32-bit integer. Can you think of using bitwise operators to iterate through its bits? Maybe you should consider iterating 32 times. +

+
+ +
+
+ Hint 2 +

+ We iterate 32 times (0 to 31) using index i. The expression (1 << i) creates a bitmask with a set bit at the i-th position. How can you check whether the i-th bit is set in the given number? Maybe you should consider using the bitwise-AND ("&"). +

+
+ +
+
+ Hint 3 +

+ Since the mask has a set bit at the i-th position and all 0s elsewhere, we can perform a bitwise-AND with n. If n has a set bit at the i-th position, the result is positive; otherwise, it is 0. We increment the global count if the result is positive and return it after the iteration. +

+
\ No newline at end of file diff --git a/hints/partition-equal-subset-sum.md b/hints/partition-equal-subset-sum.md new file mode 100644 index 000000000..6dfc98881 --- /dev/null +++ b/hints/partition-equal-subset-sum.md @@ -0,0 +1,39 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution as good or better than O(n * t) time and O(n * t) space, where n is the size of the input array and t is half the sum of the array elements. +

+
+ +
+
+ Hint 1 +

+ If the sum of the array elements is not even, we can immediately return false. Think in terms of recursion, where we try to build a subset with a sum equal to half of the total sum. If we find such a subset, the remaining elements will automatically form another subset with the same sum. The entire array can also be considered as one subset, with the other being empty. Can you visualize this as a decision tree to process the array recursively? +

+
+ +
+
+ Hint 2 +

+ We recursively iterate through the array with index i. At each step, we decide whether to include the current element in the subset or not. Instead of forming the subset explicitly, can you think of a better approach? Maybe you only need to track the subset sum rather than generating the subset itself. +

+
+ +
+
+ Hint 3 +

+ We can track the subset sum using a variable curSum. At each step, we make two recursive calls. If adding the current element does not exceed the target, we include it. If either path leads to a solution, we immediately return true. Can you determine the base case for this recursion? All elements in the array are positive. +

+
+ +
+
+ Hint 4 +

+ If curSum equals half the sum of the array elements, we return true. If index i goes out of bounds, we return false. This solution is exponential, but we can use memoization to cache recursive call results and avoid redundant computations. We can use a hash map or a 2D array with dimensions n * t, where n is the size of the input array and t is half the sum of the input array elements. +

+
\ No newline at end of file diff --git a/hints/partition-labels.md b/hints/partition-labels.md new file mode 100644 index 000000000..c5e3551bb --- /dev/null +++ b/hints/partition-labels.md @@ -0,0 +1,31 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(n) time and O(m) space, where n is the length of the string s and m is the number of unique characters in the string s. +

+
+ +
+
+ Hint 1 +

+ A character has a first and last index in the given string. Can you think of a greedy approach to solve this problem? Maybe you should try iterating over one of these two indices. +

+
+ +
+
+ Hint 2 +

+ We store the last index of each character in a hash map or an array. As we iterate through the string, treating each index as a potential start of a partition, we track the end of the partition using the maximum last index of the characters seen so far in the current partition. Additionally, we maintain the size of the current partition using a variable, say size. +

+
+ +
+
+ Hint 3 +

+ We update the end of the current partition based on the maximum last index of the characters, extending the partition as needed. When the current index reaches the partition’s end, we finalize the partition, append its size to the output list, reset the size to 0, and continue the same process for the remaining string. +

+
\ No newline at end of file diff --git a/hints/plus-one.md b/hints/plus-one.md new file mode 100644 index 000000000..ec62b78c9 --- /dev/null +++ b/hints/plus-one.md @@ -0,0 +1,23 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(n) time and O(n) space, where n is the size of the input array. +

+
+ +
+
+ Hint 1 +

+ There are two cases when adding 1 to a number. If the rightmost digit is less than 9, we simply increment it. Otherwise, we set it to 0 and apply the same process to the preceding digit. +

+
+ +
+
+ Hint 2 +

+ We iterate through the given digits from right to left using index i. If the current digit is less than 9, we increment it and return the array. Otherwise, we set the digit to 0 and continue. If the loop completes without returning, we insert 1 at the beginning of the array and return it. +

+
\ No newline at end of file diff --git a/hints/pow-x-n.md b/hints/pow-x-n.md new file mode 100644 index 000000000..de42350f0 --- /dev/null +++ b/hints/pow-x-n.md @@ -0,0 +1,39 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution as good or better than O(logn) time and O(logn) space, where n is the given integer. +

+
+ +
+
+ Hint 1 +

+ A brute force approach would be to iterate linearly up to n, multiplying by x each time to find (x^n). If n is negative, return (1 / (x^n)); otherwise, return (x^n). Can you think of a better way? Maybe a recursive approach would be more efficient. +

+
+ +
+
+ Hint 2 +

+ For example, to calculate 2^6, instead of multiplying 2 six times, we compute 2^3 and square the result. The same logic applies recursively to find 2^3 and further break down the multiplication. What should be the base case for this recursion? Maybe you should consider the term that cannot be further broken down. +

+
+ +
+
+ Hint 3 +

+ In (x^n), if x is 0, we return 0. If n is 0, we return 1, as any number raised to the power of 0 is 1. Otherwise, we compute (x^(n/2)) recursively and square the result. If n is odd, we multiply the final result by x. What should be the logic if n is negative? +

+
+ +
+
+ Hint 4 +

+ We start the recursion with the absolute value of n. After computing the result as res, we return res if n is non-negative; otherwise, we return (1 / res). +

+
\ No newline at end of file diff --git a/hints/regular-expression-matching.md b/hints/regular-expression-matching.md new file mode 100644 index 000000000..e17c78964 --- /dev/null +++ b/hints/regular-expression-matching.md @@ -0,0 +1,39 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution as good or better than O(m * n) time and O(m * n) space, where m is the length of the string s and n is the length of the string p. +

+
+ +
+
+ Hint 1 +

+ Try to think in terms of recursion and visualize it as a decision tree, where we explore different combinations to match the strings when encountering *. Multiple decisions are made at each step to find a valid matching path. Can you determine the possible decisions at each recursion step? +

+
+ +
+
+ Hint 2 +

+ We recursively iterate through the strings using indices i and j for s and p, respectively. If the characters match or p[j] is '.', we increment both i and j to process the remaining strings. When the next character of string p is '*', we have two choices: skip it (treating it as zero occurrences) or match one or more characters (if s[i] matches p[j]), incrementing i accordingly. +

+
+ +
+
+ Hint 3 +

+ If both indices go out of bounds, we return true; otherwise, we return false. If any recursive path returns true, we immediately return true. This approach is exponential. Can you think of a way to optimize it? +

+
+ +
+
+ Hint 4 +

+ We can use memoization to cache the results of recursive calls and avoid redundant calculations. A hash map or a 2D array can be used to store these results. +

+
\ No newline at end of file diff --git a/hints/reverse-bits.md b/hints/reverse-bits.md new file mode 100644 index 000000000..0eb364ce9 --- /dev/null +++ b/hints/reverse-bits.md @@ -0,0 +1,31 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(1) time and O(1) space. +

+
+ +
+
+ Hint 1 +

+ Given a 32-bit integer, what is the position of bit i after reversing the bits? Maybe you should observe the bit positions before and after reversal to find a pattern. +

+
+ +
+
+ Hint 2 +

+ After reversing the bits, the bit at position i moves to position 31 - i. Can you use this observation to construct the reversed number efficiently? +

+
+ +
+
+ Hint 3 +

+ We initialize res to 0 and iterate through the bits of the given integer n. We extract the bit at the i-th position using ((n >> i) & 1). If it is 1, we set the corresponding bit in res at position (31 - i) using (res |= (1 << (31 - i))). +

+
\ No newline at end of file diff --git a/hints/reverse-integer.md b/hints/reverse-integer.md new file mode 100644 index 000000000..23b4d9c75 --- /dev/null +++ b/hints/reverse-integer.md @@ -0,0 +1,31 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(1) time and O(1) space. +

+
+ +
+
+ Hint 1 +

+ A straightforward approach would be to convert the given integer to a string, reverse it, convert it back to an integer using a long type, and return 0 if the result exceeds the integer range. Can you think of a better way? +

+
+ +
+
+ Hint 2 +

+ We initially declare the result res as an int with a value of 0. We iterate through the given integer, extracting digits one by one. Before appending a digit to res, we consider multiple cases. Can you determine them? Maybe you should think about overflow. +

+
+ +
+
+ Hint 3 +

+ Let MAX be the maximum positive integer and MIN be the minimum negative integer. We iterate through each digit and check for overflow before updating res. If res > MAX / 10 or res < MIN / 10, return 0. If res == MAX / 10 and the current digit is greater than MAX % 10, return 0. If res == MIN / 10 and the current digit is less than MIN % 10, return 0. Otherwise, append the digit to res and continue. +

+
\ No newline at end of file diff --git a/hints/rotate-matrix.md b/hints/rotate-matrix.md new file mode 100644 index 000000000..3f5528d0f --- /dev/null +++ b/hints/rotate-matrix.md @@ -0,0 +1,31 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(n^2) time and O(1) space, where n is the length of the side of the given square matrix. +

+
+ +
+
+ Hint 1 +

+ A brute force approach would use O(n^2) extra space to solve the problem. Can you think of a way to avoid using extra space? Maybe you should consider observing the positions of the elements before rotating and after rotating of the matrix. +

+
+ +
+
+ Hint 2 +

+ We can rotate the matrix in two steps. First, we reverse the matrix vertically, meaning the first row becomes the last, the second row becomes the second last, and so on. Next, we transpose the reversed matrix, meaning rows become columns and columns become rows. How would you transpose the matrix? +

+
+ +
+
+ Hint 3 +

+ Since the given matrix is a square matrix, we only need to iterate over the upper triangular part, meaning the right upper portion of the main diagonal. In this way, we can transpose a matrix. +

+
\ No newline at end of file diff --git a/hints/set-zeroes-in-matrix.md b/hints/set-zeroes-in-matrix.md new file mode 100644 index 000000000..663ff919e --- /dev/null +++ b/hints/set-zeroes-in-matrix.md @@ -0,0 +1,39 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(m*n) time and O(1) space, where m is the number of rows and n is the number of columns in the given matrix. +

+
+ +
+
+ Hint 1 +

+ A brute force approach would iterate through the given matrix and update the corresponding row and column in a new matrix on the fly. This would result in an O((m*n)*(m+n)) time and O(m*n) space solution. Can you think of a better way? Maybe you should consider using a single variable for a row and a single variable for a column instead of updating entire row and column. +

+
+ +
+
+ Hint 2 +

+ A better approach is to use O(m+n) boolean arrays. We iterate through the matrix, and when encountering a zero, we mark the respective row and column as true. In the second iteration, we set a cell to 0 if its corresponding row or column is marked true. Can you think of a way to optimize the space further? +

+
+ +
+
+ Hint 3 +

+ We can use the topmost row and leftmost column of the matrix as boolean arrays by marking 0 instead of true. However, since they overlap at one cell, we use a single variable to track the top row separately. We then iterate through the matrix and mark zeros accordingly. +

+
+ +
+
+ Hint 4 +

+ In the second iteration, we update all cells that are not part of the top row or left column accordingly. After making the necessary changes, we check the top-leftmost cell and update the corresponding column. Finally, we check the extra variable and update the top row accordingly. +

+
\ No newline at end of file diff --git a/hints/single-number.md b/hints/single-number.md new file mode 100644 index 000000000..6aab0485f --- /dev/null +++ b/hints/single-number.md @@ -0,0 +1,39 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(n) time and O(1) space, where n is the size of the input array. +

+
+ +
+
+ Hint 1 +

+ A brute force approach would iterate through the array, checking each element using a nested loop. If a duplicate is found, we continue to the next element; otherwise, the current element is the required number. This results in an O(n^2) solution. Can you think of a better way? Maybe a data structure can help detect duplicates efficiently. +

+
+ +
+
+ Hint 2 +

+ We use a hash set, iterating through the array and adding elements that are not in the set while removing those that are already present. After the iteration, the required number remains in the hash set. This results in an O(n) space solution. Can you further optimize it? Maybe a bitwise operator could be useful here. +

+
+ +
+
+ Hint 3 +

+ Think about the bitwise XOR ("^"). What is the result when two identical numbers are XORed? +

+
+ +
+
+ Hint 4 +

+ When two identical numbers are XORed, they cancel out, resulting in zero. Since every number appears twice except for one, the XOR of the entire array gives the number that appears only once. +

+
\ No newline at end of file diff --git a/hints/spiral-matrix.md b/hints/spiral-matrix.md new file mode 100644 index 000000000..2b8eced0a --- /dev/null +++ b/hints/spiral-matrix.md @@ -0,0 +1,31 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(m*n) time and O(1) extra space, where m is the number of rows and n is the number of columns in the given matrix. +

+
+ +
+
+ Hint 1 +

+ Try to simulate the process as described in the problem. Think in terms of matrix layers, starting from the outermost boundaries and moving inward. Can you determine an efficient way to implement this? +

+
+ +
+
+ Hint 2 +

+ Each boundary consists of four parts: the top row, right column, bottom row, and left column, which follow the spiral order and act as four pointers. For each layer, the top pointer increments by one, the right pointer decrements by one, the left pointer increments by one, and the bottom pointer decrements by one. +

+
+ +
+
+ Hint 3 +

+ At each layer, four loops traverse the matrix: one moves left to right along the top row, another moves top to bottom along the right column, the next moves right to left along the bottom row, and the last moves bottom to top along the left column. This process generates the spiral order. +

+
\ No newline at end of file diff --git a/hints/string-encode-and-decode.md b/hints/string-encode-and-decode.md index 39083d5be..82bc8fbcb 100644 --- a/hints/string-encode-and-decode.md +++ b/hints/string-encode-and-decode.md @@ -2,7 +2,7 @@
Recommended Time & Space Complexity

- You should aim for a solution with O(m) time and O(1) space for each encode() and decode() call, where m is the sum of lengths of all the strings. + You should aim for a solution with O(m) time for each encode() and decode() call and O(m+n) space, where m is the sum of lengths of all the strings and n is the number of strings.

diff --git a/hints/sum-of-two-integers.md b/hints/sum-of-two-integers.md new file mode 100644 index 000000000..340f197d0 --- /dev/null +++ b/hints/sum-of-two-integers.md @@ -0,0 +1,39 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(1) time and O(1) space. +

+
+ +
+
+ Hint 1 +

+ A brute force approach would use the addition operator. Can you think of a way to perform addition without using it? Maybe you should consider solving this using bit manipulation. +

+
+ +
+
+ Hint 2 +

+ We can use the bitwise XOR operator to perform addition. If both a and b have 1 at the same bit position, the sum at that position is 0, and a carry of 1 is generated. If the bits are different, the sum at that position is 1. Additionally, we account for the carry from the previous step in the next iteration. +

+
+ +
+
+ Hint 3 +

+ We iterate bit by bit from 0 to 31 since the given integers are 32-bit. We track the carry, initially set to 0, and initialize the result as res. During iteration, the XOR of the bits at the i-th position of both integers and the carry determines the current bit of res. How can you handle negative numbers? +

+
+ +
+
+ Hint 4 +

+ To handle negative numbers, if the final result exceeds the maximum positive 32-bit integer, it means the number should be negative. We adjust it using bitwise operations: flipping the bits with res ^ ((2 ^ 32) - 1) and applying ~ to restore the correct two’s complement representation. This ensures the result correctly represents signed 32-bit integers. +

+
\ No newline at end of file diff --git a/hints/target-sum.md b/hints/target-sum.md new file mode 100644 index 000000000..06e9e9a3e --- /dev/null +++ b/hints/target-sum.md @@ -0,0 +1,31 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution as good or better than O(n * m) time and O(n * m) space, where n is the size of the input array and m is the sum of all the elements in the array. +

+
+ +
+
+ Hint 1 +

+ Try to think in terms of recursion and visualize it as a decision tree, where we have two choices at each recursion step: assigning a positive or negative sign. +

+
+ +
+
+ Hint 2 +

+ We recursively iterate through the array using index i, tracking the current sum along the recursive path. Each step branches into two paths, and we sum the number of ways to reach the target. If the index i goes out of bounds, we return 1 if the current sum equals the target; otherwise, we return 0. +

+
+ +
+
+ Hint 3 +

+ This approach is exponential. We can use memoization to cache recursive call results and avoid redundant calculations. A hash map or a 2D array with modifications can be used for caching. If using a 2D array, the dimensions can be (n * (2m + 1)), where n is the array size and m represents the sum of the array elements. +

+
\ No newline at end of file diff --git a/hints/valid-parenthesis-string.md b/hints/valid-parenthesis-string.md new file mode 100644 index 000000000..29baed7d5 --- /dev/null +++ b/hints/valid-parenthesis-string.md @@ -0,0 +1,39 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution as good or better than O(n) time and O(n) space, where n is the length of the input string. +

+
+ +
+
+ Hint 1 +

+ A brute force approach would try all possibilities when encountering a '*' and recursively solve the problem, leading to an exponential approach. Can you think of a better way? Maybe a data structure commonly used in parenthesis problems could be useful. +

+
+ +
+
+ Hint 2 +

+ We can solve the problem using a stack-based approach. We maintain two stacks: one for tracking the indices of left parentheses and another for star indices. As we iterate through the string from left to right, we push indices onto their respective stacks when encountering a left parenthesis '(' or a star '*'. Can you determine the logic for the right parentesis case? +

+
+ +
+
+ Hint 3 +

+ If the left parenthesis stack is not empty, we pop from it. Otherwise, we pop from the star stack, treating the star as a left parenthesis to keep the string valid. After iterating the string, the stacks might be non-empty? Can you determine the logic for this case? +

+
+ +
+
+ Hint 4 +

+ Now, we try to match the remaining left parentheses with stars, ensuring the stars appear after the left parentheses in the string. We simultaneously pop from both stacks, and if the index of a left parenthesis is greater than that of a star, the string is invalid as there is no matching right parenthesis. In this case, we return false. +

+
\ No newline at end of file diff --git a/hints/word-break.md b/hints/word-break.md new file mode 100644 index 000000000..cb850a49c --- /dev/null +++ b/hints/word-break.md @@ -0,0 +1,31 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution as good or better than O(n * m * t) time and O(n) space, where n is the length of the string s, m is the number of words in wordDict, and t is the maximum length of any word in wordDict. +

+
+ +
+
+ Hint 1 +

+ Try to think of this problem in terms of recursion, where we explore all possibilities. We iterate through the given string s, attempting to pick a word from wordDict that matches a portion of s, and then recursively continue processing the remaining string. Can you determine the recurrence relation and base condition? +

+
+ +
+
+ Hint 2 +

+ The base condition is to return true if we reach the end of the string s. At each recursive call with index i iterating through s, we check all words in wordDict and recursively process the remaining string by incrementing i by the length of the matched word. If any recursive path returns true, we immediately return true. However, this solution is exponential. Can you think of an optimization? Maybe you should consider an approach that avoids repeated work. +

+
+ +
+
+ Hint 3 +

+ We can avoid recalculating results for recursive calls by using memoization. Since we iterate with index i, we can use a hash map or an array of the same length as s to cache the results of recursive calls and prevent redundant computations. +

+
\ No newline at end of file From 0a2d881f8e72fa645203cddf31c3ea7f43a35812 Mon Sep 17 00:00:00 2001 From: Sri Hari <94112314+Srihari2222@users.noreply.github.com> Date: Mon, 24 Mar 2025 02:44:23 +0530 Subject: [PATCH 05/12] Sri Hari: Batch-6/Neetcode-150/Added-SwiftCode (#3936) * Batch-6/Neetcode-150/Added-swiftcode * Batch-6/Neetcode-150/Added-swiftcode * Batch-6/Neetcode-150/Added-swiftcode * Batch-6/Neetcode-150/Added-swiftcode * Batch-6/Neetcode-150/Added-swiftcode * Batch-6/Neetcode-150/Added-swiftcode * Batch-6/Neetcode-150/Added-swiftcode * Batch-6/Neetcode-150/Added-swiftcode * Batch-6/Neetcode-150/Added-swiftcode * Batch-6/Neetcode-150/Added-swiftcode * Batch-6/Neetcode-150/Added-swiftcode * Batch-6/Neetcode-150/Added-swiftcode * Batch-6/Neetcode-150/Added-swiftcode --- articles/add-two-numbers.md | 74 +- articles/anagram-groups.md | 39 +- articles/balanced-binary-tree.md | 124 +++- articles/binary-search.md | 90 +++ articles/binary-tree-diameter.md | 112 +++ ...ree-from-preorder-and-inorder-traversal.md | 130 ++++ articles/binary-tree-maximum-path-sum.md | 79 +++ articles/binary-tree-right-side-view.md | 78 +++ articles/burst-balloons.md | 75 ++ articles/buy-and-sell-crypto-with-cooldown.md | 100 +++ articles/buy-and-sell-crypto.md | 51 ++ articles/car-fleet.md | 44 ++ articles/cheapest-flight-path.md | 107 +++ articles/climbing-stairs.md | 120 ++++ articles/clone-graph.md | 84 +++ articles/coin-change-ii.md | 157 ++++- articles/coin-change.md | 111 +++ articles/combination-target-sum-ii.md | 136 ++++ articles/combination-target-sum.md | 56 ++ articles/combinations-of-a-phone-number.md | 67 +- .../copy-linked-list-with-random-pointer.md | 231 ++++++- articles/count-connected-components.md | 124 +++- articles/count-good-nodes-in-binary-tree.md | 78 +++ articles/count-number-of-islands.md | 149 +++- articles/count-paths.md | 117 ++++ articles/count-squares.md | 73 +- articles/count-subsequences.md | 161 ++++- articles/counting-bits.md | 75 ++ articles/course-schedule-ii.md | 121 ++++ articles/course-schedule.md | 82 +++ articles/daily-temperatures.md | 75 +- articles/decode-ways.md | 105 +++ articles/depth-of-binary-tree.md | 100 +++ articles/design-twitter-feed.md | 229 ++++++ articles/design-word-search-data-structure.md | 94 +++ articles/duplicate-integer.md | 54 +- articles/eating-bananas.md | 47 ++ articles/edit-distance.md | 141 ++++ articles/evaluate-reverse-polish-notation.md | 147 ++++ articles/find-duplicate-integer.md | 137 ++++ articles/find-median-in-a-data-stream.md | 65 ++ .../find-minimum-in-rotated-sorted-array.md | 51 ++ .../find-target-in-rotated-sorted-array.md | 124 ++++ articles/foreign-dictionary.md | 122 ++++ articles/gas-station.md | 93 +++ articles/generate-parentheses.md | 85 +++ articles/hand-of-straights.md | 147 ++++ articles/house-robber-ii.md | 110 +++ articles/house-robber.md | 75 ++ articles/implement-prefix-tree.md | 109 +++ articles/insert-new-interval.md | 91 +++ articles/interleaving-string.md | 157 +++++ articles/invert-a-binary-tree.md | 212 +++++- articles/is-anagram.md | 63 +- articles/is-palindrome.md | 44 ++ articles/islands-and-treasure.md | 132 ++++ articles/jump-game-ii.md | 103 ++- articles/jump-game.md | 93 +++ articles/k-closest-points-to-origin.md | 121 +++- articles/kth-largest-element-in-an-array.md | 122 ++++ articles/kth-largest-integer-in-a-stream.md | 48 +- articles/kth-smallest-integer-in-bst.md | 197 ++++++ articles/largest-rectangle-in-histogram.md | 198 +++++- articles/last-stone-weight.md | 108 +++ .../level-order-traversal-of-binary-tree.md | 84 ++- articles/linked-list-cycle-detection.md | 61 ++ articles/longest-common-subsequence.md | 134 ++++ articles/longest-consecutive-sequence.md | 103 ++- articles/longest-increasing-path-in-matrix.md | 114 +++ articles/longest-increasing-subsequence.md | 651 +++++++++++++++++- articles/longest-palindromic-substring.md | 138 +++- ...st-repeating-substring-with-replacement.md | 78 +++ .../longest-substring-without-duplicates.md | 60 ++ ...t-common-ancestor-in-binary-search-tree.md | 67 ++ articles/lru-cache.md | 149 ++++ articles/max-area-of-island.md | 148 +++- articles/max-water-container.md | 34 + articles/maximum-product-subarray.md | 106 +++ articles/maximum-subarray.md | 150 ++++ articles/median-of-two-sorted-arrays.md | 123 +++- articles/meeting-schedule-ii.md | 134 ++++ articles/meeting-schedule.md | 56 ++ articles/merge-intervals.md | 92 +++ articles/merge-k-sorted-linked-lists.md | 336 +++++++++ articles/merge-triplets-to-form-target.md | 43 ++ articles/merge-two-sorted-linked-lists.md | 66 ++ articles/min-cost-climbing-stairs.md | 63 ++ articles/min-cost-to-connect-points.md | 156 ++++- articles/minimum-interval-including-query.md | 252 ++++++- articles/minimum-stack.md | 142 +++- articles/minimum-window-with-characters.md | 89 +++ articles/missing-number.md | 59 ++ articles/multiply-strings.md | 97 +++ articles/n-queens.md | 175 +++++ articles/network-delay-time.md | 174 +++++ articles/non-cyclical-number.md | 92 +++ articles/non-overlapping-intervals.md | 155 +++++ articles/number-of-one-bits.md | 50 ++ articles/pacific-atlantic-water-flow.md | 149 ++++ articles/palindrome-partitioning.md | 177 ++++- articles/palindromic-substrings.md | 139 ++++ articles/partition-equal-subset-sum.md | 171 ++++- articles/partition-labels.md | 25 + articles/permutation-string.md | 109 ++- articles/permutations.md | 124 ++++ articles/plus-one.md | 66 ++ articles/pow-x-n.md | 69 +- articles/products-of-array-discluding-self.md | 117 +++- articles/reconstruct-flight-path.md | 89 +++ articles/redundant-connection.md | 185 +++++ articles/regular-expression-matching.md | 158 +++++ .../remove-node-from-end-of-linked-list.md | 138 +++- articles/reorder-linked-list.md | 152 +++- articles/reverse-a-linked-list.md | 56 ++ articles/reverse-bits.md | 52 ++ articles/reverse-integer.md | 68 ++ articles/reverse-nodes-in-k-group.md | 92 +++ articles/rotate-matrix.md | 69 ++ articles/rotting-fruit.md | 106 +++ articles/same-binary-tree.md | 114 +++ articles/search-2d-matrix.md | 99 +++ articles/search-for-word-ii.md | 192 +++++- articles/search-for-word.md | 115 ++++ .../serialize-and-deserialize-binary-tree.md | 125 ++++ articles/set-zeroes-in-matrix.md | 100 +++ articles/single-number.md | 69 ++ articles/sliding-window-maximum.md | 179 ++++- articles/spiral-matrix.md | 90 +++ articles/string-encode-and-decode.md | 85 +++ articles/subsets-ii.md | 131 +++- articles/subsets.md | 71 +- articles/subtree-of-a-binary-tree.md | 121 +++- articles/sum-of-two-integers.md | 53 ++ articles/surrounded-regions.md | 176 ++++- articles/swim-in-rising-water.md | 239 ++++++- articles/target-sum.md | 73 ++ articles/task-scheduling.md | 120 ++++ articles/three-integer-sum.md | 100 ++- articles/time-based-key-value-store.md | 110 +++ articles/top-k-elements-in-list.md | 90 ++- articles/trapping-rain-water.md | 111 +++ articles/two-integer-sum-ii.md | 77 +++ articles/two-integer-sum.md | 82 +++ articles/valid-binary-search-tree.md | 111 +++ articles/valid-parenthesis-string.md | 215 ++++++ articles/valid-sudoku.md | 98 +++ articles/valid-tree.md | 138 +++- articles/validate-parentheses.md | 37 + articles/word-break.md | 209 +++++- articles/word-ladder.md | 231 +++++++ 150 files changed, 17199 insertions(+), 148 deletions(-) diff --git a/articles/add-two-numbers.md b/articles/add-two-numbers.md index 6225ac227..118adab49 100644 --- a/articles/add-two-numbers.md +++ b/articles/add-two-numbers.md @@ -303,6 +303,40 @@ class Solution { } ``` +```swift +/** + * Definition for singly-linked list. + * public class ListNode { + * public var val: Int + * public var next: ListNode? + * public init() { self.val = 0; self.next = nil; } + * public init(_ val: Int) { self.val = val; self.next = nil; } + * public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; } + * } + */ +class Solution { + private func add(_ l1: ListNode?, _ l2: ListNode?, _ carry: Int) -> ListNode? { + if l1 == nil && l2 == nil && carry == 0 { + return nil + } + + let v1 = l1?.val ?? 0 + let v2 = l2?.val ?? 0 + + let sum = v1 + v2 + carry + let newCarry = sum / 10 + let val = sum % 10 + + let nextNode = add(l1?.next, l2?.next, newCarry) + return ListNode(val, nextNode) + } + + func addTwoNumbers(_ l1: ListNode?, _ l2: ListNode?) -> ListNode? { + return add(l1, l2, 0) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -577,11 +611,49 @@ class Solution { } ``` +```swift +/** + * Definition for singly-linked list. + * public class ListNode { + * public var val: Int + * public var next: ListNode? + * public init() { self.val = 0; self.next = nil; } + * public init(_ val: Int) { self.val = val; self.next = nil; } + * public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; } + * } + */ +class Solution { + func addTwoNumbers(_ l1: ListNode?, _ l2: ListNode?) -> ListNode? { + let dummy = ListNode(0) + var cur = dummy + var l1 = l1, l2 = l2 + var carry = 0 + + while l1 != nil || l2 != nil || carry != 0 { + let v1 = l1?.val ?? 0 + let v2 = l2?.val ?? 0 + + let sum = v1 + v2 + carry + carry = sum / 10 + let val = sum % 10 + cur.next = ListNode(val) + + cur = cur.next! + l1 = l1?.next + l2 = l2?.next + } + return dummy.next + } +} +``` + ::tabs-end ### Time & Space Complexity * Time complexity: $O(m + n)$ -* Space complexity: $O(1)$ +* Space complexity: + * $O(1)$ extra space. + * $O(max(m, n))$ for the output list. > Where $m$ is the length of $l1$ and $n$ is the length of $l2$. \ No newline at end of file diff --git a/articles/anagram-groups.md b/articles/anagram-groups.md index a0aae3216..bf41aaa79 100644 --- a/articles/anagram-groups.md +++ b/articles/anagram-groups.md @@ -125,6 +125,21 @@ class Solution { } ``` +```swift +class Solution { + func groupAnagrams(_ strs: [String]) -> [[String]] { + var res = [String: [String]]() + + for s in strs { + let sortedS = String(s.sorted()) + res[sortedS, default: []].append(s) + } + + return Array(res.values) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -277,11 +292,31 @@ class Solution { } ``` +```swift +class Solution { + func groupAnagrams(_ strs: [String]) -> [[String]] { + var res = [Array: [String]]() + + for s in strs { + var count = [Int](repeating: 0, count: 26) + for c in s { + count[Int(c.asciiValue!) - 97] += 1 + } + res[count, default: []].append(s) + } + + return Array(res.values) + } +} +``` + ::tabs-end ### Time & Space Complexity * Time complexity: $O(m * n)$ -* Space complexity: $O(m)$ +* Space complexity: + * $O(m)$ extra space. + * $O(m * n)$ space for the output list. -> Where $m$ is the number of strings and $n$ is the length of the longest string. +> Where $m$ is the number of strings and $n$ is the length of the longest string. \ No newline at end of file diff --git a/articles/balanced-binary-tree.md b/articles/balanced-binary-tree.md index c9c407ed0..21715bc6f 100644 --- a/articles/balanced-binary-tree.md +++ b/articles/balanced-binary-tree.md @@ -254,6 +254,43 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func isBalanced(_ root: TreeNode?) -> Bool { + guard let root = root else { return true } + + let left = height(root.left) + let right = height(root.right) + + if abs(left - right) > 1 { + return false + } + + return isBalanced(root.left) && isBalanced(root.right) + } + + private func height(_ root: TreeNode?) -> Int { + guard let root = root else { return 0 } + return 1 + max(height(root.left), height(root.right)) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -521,6 +558,39 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func isBalanced(_ root: TreeNode?) -> Bool { + return dfs(root).0 + } + + private func dfs(_ root: TreeNode?) -> (Bool, Int) { + guard let root = root else { return (true, 0) } + + let left = dfs(root.left) + let right = dfs(root.right) + + let balanced = left.0 && right.0 && abs(left.1 - right.1) <= 1 + return (balanced, 1 + max(left.1, right.1)) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -534,7 +604,7 @@ class Solution { --- -## 3. Depth First Search (Stack) +## 3. Iterative DFS ::tabs-start @@ -866,6 +936,58 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func isBalanced(_ root: TreeNode?) -> Bool { + var stack = [TreeNode]() + var node = root + var last: TreeNode? = nil + var depths = [ObjectIdentifier: Int]() + + while !stack.isEmpty || node != nil { + if let current = node { + stack.append(current) + node = current.left + } else { + guard let current = stack.last else { break } + if current.right == nil || last === current.right { + stack.removeLast() + + let leftDepth = current.left != nil ? depths[ObjectIdentifier(current.left!)] ?? 0 : 0 + let rightDepth = current.right != nil ? depths[ObjectIdentifier(current.right!)] ?? 0 : 0 + if abs(leftDepth - rightDepth) > 1 { + return false + } + + depths[ObjectIdentifier(current)] = 1 + max(leftDepth, rightDepth) + last = current + node = nil + } else { + node = current.right + } + } + } + + return true + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/binary-search.md b/articles/binary-search.md index 5e88782ce..59a970a26 100644 --- a/articles/binary-search.md +++ b/articles/binary-search.md @@ -139,6 +139,29 @@ class Solution { } ``` +```swift +class Solution { + func binarySearch(_ l: Int, _ r: Int, _ nums: [Int], _ target: Int) -> Int { + if l > r { + return -1 + } + let m = l + (r - l) / 2 + + if nums[m] == target { + return m + } + if nums[m] < target { + return binarySearch(m + 1, r, nums, target) + } + return binarySearch(l, m - 1, nums, target) + } + + func search(_ nums: [Int], _ target: Int) -> Int { + return binarySearch(0, nums.count - 1, nums, target) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -296,6 +319,28 @@ class Solution { } ``` +```swift +class Solution { + func search(_ nums: [Int], _ target: Int) -> Int { + var l = 0, r = nums.count - 1 + + while l <= r { + // (l + r) // 2 can lead to overflow + let m = l + (r - l) / 2 + + if nums[m] > target { + r = m - 1 + } else if nums[m] < target { + l = m + 1 + } else { + return m + } + } + return -1 + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -439,6 +484,24 @@ class Solution { } ``` +```swift +class Solution { + func search(_ nums: [Int], _ target: Int) -> Int { + var l = 0, r = nums.count + + while l < r { + let m = l + (r - l) / 2 + if nums[m] > target { + r = m + } else { + l = m + 1 + } + } + return (l > 0 && nums[l - 1] == target) ? l - 1 : -1 + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -582,6 +645,24 @@ class Solution { } ``` +```swift +class Solution { + func search(_ nums: [Int], _ target: Int) -> Int { + var l = 0, r = nums.count + + while l < r { + let m = l + (r - l) / 2 + if nums[m] >= target { + r = m + } else { + l = m + 1 + } + } + return (l < nums.count && nums[l] == target) ? l : -1 + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -664,6 +745,15 @@ class Solution { } ``` +```swift +class Solution { + func search(_ nums: [Int], _ target: Int) -> Int { + let index = nums.partitioningIndex { $0 >= target } + return (index < nums.count && nums[index] == target) ? index : -1 + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/binary-tree-diameter.md b/articles/binary-tree-diameter.md index 3c73fbe92..b11c3e40e 100644 --- a/articles/binary-tree-diameter.md +++ b/articles/binary-tree-diameter.md @@ -259,6 +259,41 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func diameterOfBinaryTree(_ root: TreeNode?) -> Int { + guard let root = root else { return 0 } + + let leftHeight = maxHeight(root.left) + let rightHeight = maxHeight(root.right) + let diameter = leftHeight + rightHeight + let sub = max(diameterOfBinaryTree(root.left), diameterOfBinaryTree(root.right)) + + return max(diameter, sub) + } + + private func maxHeight(_ root: TreeNode?) -> Int { + guard let root = root else { return 0 } + return 1 + max(maxHeight(root.left), maxHeight(root.right)) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -515,6 +550,40 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func diameterOfBinaryTree(_ root: TreeNode?) -> Int { + var res = 0 + + func dfs(_ root: TreeNode?) -> Int { + guard let root = root else { return 0 } + let left = dfs(root.left) + let right = dfs(root.right) + res = max(res, left + right) + return 1 + max(left, right) + } + + dfs(root) + return res + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -876,6 +945,49 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func diameterOfBinaryTree(_ root: TreeNode?) -> Int { + guard let root = root else { return 0 } + var stack: [TreeNode] = [root] + var mp = [ObjectIdentifier: (Int, Int)]() + + while !stack.isEmpty { + let node = stack.last! + if let left = node.left, mp[ObjectIdentifier(left)] == nil { + stack.append(left) + } else if let right = node.right, mp[ObjectIdentifier(right)] == nil { + stack.append(right) + } else { + let node = stack.removeLast() + let leftTuple = node.left != nil ? mp[ObjectIdentifier(node.left!)]! : (0, 0) + let rightTuple = node.right != nil ? mp[ObjectIdentifier(node.right!)]! : (0, 0) + let height = 1 + max(leftTuple.0, rightTuple.0) + let diameter = max(leftTuple.0 + rightTuple.0, leftTuple.1, rightTuple.1) + mp[ObjectIdentifier(node)] = (height, diameter) + } + } + + return mp[ObjectIdentifier(root)]!.1 + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/binary-tree-from-preorder-and-inorder-traversal.md b/articles/binary-tree-from-preorder-and-inorder-traversal.md index 621fc91cd..b21106a35 100644 --- a/articles/binary-tree-from-preorder-and-inorder-traversal.md +++ b/articles/binary-tree-from-preorder-and-inorder-traversal.md @@ -235,6 +235,49 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func buildTree(_ preorder: [Int], _ inorder: [Int]) -> TreeNode? { + if preorder.isEmpty || inorder.isEmpty { + return nil + } + + let rootValue = preorder[0] + let root = TreeNode(rootValue) + guard let mid = inorder.firstIndex(of: rootValue) else { + return root + } + + root.left = buildTree( + Array(preorder[1..<(mid + 1)]), + Array(inorder[0.. TreeNode? { + for (index, value) in inorder.enumerated() { + indexMap[value] = index + } + return dfs(preorder, 0, inorder.count - 1) + } + + private func dfs(_ preorder: [Int], _ left: Int, _ right: Int) -> TreeNode? { + if left > right { + return nil + } + + let rootVal = preorder[preIndex] + preIndex += 1 + let root = TreeNode(rootVal) + let mid = indexMap[rootVal]! + + root.left = dfs(preorder, left, mid - 1) + root.right = dfs(preorder, mid + 1, right) + + return root + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -775,6 +863,48 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + var preIdx = 0 + var inIdx = 0 + + func buildTree(_ preorder: [Int], _ inorder: [Int]) -> TreeNode? { + return dfs(preorder, inorder, Int.max) + } + + private func dfs(_ preorder: [Int], _ inorder: [Int], _ limit: Int) -> TreeNode? { + if preIdx >= preorder.count { + return nil + } + if inorder[inIdx] == limit { + inIdx += 1 + return nil + } + + let root = TreeNode(preorder[preIdx]) + preIdx += 1 + root.left = dfs(preorder, inorder, root.val) + root.right = dfs(preorder, inorder, limit) + return root + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/binary-tree-maximum-path-sum.md b/articles/binary-tree-maximum-path-sum.md index af442201a..ebd5467bc 100644 --- a/articles/binary-tree-maximum-path-sum.md +++ b/articles/binary-tree-maximum-path-sum.md @@ -290,6 +290,49 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + var res = Int.min + + func maxPathSum(_ root: TreeNode?) -> Int { + dfs(root) + return res + } + + private func dfs(_ root: TreeNode?) { + guard let node = root else { return } + let left = getMax(node.left) + let right = getMax(node.right) + res = max(res, node.val + left + right) + dfs(node.left) + dfs(node.right) + } + + private func getMax(_ root: TreeNode?) -> Int { + guard let node = root else { return 0 } + let left = getMax(node.left) + let right = getMax(node.right) + let path = node.val + max(left, right) + return max(0, path) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -560,6 +603,42 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func maxPathSum(_ root: TreeNode?) -> Int { + var res = root!.val + + func dfs(_ root: TreeNode?) -> Int { + guard let node = root else { return 0 } + + let leftMax = max(dfs(node.left), 0) + let rightMax = max(dfs(node.right), 0) + + res = max(res, node.val + leftMax + rightMax) + return node.val + max(leftMax, rightMax) + } + + dfs(root) + return res + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/binary-tree-right-side-view.md b/articles/binary-tree-right-side-view.md index e17b22299..4d8a68b19 100644 --- a/articles/binary-tree-right-side-view.md +++ b/articles/binary-tree-right-side-view.md @@ -236,6 +236,42 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func rightSideView(_ root: TreeNode?) -> [Int] { + var res = [Int]() + + func dfs(_ node: TreeNode?, _ depth: Int) { + guard let node = node else { return } + if depth == res.count { + res.append(node.val) + } + + dfs(node.right, depth + 1) + dfs(node.left, depth + 1) + } + + dfs(root, 0) + return res + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -530,6 +566,48 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func rightSideView(_ root: TreeNode?) -> [Int] { + var res = [Int]() + var q = Deque() + q.append(root) + + while !q.isEmpty { + var rightSide: TreeNode? + let qLen = q.count + + for _ in 0.. Int { + var nums = [1] + nums + [1] + + func dfs(_ nums: [Int]) -> Int { + if nums.count == 2 { + return 0 + } + + var maxCoins = 0 + for i in 1..<(nums.count - 1) { + let coins = nums[i - 1] * nums[i] * nums[i + 1] + + dfs(Array(nums[.. Int { + var nums = [1] + nums + [1] + let n = nums.count + var dp = Array(repeating: Array(repeating: -1, count: n), count: n) + + func dfs(_ l: Int, _ r: Int) -> Int { + if l > r { + return 0 + } + if dp[l][r] != -1 { + return dp[l][r] + } + + dp[l][r] = 0 + for i in l...r { + let coins = nums[l - 1] * nums[i] * nums[r + 1] + dfs(l, i - 1) + dfs(i + 1, r) + dp[l][r] = max(dp[l][r], coins) + } + return dp[l][r] + } + + return dfs(1, n - 2) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -621,6 +673,29 @@ class Solution { } ``` +```swift +class Solution { + func maxCoins(_ nums: [Int]) -> Int { + let n = nums.count + var newNums = [1] + nums + [1] + + var dp = Array(repeating: Array(repeating: 0, count: n + 2), count: n + 2) + + for l in stride(from: n, through: 1, by: -1) { + for r in l...n { + for i in l...r { + let coins = (newNums[l - 1] * newNums[i] * newNums[r + 1]) + + dp[l][i - 1] + dp[i + 1][r] + dp[l][r] = max(dp[l][r], coins) + } + } + } + + return dp[1][n] + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/buy-and-sell-crypto-with-cooldown.md b/articles/buy-and-sell-crypto-with-cooldown.md index 366028454..9c4ae550b 100644 --- a/articles/buy-and-sell-crypto-with-cooldown.md +++ b/articles/buy-and-sell-crypto-with-cooldown.md @@ -171,6 +171,31 @@ class Solution { } ``` +```swift +class Solution { + func maxProfit(_ prices: [Int]) -> Int { + let n = prices.count + + func dfs(_ i: Int, _ buying: Bool) -> Int { + if i >= n { + return 0 + } + + let cooldown = dfs(i + 1, buying) + if buying { + let buy = dfs(i + 1, false) - prices[i] + return max(buy, cooldown) + } else { + let sell = dfs(i + 2, true) + prices[i] + return max(sell, cooldown) + } + } + + return dfs(0, true) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -412,6 +437,36 @@ class Solution { } ``` +```swift +class Solution { + func maxProfit(_ prices: [Int]) -> Int { + let n = prices.count + var dp = [[Int?]](repeating: [Int?](repeating: nil, count: 2), count: n) + + func dfs(_ i: Int, _ buying: Int) -> Int { + if i >= n { + return 0 + } + if let cached = dp[i][buying] { + return cached + } + + let cooldown = dfs(i + 1, buying) + if buying == 1 { + let buy = dfs(i + 1, 0) - prices[i] + dp[i][buying] = max(buy, cooldown) + } else { + let sell = dfs(i + 2, 1) + prices[i] + dp[i][buying] = max(sell, cooldown) + } + return dp[i][buying]! + } + + return dfs(0, 1) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -611,6 +666,31 @@ class Solution { } ``` +```swift +class Solution { + func maxProfit(_ prices: [Int]) -> Int { + let n = prices.count + var dp = Array(repeating: [0, 0], count: n + 1) + + for i in stride(from: n - 1, through: 0, by: -1) { + for buying in 0...1 { + if buying == 1 { + let buy = (i + 1 < n ? dp[i + 1][0] - prices[i] : -prices[i]) + let cooldown = (i + 1 < n ? dp[i + 1][1] : 0) + dp[i][1] = max(buy, cooldown) + } else { + let sell = (i + 2 < n ? dp[i + 2][1] + prices[i] : prices[i]) + let cooldown = (i + 1 < n ? dp[i + 1][0] : 0) + dp[i][0] = max(sell, cooldown) + } + } + } + + return dp[0][1] + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -769,6 +849,26 @@ class Solution { } ``` +```swift +class Solution { + func maxProfit(_ prices: [Int]) -> Int { + let n = prices.count + var dp1Buy = 0, dp1Sell = 0 + var dp2Buy = 0 + + for i in stride(from: n - 1, through: 0, by: -1) { + let dpBuy = max(dp1Sell - prices[i], dp1Buy) + let dpSell = max(dp2Buy + prices[i], dp1Sell) + dp2Buy = dp1Buy + dp1Buy = dpBuy + dp1Sell = dpSell + } + + return dp1Buy + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/buy-and-sell-crypto.md b/articles/buy-and-sell-crypto.md index 0e618efd5..b983fd272 100644 --- a/articles/buy-and-sell-crypto.md +++ b/articles/buy-and-sell-crypto.md @@ -120,6 +120,22 @@ class Solution { } ``` +```swift +class Solution { + func maxProfit(_ prices: [Int]) -> Int { + var res = 0 + for i in 0.. Int { + var l = 0, r = 1 + var maxP = 0 + + while r < prices.count { + if prices[l] < prices[r] { + let profit = prices[r] - prices[l] + maxP = max(maxP, profit) + } else { + l = r + } + r += 1 + } + return maxP + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -397,6 +433,21 @@ class Solution { } ``` +```swift +class Solution { + func maxProfit(_ prices: [Int]) -> Int { + var maxP = 0 + var minBuy = prices[0] + + for sell in prices { + maxP = max(maxP, sell - minBuy) + minBuy = min(minBuy, sell) + } + return maxP + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/car-fleet.md b/articles/car-fleet.md index 2d4e2ef35..22c7a9d0f 100644 --- a/articles/car-fleet.md +++ b/articles/car-fleet.md @@ -150,6 +150,26 @@ class Solution { } ``` +```swift +class Solution { + func carFleet(_ target: Int, _ position: [Int], _ speed: [Int]) -> Int { + var pair = zip(position, speed).map { ($0, $1) } + pair.sort { $0.0 > $1.0 } // Sort in descending order by position + + var stack = [Double]() + + for (p, s) in pair { + stack.append(Double(target - p) / Double(s)) + if stack.count >= 2 && stack.last! <= stack[stack.count - 2] { + stack.removeLast() + } + } + + return stack.count + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -327,6 +347,30 @@ class Solution { } ``` +```swift +class Solution { + func carFleet(_ target: Int, _ position: [Int], _ speed: [Int]) -> Int { + var pair = zip(position, speed).map { ($0, $1) } + pair.sort { $0.0 > $1.0 } // Sort in descending order by position + + var fleets = 1 + var prevTime = Double(target - pair[0].0) / Double(pair[0].1) + + for i in 1.. prevTime { + fleets += 1 + prevTime = currTime + } + } + + return fleets + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/cheapest-flight-path.md b/articles/cheapest-flight-path.md index 6c23351be..976640249 100644 --- a/articles/cheapest-flight-path.md +++ b/articles/cheapest-flight-path.md @@ -258,6 +258,53 @@ class Solution { } ``` +```swift +struct Item: Comparable { + let cost: Int + let node: Int + let stops: Int + + static func < (lhs: Item, rhs: Item) -> Bool { + return lhs.cost < rhs.cost + } +} + +class Solution { + func findCheapestPrice(_ n: Int, _ flights: [[Int]], _ src: Int, _ dst: Int, _ k: Int) -> Int { + let INF = Int.max + var adj = Array(repeating: [(Int, Int)](), count: n) + var dist = Array(repeating: Array(repeating: INF, count: k + 5), count: n) + + for flight in flights { + let u = flight[0], v = flight[1], cst = flight[2] + adj[u].append((v, cst)) + } + + var minHeap = Heap() + minHeap.insert(Item(cost: 0, node: src, stops: -1)) + dist[src][0] = 0 + + while !minHeap.isEmpty { + let item = minHeap.removeMin() + let cst = item.cost, node = item.node, stops = item.stops + if node == dst { return cst } + if stops == k || dist[node][stops + 1] < cst { continue } + + for (nei, w) in adj[node] { + let nextCst = cst + w + let nextStops = stops + 1 + if dist[nei][nextStops + 1] > nextCst { + dist[nei][nextStops + 1] = nextCst + minHeap.insert(Item(cost: nextCst, node: nei, stops: nextStops)) + } + } + } + + return -1 + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -471,6 +518,31 @@ class Solution { } ``` +```swift +class Solution { + func findCheapestPrice(_ n: Int, _ flights: [[Int]], _ src: Int, _ dst: Int, _ k: Int) -> Int { + var prices = Array(repeating: Int.max, count: n) + prices[src] = 0 + + for _ in 0...k { + var tmpPrices = prices + + for flight in flights { + let s = flight[0], d = flight[1], p = flight[2] + if prices[s] == Int.max { + continue + } + if prices[s] + p < tmpPrices[d] { + tmpPrices[d] = prices[s] + p + } + } + prices = tmpPrices + } + return prices[dst] == Int.max ? -1 : prices[dst] + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -727,6 +799,41 @@ class Solution { } ``` +```swift +class Solution { + func findCheapestPrice(_ n: Int, _ flights: [[Int]], _ src: Int, _ dst: Int, _ k: Int) -> Int { + var prices = Array(repeating: Int.max, count: n) + prices[src] = 0 + var adj = Array(repeating: [(Int, Int)](), count: n) + + for flight in flights { + let u = flight[0], v = flight[1], cst = flight[2] + adj[u].append((v, cst)) + } + + var queue = Deque<(Int, Int, Int)>() + queue.append((0, src, 0)) + + while !queue.isEmpty { + let (cst, node, stops) = queue.popFirst()! + if stops > k { + continue + } + + for (nei, w) in adj[node] { + let nextCost = cst + w + if nextCost < prices[nei] { + prices[nei] = nextCost + queue.append((nextCost, nei, stops + 1)) + } + } + } + + return prices[dst] == Int.max ? -1 : prices[dst] + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/climbing-stairs.md b/articles/climbing-stairs.md index a1a70e0fa..126511582 100644 --- a/articles/climbing-stairs.md +++ b/articles/climbing-stairs.md @@ -99,6 +99,21 @@ class Solution { } ``` +```swift +class Solution { + func climbStairs(_ n: Int) -> Int { + func dfs(_ i: Int) -> Int { + if i >= n { + return i == n ? 1 : 0 + } + return dfs(i + 1) + dfs(i + 2) + } + + return dfs(0) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -240,6 +255,27 @@ class Solution { } ``` +```swift +class Solution { + func climbStairs(_ n: Int) -> Int { + var cache = Array(repeating: -1, count: n) + + func dfs(_ i: Int) -> Int { + if i >= n { + return i == n ? 1 : 0 + } + if cache[i] != -1 { + return cache[i] + } + cache[i] = dfs(i + 1) + dfs(i + 2) + return cache[i] + } + + return dfs(0) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -368,6 +404,23 @@ class Solution { } ``` +```swift +class Solution { + func climbStairs(_ n: Int) -> Int { + if n <= 2 { + return n + } + var dp = Array(repeating: 0, count: n + 1) + dp[1] = 1 + dp[2] = 2 + for i in 3...n { + dp[i] = dp[i - 1] + dp[i - 2] + } + return dp[n] + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -495,6 +548,22 @@ class Solution { } ``` +```swift +class Solution { + func climbStairs(_ n: Int) -> Int { + var one = 1, two = 1 + + for _ in 0..<(n - 1) { + let temp = one + one = one + two + two = temp + } + + return one + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -764,6 +833,45 @@ class Solution { } ``` +```swift +class Solution { + func climbStairs(_ n: Int) -> Int { + if n == 1 { + return 1 + } + + func matrixMult(_ A: [[Int]], _ B: [[Int]]) -> [[Int]] { + return [ + [A[0][0] * B[0][0] + A[0][1] * B[1][0], + A[0][0] * B[0][1] + A[0][1] * B[1][1]], + [A[1][0] * B[0][0] + A[1][1] * B[1][0], + A[1][0] * B[0][1] + A[1][1] * B[1][1]] + ] + } + + func matrixPow(_ M: [[Int]], _ p: Int) -> [[Int]] { + var result = [[1, 0], [0, 1]] + var base = M + var power = p + + while power > 0 { + if power % 2 == 1 { + result = matrixMult(result, base) + } + base = matrixMult(base, base) + power /= 2 + } + + return result + } + + let M = [[1, 1], [1, 0]] + let result = matrixPow(M, n) + return result[0][0] + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -865,6 +973,18 @@ class Solution { } ``` +```swift +class Solution { + func climbStairs(_ n: Int) -> Int { + let sqrt5 = sqrt(5.0) + let phi = (1.0 + sqrt5) / 2.0 + let psi = (1.0 - sqrt5) / 2.0 + let n = n + 1 + return Int(round((pow(phi, Double(n)) - pow(psi, Double(n))) / sqrt5)) + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/clone-graph.md b/articles/clone-graph.md index ff2612c4c..e71e55184 100644 --- a/articles/clone-graph.md +++ b/articles/clone-graph.md @@ -290,6 +290,47 @@ class Solution { } ``` +```swift +/** + * Definition for a Node. + * public class Node { + * public var val: Int + * public var neighbors: [Node?] + * public init(_ val: Int) { + * self.val = val + * self.neighbors = [] + * } + * } + */ + +class Solution { + func cloneGraph(_ node: Node?) -> Node? { + var oldToNew = [Node: Node]() + + func dfs(_ node: Node?) -> Node? { + guard let node = node else { return nil } + + if let existingCopy = oldToNew[node] { + return existingCopy + } + + let copy = Node(node.val) + oldToNew[node] = copy + + for neighbor in node.neighbors { + if let clonedNeighbor = dfs(neighbor) { + copy.neighbors.append(clonedNeighbor) + } + } + + return copy + } + + return dfs(node) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -582,6 +623,49 @@ class Solution { } ``` +```swift +/** + * Definition for a Node. + * public class Node { + * public var val: Int + * public var neighbors: [Node?] + * public init(_ val: Int) { + * self.val = val + * self.neighbors = [] + * } + * } + */ + +class Solution { + func cloneGraph(_ node: Node?) -> Node? { + if node == nil { + return nil + } + + var oldToNew: [Node: Node] = [:] + let newNode = Node(node!.val) + oldToNew[node!] = newNode + var queue = Deque() + queue.append(node!) + + while !queue.isEmpty { + let cur = queue.popFirst()! + for nei in cur.neighbors { + if let nei = nei { + if oldToNew[nei] == nil { + oldToNew[nei] = Node(nei.val) + queue.append(nei) + } + oldToNew[cur]!.neighbors.append(oldToNew[nei]!) + } + } + } + + return oldToNew[node!] + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/coin-change-ii.md b/articles/coin-change-ii.md index cdfd83983..6e4cce788 100644 --- a/articles/coin-change-ii.md +++ b/articles/coin-change-ii.md @@ -178,6 +178,32 @@ class Solution { } ``` +```swift +class Solution { + func change(_ amount: Int, _ coins: [Int]) -> Int { + let coins = coins.sorted() + + func dfs(_ i: Int, _ a: Int) -> Int { + if a == 0 { + return 1 + } + if i >= coins.count { + return 0 + } + + var res = 0 + if a >= coins[i] { + res = dfs(i + 1, a) + res += dfs(i, a - coins[i]) + } + return res + } + + return dfs(0, amount) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -399,6 +425,38 @@ class Solution { } ``` +```swift +class Solution { + func change(_ amount: Int, _ coins: [Int]) -> Int { + let coins = coins.sorted() + var memo = Array(repeating: Array(repeating: -1, count: amount + 1), count: coins.count + 1) + + func dfs(_ i: Int, _ a: Int) -> Int { + if a == 0 { + return 1 + } + if i >= coins.count { + return 0 + } + if memo[i][a] != -1 { + return memo[i][a] + } + + var res = 0 + if a >= coins[i] { + res = dfs(i + 1, a) + res += dfs(i, a - coins[i]) + } + + memo[i][a] = res + return res + } + + return dfs(0, amount) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -464,8 +522,8 @@ public: int change(int amount, vector& coins) { int n = coins.size(); sort(coins.begin(), coins.end()); - vector> dp(n + 1, vector(amount + 1, 0)); - + vector> dp(n + 1, vector(amount + 1, 0)); + for (int i = 0; i <= n; i++) { dp[i][0] = 1; } @@ -592,6 +650,41 @@ class Solution { } ``` +```swift +class Solution { + func change(_ amount: Int, _ coins: [Int]) -> Int { + let n = coins.count + let sortedCoins = coins.sorted() + var dp = Array( + repeating: Array(repeating: 0, count: amount + 1), + count: n + 1 + ) + + for i in 0...n { + dp[i][0] = 1 + } + + for i in stride(from: n - 1, through: 0, by: -1) { + for a in 0...amount { + let base = dp[i + 1][a] + if a >= sortedCoins[i] { + let addend = dp[i][a - sortedCoins[i]] + if base > Int.max - addend { + dp[i][a] = 0 + } else { + dp[i][a] = base + addend + } + } else { + dp[i][a] = base + } + } + } + + return dp[0][amount] + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -650,10 +743,10 @@ public class Solution { class Solution { public: int change(int amount, vector& coins) { - vector dp(amount + 1, 0); + vector dp(amount + 1, 0); dp[0] = 1; for (int i = coins.size() - 1; i >= 0; i--) { - vector nextDP(amount + 1, 0); + vector nextDP(amount + 1, 0); nextDP[0] = 1; for (int a = 1; a <= amount; a++) { @@ -764,6 +857,36 @@ class Solution { } ``` +```swift +class Solution { + func change(_ amount: Int, _ coins: [Int]) -> Int { + var dp = [Int](repeating: 0, count: amount + 1) + dp[0] = 1 + + for i in stride(from: coins.count - 1, through: 0, by: -1) { + var nextDP = [Int](repeating: 0, count: amount + 1) + nextDP[0] = 1 + + for a in 1..<(amount + 1) { + nextDP[a] = dp[a] + if a - coins[i] >= 0 { + let addend = nextDP[a - coins[i]] + if nextDP[a] > Int.max - addend { + nextDP[a] = 0 + } else { + nextDP[a] += addend + } + } + } + + dp = nextDP + } + + return dp[amount] + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -807,7 +930,7 @@ public class Solution { class Solution { public: int change(int amount, vector& coins) { - vector dp(amount + 1, 0); + vector dp(amount + 1, 0); dp[0] = 1; for (int i = coins.size() - 1; i >= 0; i--) { for (int a = 1; a <= amount; a++) { @@ -890,6 +1013,30 @@ class Solution { } ``` +```swift +class Solution { + func change(_ amount: Int, _ coins: [Int]) -> Int { + var dp = [Int](repeating: 0, count: amount + 1) + dp[0] = 1 + + for i in stride(from: coins.count - 1, through: 0, by: -1) { + for a in 1..<(amount + 1) { + if coins[i] <= a { + let addend = dp[a - coins[i]] + if dp[a] > Int.max - addend { + dp[a] = 0 + } else { + dp[a] += addend + } + } + } + } + + return dp[amount] + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/coin-change.md b/articles/coin-change.md index eb1f7e715..f61f99922 100644 --- a/articles/coin-change.md +++ b/articles/coin-change.md @@ -170,6 +170,29 @@ class Solution { } ``` +```swift +class Solution { + func coinChange(_ coins: [Int], _ amount: Int) -> Int { + func dfs(_ amount: Int) -> Int { + if amount == 0 { + return 0 + } + + var res = Int(1e9) + for coin in coins { + if amount - coin >= 0 { + res = min(res, 1 + dfs(amount - coin)) + } + } + return res + } + + let minCoins = dfs(amount) + return minCoins >= Int(1e9) ? -1 : minCoins + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -393,6 +416,36 @@ class Solution { } ``` +```swift +class Solution { + func coinChange(_ coins: [Int], _ amount: Int) -> Int { + var memo = [Int: Int]() + + func dfs(_ amount: Int) -> Int { + if amount == 0 { + return 0 + } + if let cached = memo[amount] { + return cached + } + + var res = Int(1e9) + for coin in coins { + if amount - coin >= 0 { + res = min(res, 1 + dfs(amount - coin)) + } + } + + memo[amount] = res + return res + } + + let minCoins = dfs(amount) + return minCoins >= Int(1e9) ? -1 : minCoins + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -542,6 +595,29 @@ class Solution { } ``` +```swift +class Solution { + func coinChange(_ coins: [Int], _ amount: Int) -> Int { + if amount == 0 { + return 0 + } + + var dp = [Int](repeating: amount + 1, count: amount + 1) + dp[0] = 0 + + for a in 1...amount { + for coin in coins { + if a - coin >= 0 { + dp[a] = min(dp[a], 1 + dp[a - coin]) + } + } + } + + return dp[amount] == amount + 1 ? -1 : dp[amount] + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -772,6 +848,41 @@ class Solution { } ``` +```swift +class Solution { + func coinChange(_ coins: [Int], _ amount: Int) -> Int { + if amount == 0 { + return 0 + } + + var q = Deque([0]) + var seen = Array(repeating: false, count: amount + 1) + seen[0] = true + var res = 0 + + while !q.isEmpty { + res += 1 + for _ in 0.. amount || seen[nxt] { + continue + } + seen[nxt] = true + q.append(nxt) + } + } + } + + return -1 + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/combination-target-sum-ii.md b/articles/combination-target-sum-ii.md index 0c9a90f24..3b35aab6d 100644 --- a/articles/combination-target-sum-ii.md +++ b/articles/combination-target-sum-ii.md @@ -216,6 +216,35 @@ class Solution { } ``` +```swift +class Solution { + func combinationSum2(_ candidates: [Int], _ target: Int) -> [[Int]] { + var res = Set<[Int]>() + let sortedCandidates = candidates.sorted() + + func generateSubsets(_ i: Int, _ cur: inout [Int], _ total: Int) { + if total == target { + res.insert(cur) + return + } + if total > target || i == sortedCandidates.count { + return + } + + cur.append(sortedCandidates[i]) + generateSubsets(i + 1, &cur, total + sortedCandidates[i]) + cur.removeLast() + + generateSubsets(i + 1, &cur, total) + } + + var cur: [Int] = [] + generateSubsets(0, &cur, 0) + return Array(res) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -464,6 +493,39 @@ class Solution { } ``` +```swift +class Solution { + func combinationSum2(_ candidates: [Int], _ target: Int) -> [[Int]] { + var res = [[Int]]() + let sortedCandidates = candidates.sorted() + + func dfs(_ i: Int, _ cur: inout [Int], _ total: Int) { + if total == target { + res.append(cur) + return + } + if total > target || i == sortedCandidates.count { + return + } + + cur.append(sortedCandidates[i]) + dfs(i + 1, &cur, total + sortedCandidates[i]) + cur.removeLast() + + var j = i + while j + 1 < sortedCandidates.count && sortedCandidates[j] == sortedCandidates[j + 1] { + j += 1 + } + dfs(j + 1, &cur, total) + } + + var cur: [Int] = [] + dfs(0, &cur, 0) + return res + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -772,6 +834,47 @@ class Solution { } ``` +```swift +class Solution { + func combinationSum2(_ nums: [Int], _ target: Int) -> [[Int]] { + var res = [[Int]]() + var count = [Int: Int]() + var uniqueNums = [Int]() + + for num in nums { + if count[num] == nil { + uniqueNums.append(num) + } + count[num, default: 0] += 1 + } + + func backtrack(_ nums: [Int], _ target: Int, _ cur: inout [Int], _ i: Int) { + if target == 0 { + res.append(cur) + return + } + if target < 0 || i >= nums.count { + return + } + + if count[nums[i], default: 0] > 0 { + cur.append(nums[i]) + count[nums[i], default: 0] -= 1 + backtrack(nums, target - nums[i], &cur, i) + count[nums[i], default: 0] += 1 + cur.removeLast() + } + + backtrack(nums, target, &cur, i + 1) + } + + var cur: [Int] = [] + backtrack(uniqueNums, target, &cur, 0) + return res + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -1008,6 +1111,39 @@ class Solution { } ``` +```swift +class Solution { + func combinationSum2(_ candidates: [Int], _ target: Int) -> [[Int]] { + var res = [[Int]]() + let sortedCandidates = candidates.sorted() + + func dfs(_ idx: Int, _ path: inout [Int], _ cur: Int) { + if cur == target { + res.append(path) + return + } + + for i in idx.. idx && sortedCandidates[i] == sortedCandidates[i - 1] { + continue + } + if cur + sortedCandidates[i] > target { + break + } + + path.append(sortedCandidates[i]) + dfs(i + 1, &path, cur + sortedCandidates[i]) + path.removeLast() + } + } + + var path: [Int] = [] + dfs(0, &path, 0) + return res + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/combination-target-sum.md b/articles/combination-target-sum.md index 43a9f3cd1..46436ad64 100644 --- a/articles/combination-target-sum.md +++ b/articles/combination-target-sum.md @@ -194,6 +194,33 @@ class Solution { } ``` +```swift +class Solution { + func combinationSum(_ nums: [Int], _ target: Int) -> [[Int]] { + var res: [[Int]] = [] + + func dfs(_ i: Int, _ cur: inout [Int], _ total: Int) { + if total == target { + res.append(cur) + return + } + if i >= nums.count || total > target { + return + } + + cur.append(nums[i]) + dfs(i, &cur, total + nums[i]) + cur.removeLast() + dfs(i + 1, &cur, total) + } + + var cur: [Int] = [] + dfs(0, &cur, 0) + return res + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -406,6 +433,35 @@ class Solution { } ``` +```swift +class Solution { + func combinationSum(_ nums: [Int], _ target: Int) -> [[Int]] { + var res: [[Int]] = [] + let sortedNums = nums.sorted() + + func dfs(_ i: Int, _ cur: inout [Int], _ total: Int) { + if total == target { + res.append(cur) + return + } + + for j in i.. target { + return + } + cur.append(sortedNums[j]) + dfs(j, &cur, total + sortedNums[j]) + cur.removeLast() + } + } + + var cur: [Int] = [] + dfs(0, &cur, 0) + return res + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/combinations-of-a-phone-number.md b/articles/combinations-of-a-phone-number.md index 941f7ebf6..6f6bfd6dd 100644 --- a/articles/combinations-of-a-phone-number.md +++ b/articles/combinations-of-a-phone-number.md @@ -212,12 +212,45 @@ class Solution { } ``` +```swift +class Solution { + func letterCombinations(_ digits: String) -> [String] { + guard !digits.isEmpty else { return [] } + + let digitToChar: [Character: String] = [ + "2": "abc", "3": "def", "4": "ghi", "5": "jkl", + "6": "mno", "7": "pqrs", "8": "tuv", "9": "wxyz" + ] + + var res = [String]() + let digitsArray = Array(digits) + + func backtrack(_ i: Int, _ curStr: String) { + if curStr.count == digits.count { + res.append(curStr) + return + } + if let letters = digitToChar[digitsArray[i]] { + for c in letters { + backtrack(i + 1, curStr + String(c)) + } + } + } + + backtrack(0, "") + return res + } +} +``` + ::tabs-end ### Time & Space Complexity * Time complexity: $O(n * 4 ^ n)$ -* Space complexity: $O(n)$ +* Space complexity: + * $O(n)$ extra space. + * $O(n * 4 ^ n)$ space for the output list. --- @@ -429,9 +462,39 @@ class Solution { } ``` +```swift +class Solution { + func letterCombinations(_ digits: String) -> [String] { + guard !digits.isEmpty else { return [] } + + let digitToChar: [Character: String] = [ + "2": "abc", "3": "def", "4": "ghi", "5": "jkl", + "6": "mno", "7": "pqrs", "8": "tuv", "9": "wxyz" + ] + + var res = [""] + + for digit in digits { + guard let letters = digitToChar[digit] else { continue } + var tmp = [String]() + for curStr in res { + for c in letters { + tmp.append(curStr + String(c)) + } + } + res = tmp + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity * Time complexity: $O(n * 4 ^ n)$ -* Space complexity: $O(n)$ \ No newline at end of file +* Space complexity: + * $O(n)$ extra space. + * $O(n * 4 ^ n)$ space for the output list. \ No newline at end of file diff --git a/articles/copy-linked-list-with-random-pointer.md b/articles/copy-linked-list-with-random-pointer.md index 2c8acaed9..0b595bf64 100644 --- a/articles/copy-linked-list-with-random-pointer.md +++ b/articles/copy-linked-list-with-random-pointer.md @@ -1,4 +1,4 @@ -## 1. Hash Map (Recursion) +## 1. Recursion + Hash Map ::tabs-start @@ -223,6 +223,44 @@ class Solution { } ``` +```swift +/** + * Definition for a Node. + * public class Node { + * public var val: Int + * public var next: Node? + * public var random: Node? + * public init(_ val: Int) { + * self.val = val + * self.next = nil + * self.random = nil + * } + * } + */ + +class Solution { + private var map = [Node: Node]() + + func copyRandomList(_ head: Node?) -> Node? { + if head == nil { + return nil + } + + if let copied = map[head!] { + return copied + } + + let copy = Node(head!.val) + map[head!] = copy + + copy.next = copyRandomList(head!.next) + copy.random = copyRandomList(head!.random) + + return copy + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -494,6 +532,45 @@ class Solution { } ``` +```swift +/** + * Definition for a Node. + * public class Node { + * public var val: Int + * public var next: Node? + * public var random: Node? + * public init(_ val: Int) { + * self.val = val + * self.next = nil + * self.random = nil + * } + * } + */ + +class Solution { + func copyRandomList(_ head: Node?) -> Node? { + var oldToCopy: [Node?: Node?] = [nil: nil] + + var cur = head + while cur != nil { + let copy = Node(cur!.val) + oldToCopy[cur] = copy + cur = cur?.next + } + + cur = head + while cur != nil { + let copy = oldToCopy[cur]! + copy?.next = oldToCopy[cur?.next]! + copy?.random = oldToCopy[cur?.random]! + cur = cur?.next + } + + return oldToCopy[head]! + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -789,6 +866,46 @@ class Solution { } ``` +```swift +/** + * Definition for a Node. + * public class Node { + * public var val: Int + * public var next: Node? + * public var random: Node? + * public init(_ val: Int) { + * self.val = val + * self.next = nil + * self.random = nil + * } + * } + */ + +class Solution { + func copyRandomList(_ head: Node?) -> Node? { + var oldToCopy = [Node?: Node?]() + + func getNode(_ node: Node?) -> Node? { + if node == nil { return nil } + if oldToCopy[node] == nil { + oldToCopy[node] = Node(0) + } + return oldToCopy[node]! + } + + var cur = head + while cur != nil { + getNode(cur)!.val = cur!.val + getNode(cur)!.next = getNode(cur!.next) + getNode(cur)!.random = getNode(cur!.random) + cur = cur!.next + } + + return getNode(head) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -1161,12 +1278,67 @@ class Solution { } ``` +```swift +/** + * Definition for a Node. + * public class Node { + * public var val: Int + * public var next: Node? + * public var random: Node? + * public init(_ val: Int) { + * self.val = val + * self.next = nil + * self.random = nil + * } + * } + */ + +class Solution { + func copyRandomList(_ head: Node?) -> Node? { + if head == nil { + return nil + } + + var l1 = head + while l1 != nil { + let l2 = Node(l1!.val) + l2.next = l1?.next + l1?.next = l2 + l1 = l2.next + } + + let newHead = head?.next + l1 = head + while l1 != nil { + if let random = l1?.random { + l1?.next?.random = random.next + } + l1 = l1?.next?.next + } + + l1 = head + while l1 != nil { + let l2 = l1?.next + l1?.next = l2?.next + if l2?.next != nil { + l2?.next = l2?.next?.next + } + l1 = l1?.next + } + + return newHead + } +} +``` + ::tabs-end ### Time & Space Complexity * Time complexity: $O(n)$ -* Space complexity: $O(1)$ +* Space complexity: + * $O(1)$ extra space. + * $O(n)$ for the output. --- @@ -1525,9 +1697,62 @@ class Solution { } ``` +```swift +/** + * Definition for a Node. + * public class Node { + * public var val: Int + * public var next: Node? + * public var random: Node? + * public init(_ val: Int) { + * self.val = val + * self.next = nil + * self.random = nil + * } + * } + */ + +class Solution { + func copyRandomList(_ head: Node?) -> Node? { + if head == nil { + return nil + } + + var l1 = head + while l1 != nil { + let l2 = Node(l1!.val) + l2.next = l1?.random + l1?.random = l2 + l1 = l1?.next + } + + let newHead = head?.random + + l1 = head + while l1 != nil { + let l2 = l1?.random + l2?.random = l2?.next?.random + l1 = l1?.next + } + + l1 = head + while l1 != nil { + let l2 = l1?.random + l1?.random = l2?.next + l2?.next = l1?.next?.random + l1 = l1?.next + } + + return newHead + } +} +``` + ::tabs-end ### Time & Space Complexity * Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +* Space complexity: + * $O(1)$ extra space. + * $O(n)$ for the output. \ No newline at end of file diff --git a/articles/count-connected-components.md b/articles/count-connected-components.md index 0f0dc28ba..c31580864 100644 --- a/articles/count-connected-components.md +++ b/articles/count-connected-components.md @@ -229,6 +229,41 @@ class Solution { } ``` +```swift +class Solution { + func countComponents(_ n: Int, _ edges: [[Int]]) -> Int { + var adj = Array(repeating: [Int](), count: n) + var visit = Array(repeating: false, count: n) + + for edge in edges { + let u = edge[0], v = edge[1] + adj[u].append(v) + adj[v].append(u) + } + + func dfs(_ node: Int) { + for nei in adj[node] { + if !visit[nei] { + visit[nei] = true + dfs(nei) + } + } + } + + var res = 0 + for node in 0.. Int { + var adj = Array(repeating: [Int](), count: n) + var visit = Array(repeating: false, count: n) + for edge in edges { + let u = edge[0], v = edge[1] + adj[u].append(v) + adj[v].append(u) + } + + func bfs(_ node: Int) { + var q = Deque() + q.append(node) + visit[node] = true + while !q.isEmpty { + let cur = q.removeFirst() + for nei in adj[cur] { + if !visit[nei] { + visit[nei] = true + q.append(nei) + } + } + } + } + + var res = 0 + for node in 0.. Int { + var cur = node + while cur != parent[cur] { + parent[cur] = parent[parent[cur]] + cur = parent[cur] + } + return cur + } + + func union(_ u: Int, _ v: Int) -> Bool { + let pu = find(u) + let pv = find(v) + if pu == pv { return false } + var rootU = pu + var rootV = pv + if rank[rootV] > rank[rootU] { + swap(&rootU, &rootV) + } + parent[rootV] = rootU + rank[rootU] += rank[rootV] + return true + } +} + +class Solution { + func countComponents(_ n: Int, _ edges: [[Int]]) -> Int { + let dsu = DSU(n) + var res = n + for edge in edges { + let u = edge[0], v = edge[1] + if dsu.union(u, v) { + res -= 1 + } + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/count-good-nodes-in-binary-tree.md b/articles/count-good-nodes-in-binary-tree.md index 1eda1a860..d9356f32c 100644 --- a/articles/count-good-nodes-in-binary-tree.md +++ b/articles/count-good-nodes-in-binary-tree.md @@ -250,6 +250,39 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func goodNodes(_ root: TreeNode?) -> Int { + func dfs(_ node: TreeNode?, _ maxVal: Int) -> Int { + guard let node = node else { return 0 } + + var res = node.val >= maxVal ? 1 : 0 + let newMaxVal = max(maxVal, node.val) + res += dfs(node.left, newMaxVal) + res += dfs(node.right, newMaxVal) + return res + } + + return dfs(root, root?.val ?? Int.min) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -545,6 +578,51 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func goodNodes(_ root: TreeNode?) -> Int { + guard let root = root else { return 0 } + + var res = 0 + var q = Deque<(TreeNode, Int)>() + q.append((root, Int.min)) + + while !q.isEmpty { + let (node, maxVal) = q.popFirst()! + if node.val >= maxVal { + res += 1 + } + + let newMaxVal = max(maxVal, node.val) + + if let left = node.left { + q.append((left, newMaxVal)) + } + if let right = node.right { + q.append((right, newMaxVal)) + } + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/count-number-of-islands.md b/articles/count-number-of-islands.md index cee406700..042d79082 100644 --- a/articles/count-number-of-islands.md +++ b/articles/count-number-of-islands.md @@ -236,6 +236,40 @@ class Solution { } ``` +```swift +class Solution { + func numIslands(_ grid: [[Character]]) -> Int { + let directions = [[1, 0], [-1, 0], [0, 1], [0, -1]] + let ROWS = grid.count + let COLS = grid[0].count + var islands = 0 + var grid = grid + + func dfs(_ r: Int, _ c: Int) { + if r < 0 || c < 0 || r >= ROWS || c >= COLS || grid[r][c] == "0" { + return + } + + grid[r][c] = "0" + for dir in directions { + dfs(r + dir[0], c + dir[1]) + } + } + + for r in 0.. Int { + let directions = [[1, 0], [-1, 0], [0, 1], [0, -1]] + let ROWS = grid.count + let COLS = grid[0].count + var islands = 0 + var grid = grid + + func bfs(_ r: Int, _ c: Int) { + var queue = Deque<(Int, Int)>() + grid[r][c] = "0" + queue.append((r, c)) + + while !queue.isEmpty { + let (row, col) = queue.popFirst()! + for dir in directions { + let nr = row + dir[0] + let nc = col + dir[1] + if nr < 0 || nc < 0 || nr >= ROWS || nc >= COLS || grid[nr][nc] == "0" { + continue + } + queue.append((nr, nc)) + grid[nr][nc] = "0" + } + } + } + + for r in 0.. Int { + if parent[node] != node { + parent[node] = find(parent[node]) + } + return parent[node] + } + + func union(_ u: Int, _ v: Int) -> Bool { + let pu = find(u) + let pv = find(v) + if pu == pv { + return false + } + if size[pu] >= size[pv] { + size[pu] += size[pv] + parent[pv] = pu + } else { + size[pv] += size[pu] + parent[pu] = pv + } + return true + } +} + +class Solution { + func numIslands(_ grid: [[Character]]) -> Int { + let ROWS = grid.count + let COLS = grid[0].count + let dsu = DSU(ROWS * COLS) + + func index(_ r: Int, _ c: Int) -> Int { + return r * COLS + c + } + + let directions = [(1, 0), (-1, 0), (0, 1), (0, -1)] + var islands = 0 + var grid = grid + + for r in 0..= ROWS || nc >= COLS || grid[nr][nc] == "0" { + continue + } + if dsu.union(index(r, c), index(nr, nc)) { + islands -= 1 + } + } + } + } + } + + return islands + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/count-paths.md b/articles/count-paths.md index 61ab8e148..5db166df2 100644 --- a/articles/count-paths.md +++ b/articles/count-paths.md @@ -121,6 +121,24 @@ class Solution { } ``` +```swift +class Solution { + func uniquePaths(_ m: Int, _ n: Int) -> Int { + func dfs(_ i: Int, _ j: Int) -> Int { + if i == m - 1 && j == n - 1 { + return 1 + } + if i >= m || j >= n { + return 0 + } + return dfs(i, j + 1) + dfs(i + 1, j) + } + + return dfs(0, 0) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -304,6 +322,31 @@ class Solution { } ``` +```swift +class Solution { + func uniquePaths(_ m: Int, _ n: Int) -> Int { + var memo = Array(repeating: Array(repeating: -1, count: n), count: m) + + func dfs(_ i: Int, _ j: Int) -> Int { + if i == m - 1 && j == n - 1 { + return 1 + } + if i >= m || j >= n { + return 0 + } + if memo[i][j] != -1 { + return memo[i][j] + } + + memo[i][j] = dfs(i, j + 1) + dfs(i + 1, j) + return memo[i][j] + } + + return dfs(0, 0) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -442,6 +485,23 @@ class Solution { } ``` +```swift +class Solution { + func uniquePaths(_ m: Int, _ n: Int) -> Int { + var dp = Array(repeating: Array(repeating: 0, count: n + 1), count: m + 1) + dp[m - 1][n - 1] = 1 + + for i in stride(from: m - 1, through: 0, by: -1) { + for j in stride(from: n - 1, through: 0, by: -1) { + dp[i][j] += dp[i + 1][j] + dp[i][j + 1] + } + } + + return dp[0][0] + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -585,6 +645,23 @@ class Solution { } ``` +```swift +class Solution { + func uniquePaths(_ m: Int, _ n: Int) -> Int { + var row = Array(repeating: 1, count: n) + + for _ in 0..<(m - 1) { + var newRow = Array(repeating: 1, count: n) + for j in stride(from: n - 2, through: 0, by: -1) { + newRow[j] = newRow[j + 1] + row[j] + } + row = newRow + } + return row[0] + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -716,6 +793,22 @@ class Solution { } ``` +```swift +class Solution { + func uniquePaths(_ m: Int, _ n: Int) -> Int { + var dp = Array(repeating: 1, count: n) + + for _ in stride(from: m - 2, through: 0, by: -1) { + for j in stride(from: n - 2, through: 0, by: -1) { + dp[j] += dp[j + 1] + } + } + + return dp[0] + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -896,6 +989,30 @@ class Solution { } ``` +```swift +class Solution { + func uniquePaths(_ m: Int, _ n: Int) -> Int { + if m == 1 || n == 1 { + return 1 + } + var m = m, n = n + if m < n { + swap(&m, &n) + } + + var res = 1 + var j = 1 + for i in m..<(m + n - 1) { + res *= i + res /= j + j += 1 + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/count-squares.md b/articles/count-squares.md index 6b27ebb50..1b5defe8c 100644 --- a/articles/count-squares.md +++ b/articles/count-squares.md @@ -240,6 +240,40 @@ class CountSquares() { } ``` +```swift +class CountSquares { + private var ptsCount: [String: Int] + private var pts: [[Int]] + + init() { + self.ptsCount = [:] + self.pts = [] + } + + func add(_ point: [Int]) { + let key = "\(point[0]),\(point[1])" + ptsCount[key, default: 0] += 1 + pts.append(point) + } + + func count(_ point: [Int]) -> Int { + var res = 0 + let px = point[0], py = point[1] + + for pt in pts { + let x = pt[0], y = pt[1] + if abs(py - y) != abs(px - x) || x == px || y == py { + continue + } + let key1 = "\(x),\(py)" + let key2 = "\(px),\(y)" + res += (ptsCount[key1] ?? 0) * (ptsCount[key2] ?? 0) + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -320,10 +354,9 @@ public class CountSquares { ```cpp class CountSquares { unordered_map> ptsCount; + public: - CountSquares() { - - } + CountSquares() {} void add(vector point) { ptsCount[point[0]][point[1]]++; @@ -531,6 +564,40 @@ class CountSquares { } ``` +```swift +class CountSquares { + var ptsCount: [Int: [Int: Int]] + + init() { + ptsCount = [:] + } + + func add(_ point: [Int]) { + let x = point[0] + let y = point[1] + ptsCount[x, default: [:]][y, default: 0] += 1 + } + + func count(_ point: [Int]) -> Int { + var res = 0 + let x1 = point[0] + let y1 = point[1] + + if let yMap = ptsCount[x1] { + for (y2, countXY2) in yMap { + let side = y2 - y1 + if side == 0 { continue } + let x3 = x1 + side + let x4 = x1 - side + res += countXY2 * (ptsCount[x3]?[y1] ?? 0) * (ptsCount[x3]?[y2] ?? 0) + res += countXY2 * (ptsCount[x4]?[y1] ?? 0) * (ptsCount[x4]?[y2] ?? 0) + } + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/count-subsequences.md b/articles/count-subsequences.md index 04fd77389..241876a84 100644 --- a/articles/count-subsequences.md +++ b/articles/count-subsequences.md @@ -181,6 +181,29 @@ class Solution { } ``` +```swift +class Solution { + func numDistinct(_ s: String, _ t: String) -> Int { + let sArray = Array(s), tArray = Array(t) + let sLen = sArray.count, tLen = tArray.count + if tLen > sLen { return 0 } + + func dfs(_ i: Int, _ j: Int) -> Int { + if j == tLen { return 1 } + if i == sLen { return 0 } + + var res = dfs(i + 1, j) + if sArray[i] == tArray[j] { + res += dfs(i + 1, j + 1) + } + return res + } + + return dfs(0, 0) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -188,6 +211,8 @@ class Solution { * Time complexity: $O(2 ^ m)$ * Space complexity: $O(m)$ +> Where $m$ is the length of the string $s$. + --- ## 2. Dynamic Programming (Top-Down) @@ -396,6 +421,33 @@ class Solution { } ``` +```swift +class Solution { + func numDistinct(_ s: String, _ t: String) -> Int { + let sArray = Array(s), tArray = Array(t) + let sLen = sArray.count, tLen = tArray.count + if tLen > sLen { return 0 } + + var dp = [[Int]: Int]() + + func dfs(_ i: Int, _ j: Int) -> Int { + if j == tLen { return 1 } + if i == sLen { return 0 } + if let val = dp[[i, j]] { return val } + + var res = dfs(i + 1, j) + if sArray[i] == tArray[j] { + res += dfs(i + 1, j + 1) + } + dp[[i, j]] = res + return res + } + + return dfs(0, 0) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -458,7 +510,7 @@ class Solution { public: int numDistinct(string s, string t) { int m = s.length(), n = t.length(); - vector> dp(m + 1, vector(n + 1, 0)); + vector> dp(m + 1, vector(n + 1, 0)); for (int i = 0; i <= m; i++) { dp[i][n] = 1; @@ -582,6 +634,42 @@ class Solution { } ``` +```swift +class Solution { + func numDistinct(_ s: String, _ t: String) -> Int { + let m = s.count, n = t.count + var dp = Array( + repeating: Array(repeating: 0, count: n + 1), + count: m + 1 + ) + + let sArray = Array(s) + let tArray = Array(t) + + for i in 0...m { + dp[i][n] = 1 + } + + for i in stride(from: m - 1, through: 0, by: -1) { + for j in stride(from: n - 1, through: 0, by: -1) { + let base = dp[i + 1][j] + dp[i][j] = base + if sArray[i] == tArray[j] { + let addend = dp[i + 1][j + 1] + if base > Int.max - addend { + dp[i][j] = 0 + } else { + dp[i][j] += addend + } + } + } + } + + return dp[0][0] + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -643,8 +731,8 @@ class Solution { public: int numDistinct(string s, string t) { int m = s.size(), n = t.size(); - vector dp(n + 1, 0); - vector nextDp(n + 1, 0); + vector dp(n + 1, 0); + vector nextDp(n + 1, 0); dp[n] = nextDp[n] = 1; for (int i = m - 1; i >= 0; i--) { @@ -762,6 +850,38 @@ class Solution { } ``` +```swift +class Solution { + func numDistinct(_ s: String, _ t: String) -> Int { + let m = s.count, n = t.count + var dp = [Int](repeating: 0, count: n + 1) + var nextDp = [Int](repeating: 0, count: n + 1) + dp[n] = 1 + nextDp[n] = 1 + + let sArr = Array(s) + let tArr = Array(t) + + for i in stride(from: m - 1, through: 0, by: -1) { + for j in stride(from: n - 1, through: 0, by: -1) { + nextDp[j] = dp[j] + if sArr[i] == tArr[j] { + let addend = dp[j + 1] + if nextDp[j] > Int.max - addend { + nextDp[j] = 0 + } else { + nextDp[j] += addend + } + } + } + dp = nextDp + } + + return dp[0] + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -827,13 +947,13 @@ class Solution { public: int numDistinct(string s, string t) { int m = s.size(), n = t.size(); - vector dp(n + 1, 0); + vector dp(n + 1, 0); dp[n] = 1; for (int i = m - 1; i >= 0; i--) { int prev = 1; for (int j = n - 1; j >= 0; j--) { - int res = dp[j]; + uint res = dp[j]; if (s[i] == t[j]) { res += prev; } @@ -950,6 +1070,37 @@ class Solution { } ``` +```swift +class Solution { + func numDistinct(_ s: String, _ t: String) -> Int { + let m = s.count, n = t.count + var dp = [Int](repeating: 0, count: n + 1) + dp[n] = 1 + let sArr = Array(s) + let tArr = Array(t) + + for i in stride(from: m - 1, through: 0, by: -1) { + var prev = 1 + for j in stride(from: n - 1, through: 0, by: -1) { + let base = dp[j] + var res = base + if sArr[i] == tArr[j] { + if base > Int.max - prev { + res = 0 + } else { + res += prev + } + } + prev = dp[j] + dp[j] = res + } + } + + return dp[0] + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/counting-bits.md b/articles/counting-bits.md index ac8139aba..66b5db885 100644 --- a/articles/counting-bits.md +++ b/articles/counting-bits.md @@ -120,6 +120,24 @@ class Solution { } ``` +```swift +class Solution { + func countBits(_ n: Int) -> [Int] { + var res = [Int]() + for num in 0...n { + var one = 0 + for i in 0..<32 { + if num & (1 << i) != 0 { + one += 1 + } + } + res.append(one) + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -246,6 +264,22 @@ class Solution { } ``` +```swift +class Solution { + func countBits(_ n: Int) -> [Int] { + var res = [Int](repeating: 0, count: n + 1) + for i in 1..<(n + 1) { + var num = i + while num != 0 { + res[i] += 1 + num &= (num - 1) + } + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -338,6 +372,18 @@ class Solution { } ``` +```swift +class Solution { + func countBits(_ n: Int) -> [Int] { + var res = [Int](repeating: 0, count: n + 1) + for num in 1..<(n + 1) { + res[num] = num.nonzeroBitCount + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -471,6 +517,23 @@ class Solution { } ``` +```swift +class Solution { + func countBits(_ n: Int) -> [Int] { + var dp = [Int](repeating: 0, count: n + 1) + var offset = 1 + + for i in 1..<(n + 1) { + if offset * 2 == i { + offset = i + } + dp[i] = 1 + dp[i - offset] + } + return dp + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -570,6 +633,18 @@ class Solution { } ``` +```swift +class Solution { + func countBits(_ n: Int) -> [Int] { + var dp = [Int](repeating: 0, count: n + 1) + for i in 0..<(n + 1) { + dp[i] = dp[i >> 1] + (i & 1) + } + return dp + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/course-schedule-ii.md b/articles/course-schedule-ii.md index 7980e9e5e..6a3e85924 100644 --- a/articles/course-schedule-ii.md +++ b/articles/course-schedule-ii.md @@ -329,6 +329,51 @@ class Solution { } ``` +```swift +class Solution { + func findOrder(_ numCourses: Int, _ prerequisites: [[Int]]) -> [Int] { + var prereq = [Int: [Int]]() + for c in 0..() + var cycle = Set() + + func dfs(_ crs: Int) -> Bool { + if cycle.contains(crs) { + return false + } + if visit.contains(crs) { + return true + } + + cycle.insert(crs) + for pre in prereq[crs]! { + if !dfs(pre) { + return false + } + } + cycle.remove(crs) + visit.insert(crs) + output.append(crs) + return true + } + + for c in 0.. [Int] { + var indegree = Array(repeating: 0, count: numCourses) + var adj = Array(repeating: [Int](), count: numCourses) + + for pair in prerequisites { + let src = pair[0] + let dst = pair[1] + indegree[dst] += 1 + adj[src].append(dst) + } + + var queue = Deque() + for n in 0.. [Int] { + var adj = Array(repeating: [Int](), count: numCourses) + var indegree = Array(repeating: 0, count: numCourses) + + for pair in prerequisites { + let nxt = pair[0] + let pre = pair[1] + indegree[nxt] += 1 + adj[pre].append(nxt) + } + + var output = [Int]() + + func dfs(_ node: Int) { + output.append(node) + indegree[node] -= 1 + for nei in adj[node] { + indegree[nei] -= 1 + if indegree[nei] == 0 { + dfs(nei) + } + } + } + + for i in 0.. Bool { + // Map each course to its prerequisites + var preMap = [Int: [Int]]() + for i in 0..() + + func dfs(_ crs: Int) -> Bool { + if visiting.contains(crs) { + // Cycle detected + return false + } + if preMap[crs]!.isEmpty { + return true + } + + visiting.insert(crs) + for pre in preMap[crs]! { + if !dfs(pre) { + return false + } + } + visiting.remove(crs) + preMap[crs] = [] + return true + } + + for c in 0.. Bool { + var indegree = Array(repeating: 0, count: numCourses) + var adj = Array(repeating: [Int](), count: numCourses) + + for pair in prerequisites { + let src = pair[0] + let dst = pair[1] + indegree[dst] += 1 + adj[src].append(dst) + } + + var queue = Deque() + for n in 0.. [Int] { + let n = temperatures.count + var res = [Int]() + + for i in 0.. temperatures[i] { + break + } + j += 1 + count += 1 + } + count = (j == n) ? 0 : count + res.append(count) + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity * Time complexity: $O(n ^ 2)$ -* Space complexity: $O(1)$ +* Space complexity: + * $O(1)$ extra space. + * $O(n)$ space for the output array. --- @@ -323,6 +349,24 @@ class Solution { } ``` +```swift +class Solution { + func dailyTemperatures(_ temperatures: [Int]) -> [Int] { + var res = [Int](repeating: 0, count: temperatures.count) + var stack = [(Int, Int)]() // Pair: (temperature, index) + + for (i, t) in temperatures.enumerated() { + while !stack.isEmpty && t > stack.last!.0 { + let (stackT, stackInd) = stack.removeLast() + res[stackInd] = i - stackInd + } + stack.append((t, i)) + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -508,9 +552,36 @@ class Solution { } ``` +```swift +class Solution { + func dailyTemperatures(_ temperatures: [Int]) -> [Int] { + let n = temperatures.count + var res = [Int](repeating: 0, count: n) + + for i in stride(from: n - 2, through: 0, by: -1) { + var j = i + 1 + while j < n && temperatures[j] <= temperatures[i] { + if res[j] == 0 { + j = n + break + } + j += res[j] + } + + if j < n { + res[i] = j - i + } + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity * Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +* Space complexity: + * $O(1)$ extra space. + * $O(n)$ space for the output array. \ No newline at end of file diff --git a/articles/decode-ways.md b/articles/decode-ways.md index bfda19321..c735d1d3f 100644 --- a/articles/decode-ways.md +++ b/articles/decode-ways.md @@ -163,6 +163,34 @@ class Solution { } ``` +```swift +class Solution { + func numDecodings(_ s: String) -> Int { + let chars = Array(s) + + func dfs(_ i: Int) -> Int { + if i == chars.count { + return 1 + } + if chars[i] == "0" { + return 0 + } + + var res = dfs(i + 1) + if i < chars.count - 1 { + if chars[i] == "1" || (chars[i] == "2" && chars[i + 1] < "7") { + res += dfs(i + 2) + } + } + + return res + } + + return dfs(0) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -375,6 +403,35 @@ class Solution { } ``` +```swift +class Solution { + func numDecodings(_ s: String) -> Int { + let chars = Array(s) + var dp = [Int: Int]() + dp[chars.count] = 1 + + func dfs(_ i: Int) -> Int { + if let cached = dp[i] { + return cached + } + if chars[i] == "0" { + return 0 + } + + var res = dfs(i + 1) + if i + 1 < chars.count, + chars[i] == "1" || (chars[i] == "2" && "0123456".contains(chars[i + 1])) { + res += dfs(i + 2) + } + dp[i] = res + return res + } + + return dfs(0) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -533,6 +590,30 @@ class Solution { } ``` +```swift +class Solution { + func numDecodings(_ s: String) -> Int { + let chars = Array(s) + var dp = [Int: Int]() + dp[chars.count] = 1 + + for i in stride(from: chars.count - 1, through: 0, by: -1) { + if chars[i] == "0" { + dp[i] = 0 + } else { + dp[i] = dp[i + 1] ?? 0 + } + + if i + 1 < chars.count, + chars[i] == "1" || (chars[i] == "2" && "0123456".contains(chars[i + 1])) { + dp[i]! += dp[i + 2] ?? 0 + } + } + return dp[0] ?? 0 + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -711,6 +792,30 @@ class Solution { } ``` +```swift +class Solution { + func numDecodings(_ s: String) -> Int { + let chars = Array(s) + var dp = 0, dp1 = 1, dp2 = 0 + + for i in stride(from: chars.count - 1, through: 0, by: -1) { + if chars[i] == "0" { + dp = 0 + } else { + dp = dp1 + } + + if i + 1 < chars.count, + chars[i] == "1" || (chars[i] == "2" && "0123456".contains(chars[i + 1])) { + dp += dp2 + } + (dp, dp1, dp2) = (0, dp, dp1) + } + return dp1 + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/depth-of-binary-tree.md b/articles/depth-of-binary-tree.md index efd76b64d..88a35751d 100644 --- a/articles/depth-of-binary-tree.md +++ b/articles/depth-of-binary-tree.md @@ -171,6 +171,30 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func maxDepth(_ root: TreeNode?) -> Int { + guard let root = root else { return 0 } + return 1 + max(maxDepth(root.left), maxDepth(root.right)) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -440,6 +464,41 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func maxDepth(_ root: TreeNode?) -> Int { + var stack: [(TreeNode?, Int)] = [(root, 1)] + var res = 0 + + while !stack.isEmpty { + let (node, depth) = stack.removeLast() + + if let node = node { + res = max(res, depth) + stack.append((node.left, depth + 1)) + stack.append((node.right, depth + 1)) + } + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -723,6 +782,47 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func maxDepth(_ root: TreeNode?) -> Int { + var queue = Deque() + if let root = root { + queue.append(root) + } + + var level = 0 + while !queue.isEmpty { + for _ in 0..] + private var tweetMap: [Int: [(Int, Int)]] + + init() { + self.time = 0 + self.followMap = [:] + self.tweetMap = [:] + } + + func postTweet(_ userId: Int, _ tweetId: Int) { + if tweetMap[userId] == nil { + tweetMap[userId] = [] + } + tweetMap[userId]!.append((time, tweetId)) + time += 1 + } + + func getNewsFeed(_ userId: Int) -> [Int] { + var feed = tweetMap[userId] ?? [] + if let followees = followMap[userId] { + for followeeId in followees { + if let tweets = tweetMap[followeeId] { + feed.append(contentsOf: tweets) + } + } + } + feed.sort { $0.0 > $1.0 } + return feed.prefix(10).map { $0.1 } + } + + func follow(_ followerId: Int, _ followeeId: Int) { + if followerId != followeeId { + followMap[followerId, default: Set()].insert(followeeId) + } + } + + func unfollow(_ followerId: Int, _ followeeId: Int) { + followMap[followerId]?.remove(followeeId) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -769,6 +814,84 @@ class Twitter { } ``` +```swift +class Twitter { + private var count: Int + private var tweetMap: [Int: [(Int, Int)]] // userId -> list of (count, tweetId) + private var followMap: [Int: Set] // userId -> set of followeeId + + init() { + self.count = 0 + self.tweetMap = [:] + self.followMap = [:] + } + + func postTweet(_ userId: Int, _ tweetId: Int) { + tweetMap[userId, default: []].append((count, tweetId)) + count -= 1 + } + + func getNewsFeed(_ userId: Int) -> [Int] { + var res = [Int]() + var minHeap = Heap() + + followMap[userId, default: Set()].insert(userId) + if let followees = followMap[userId] { + for followee in followees { + if let tweets = tweetMap[followee], !tweets.isEmpty { + let index = tweets.count - 1 + let (cnt, tweetId) = tweets[index] + minHeap.insert( + Item( + count: cnt, tweetId: tweetId, + followeeId: followee, index: index - 1 + ) + ) + } + } + } + + while !minHeap.isEmpty && res.count < 10 { + let entry = minHeap.popMin()! + res.append(entry.tweetId) + if entry.index >= 0, let tweets = tweetMap[entry.followeeId] { + let (cnt, tweetId) = tweets[entry.index] + minHeap.insert( + Item( + count: cnt, tweetId: tweetId, + followeeId: entry.followeeId, index: entry.index - 1 + ) + ) + } + } + return res + } + + func follow(_ followerId: Int, _ followeeId: Int) { + followMap[followerId, default: Set()].insert(followeeId) + } + + func unfollow(_ followerId: Int, _ followeeId: Int) { + followMap[followerId]?.remove(followeeId) + } +} + +struct Item: Comparable { + let count: Int + let tweetId: Int + let followeeId: Int + let index: Int + + static func < (lhs: Item, rhs: Item) -> Bool { + return lhs.count < rhs.count + } + + static func == (lhs: Item, rhs: Item) -> Bool { + return lhs.count == rhs.count + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -1425,6 +1548,112 @@ class Twitter { } ``` +```swift +struct Item: Comparable { + let count: Int + let tweetId: Int + let followeeId: Int + let index: Int + + static func < (lhs: Item, rhs: Item) -> Bool { + return lhs.count < rhs.count + } + + static func == (lhs: Item, rhs: Item) -> Bool { + return lhs.count == rhs.count && + lhs.tweetId == rhs.tweetId && + lhs.followeeId == rhs.followeeId && + lhs.index == rhs.index + } +} + +class Twitter { + private var count: Int + private var tweetMap: [Int: [(Int, Int)]] // userId -> list of (count, tweetId) + private var followMap: [Int: Set] // userId -> set of followeeId + + init() { + self.count = 0 + self.tweetMap = [:] + self.followMap = [:] + } + + func postTweet(_ userId: Int, _ tweetId: Int) { + tweetMap[userId, default: []].append((count, tweetId)) + if tweetMap[userId]!.count > 10 { + tweetMap[userId]!.removeFirst() + } + count -= 1 + } + + func getNewsFeed(_ userId: Int) -> [Int] { + var res = [Int]() + var minHeap = Heap() + followMap[userId, default: Set()].insert(userId) + + if followMap[userId]!.count >= 10 { + var maxHeap = Heap() + for followeeId in followMap[userId]! { + if let tweets = tweetMap[followeeId], !tweets.isEmpty { + let index = tweets.count - 1 + let (cnt, tweetId) = tweets[index] + maxHeap.insert( + Item( + count: cnt, tweetId: tweetId, + followeeId: followeeId, index: index - 1 + ) + ) + if maxHeap.count > 10 { + maxHeap.removeMax() + } + } + } + while !maxHeap.isEmpty { + let item = maxHeap.popMax()! + minHeap.insert(item) + } + } else { + for followeeId in followMap[userId]! { + if let tweets = tweetMap[followeeId], !tweets.isEmpty { + let index = tweets.count - 1 + let (cnt, tweetId) = tweets[index] + minHeap.insert( + Item( + count: cnt, tweetId: tweetId, + followeeId: followeeId, index: index - 1 + ) + ) + } + } + } + + while !minHeap.isEmpty && res.count < 10 { + let item = minHeap.popMin()! + res.append(item.tweetId) + if item.index >= 0, let tweets = tweetMap[item.followeeId] { + let (cnt, tweetId) = tweets[item.index] + minHeap.insert( + Item( + count: cnt, tweetId: tweetId, + followeeId: item.followeeId, index: item.index - 1 + ) + ) + } + } + + return res + } + + func follow(_ followerId: Int, _ followeeId: Int) { + followMap[followerId, default: Set()].insert(followeeId) + } + + func unfollow(_ followerId: Int, _ followeeId: Int) { + followMap[followerId]?.remove(followeeId) + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/design-word-search-data-structure.md b/articles/design-word-search-data-structure.md index 501e42785..033096234 100644 --- a/articles/design-word-search-data-structure.md +++ b/articles/design-word-search-data-structure.md @@ -222,6 +222,42 @@ class WordDictionary { } ``` +```swift +class WordDictionary { + private var store: [String] + + init() { + self.store = [] + } + + func addWord(_ word: String) { + store.append(word) + } + + func search(_ word: String) -> Bool { + for w in store { + if w.count != word.count { + continue + } + var i = 0 + let wArray = Array(w) + let wordArray = Array(word) + while i < wArray.count { + if wArray[i] == wordArray[i] || wordArray[i] == "." { + i += 1 + } else { + break + } + } + if i == wArray.count { + return true + } + } + return false + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -627,6 +663,64 @@ class WordDictionary { } ``` +```swift +class TrieNode { + var children: [Character: TrieNode] + var word: Bool + + init() { + self.children = [:] + self.word = false + } +} + +class WordDictionary { + private let root: TrieNode + + init() { + self.root = TrieNode() + } + + func addWord(_ word: String) { + var cur = root + for c in word { + if cur.children[c] == nil { + cur.children[c] = TrieNode() + } + cur = cur.children[c]! + } + cur.word = true + } + + func search(_ word: String) -> Bool { + func dfs(_ j: Int, _ root: TrieNode) -> Bool { + var cur = root + let wordArray = Array(word) + + for i in j.. Bool { + for i in 0.. Bool { + var nums = nums.sorted() + for i in 1.. Bool { + var seen = Set() + for num in nums { + if seen.contains(num) { + return true + } + seen.insert(num) + } + return false + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -406,6 +450,14 @@ class Solution { } ``` +```swift +class Solution { + func hasDuplicate(_ nums: [Int]) -> Bool { + return Set(nums).count < nums.count + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/eating-bananas.md b/articles/eating-bananas.md index bf00f6c04..4acd82fb0 100644 --- a/articles/eating-bananas.md +++ b/articles/eating-bananas.md @@ -137,6 +137,27 @@ class Solution { } ``` +```swift +class Solution { + func minEatingSpeed(_ piles: [Int], _ h: Int) -> Int { + var speed = 1 + + while true { + var totalTime = 0 + for pile in piles { + totalTime += Int(ceil(Double(pile) / Double(speed))) + } + + if totalTime <= h { + return speed + } + speed += 1 + } + return speed + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -338,6 +359,32 @@ class Solution { } ``` +```swift +class Solution { + func minEatingSpeed(_ piles: [Int], _ h: Int) -> Int { + var l = 1, r = piles.max()! + var res = r + + while l <= r { + let k = (l + r) / 2 + + var totalTime = 0 + for p in piles { + totalTime += Int(ceil(Double(p) / Double(k))) + } + + if totalTime <= h { + res = k + r = k - 1 + } else { + l = k + 1 + } + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/edit-distance.md b/articles/edit-distance.md index a116df5c7..7c4b6bfeb 100644 --- a/articles/edit-distance.md +++ b/articles/edit-distance.md @@ -169,6 +169,27 @@ class Solution { } ``` +```swift +class Solution { + func minDistance(_ word1: String, _ word2: String) -> Int { + let m = word1.count, n = word2.count + let word1Array = Array(word1), word2Array = Array(word2) + + func dfs(_ i: Int, _ j: Int) -> Int { + if i == m { return n - j } + if j == n { return m - i } + if word1Array[i] == word2Array[j] { + return dfs(i + 1, j + 1) + } + let res = min(dfs(i + 1, j), dfs(i, j + 1)) + return min(res, dfs(i + 1, j + 1)) + 1 + } + + return dfs(0, 0) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -403,6 +424,32 @@ class Solution { } ``` +```swift +class Solution { + func minDistance(_ word1: String, _ word2: String) -> Int { + let m = word1.count, n = word2.count + let word1Array = Array(word1), word2Array = Array(word2) + var dp = [[Int?]](repeating: [Int?](repeating: nil, count: n + 1), count: m + 1) + + func dfs(_ i: Int, _ j: Int) -> Int { + if i == m { return n - j } + if j == n { return m - i } + if let val = dp[i][j] { return val } + + if word1Array[i] == word2Array[j] { + dp[i][j] = dfs(i + 1, j + 1) + } else { + let res = min(dfs(i + 1, j), dfs(i, j + 1), dfs(i + 1, j + 1)) + 1 + dp[i][j] = res + } + return dp[i][j]! + } + + return dfs(0, 0) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -624,6 +671,34 @@ class Solution { } ``` +```swift +class Solution { + func minDistance(_ word1: String, _ word2: String) -> Int { + let m = word1.count, n = word2.count + let word1Array = Array(word1), word2Array = Array(word2) + var dp = [[Int]](repeating: [Int](repeating: Int.max, count: n + 1), count: m + 1) + + for j in 0...n { + dp[m][j] = n - j + } + for i in 0...m { + dp[i][n] = m - i + } + + for i in stride(from: m - 1, through: 0, by: -1) { + for j in stride(from: n - 1, through: 0, by: -1) { + if word1Array[i] == word2Array[j] { + dp[i][j] = dp[i + 1][j + 1] + } else { + dp[i][j] = 1 + min(dp[i + 1][j], dp[i][j + 1], dp[i + 1][j + 1]) + } + } + } + return dp[0][0] + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -890,6 +965,41 @@ class Solution { } ``` +```swift +class Solution { + func minDistance(_ word1: String, _ word2: String) -> Int { + var m = word1.count, n = word2.count + var word1Array = Array(word1), word2Array = Array(word2) + + if m < n { + swap(&m, &n) + swap(&word1Array, &word2Array) + } + + var dp = [Int](repeating: 0, count: n + 1) + var nextDp = [Int](repeating: 0, count: n + 1) + + for j in 0...n { + dp[j] = n - j + } + + for i in stride(from: m - 1, through: 0, by: -1) { + nextDp[n] = m - i + for j in stride(from: n - 1, through: 0, by: -1) { + if word1Array[i] == word2Array[j] { + nextDp[j] = dp[j + 1] + } else { + nextDp[j] = 1 + min(dp[j], nextDp[j + 1], dp[j + 1]) + } + } + dp = nextDp + } + + return dp[0] + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -1134,6 +1244,37 @@ class Solution { } ``` +```swift +class Solution { + func minDistance(_ word1: String, _ word2: String) -> Int { + var m = word1.count, n = word2.count + var word1Array = Array(word1), word2Array = Array(word2) + + if m < n { + swap(&m, &n) + swap(&word1Array, &word2Array) + } + + var dp = (0...n).map { n - $0 } + + for i in stride(from: m - 1, through: 0, by: -1) { + var nextDp = dp[n] + dp[n] = m - i + for j in stride(from: n - 1, through: 0, by: -1) { + let temp = dp[j] + if word1Array[i] == word2Array[j] { + dp[j] = nextDp + } else { + dp[j] = 1 + min(dp[j], dp[j + 1], nextDp) + } + nextDp = temp + } + } + return dp[0] + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/evaluate-reverse-polish-notation.md b/articles/evaluate-reverse-polish-notation.md index 9c3520b02..3ad96eff8 100644 --- a/articles/evaluate-reverse-polish-notation.md +++ b/articles/evaluate-reverse-polish-notation.md @@ -216,6 +216,39 @@ class Solution { } ``` +```swift +class Solution { + func evalRPN(_ tokens: [String]) -> Int { + var tokens = tokens + + while tokens.count > 1 { + for i in 0.. Int { + var head: DoublyLinkedList? = DoublyLinkedList(val: tokens[0]) + var curr = head + + for i in 1.. Int { + var tokens = tokens + + func dfs() -> Int { + let token = tokens.removeLast() + if let num = Int(token) { + return num + } + + let right = dfs() + let left = dfs() + + switch token { + case "+": return left + right + case "-": return left - right + case "*": return left * right + case "/": return left / right + default: return 0 + } + } + + return dfs() + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -1042,6 +1161,34 @@ class Solution { } ``` +```swift +class Solution { + func evalRPN(_ tokens: [String]) -> Int { + var stack = [Int]() + + for c in tokens { + switch c { + case "+": + stack.append(stack.removeLast() + stack.removeLast()) + case "-": + let a = stack.removeLast() + let b = stack.removeLast() + stack.append(b - a) + case "*": + stack.append(stack.removeLast() * stack.removeLast()) + case "/": + let a = stack.removeLast() + let b = stack.removeLast() + stack.append(b / a) + default: + stack.append(Int(c)!) + } + } + return stack[0] + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/find-duplicate-integer.md b/articles/find-duplicate-integer.md index 46542d9b6..ef3317436 100644 --- a/articles/find-duplicate-integer.md +++ b/articles/find-duplicate-integer.md @@ -99,6 +99,20 @@ class Solution { } ``` +```swift +class Solution { + func findDuplicate(_ nums: [Int]) -> Int { + var nums = nums.sorted() + for i in 0.. Int { + var seen = Set() + for num in nums { + if seen.contains(num) { + return num + } + seen.insert(num) + } + return -1 + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -333,6 +362,21 @@ class Solution { } ``` +```swift +class Solution { + func findDuplicate(_ nums: [Int]) -> Int { + var seen = [Int](repeating: 0, count: nums.count) + for num in nums { + if seen[num - 1] == 1 { + return num + } + seen[num - 1] = 1 + } + return -1 + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -457,6 +501,22 @@ class Solution { } ``` +```swift +class Solution { + func findDuplicate(_ nums: [Int]) -> Int { + var nums = nums + for num in nums { + let idx = abs(num) - 1 + if nums[idx] < 0 { + return abs(num) + } + nums[idx] *= -1 + } + return -1 + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -656,6 +716,27 @@ class Solution { } ``` +```swift +class Solution { + func findDuplicate(_ nums: [Int]) -> Int { + let n = nums.count + var low = 1, high = n - 1 + + while low < high { + let mid = low + (high - low) / 2 + let lessOrEqual = nums.filter { $0 <= mid }.count + + if lessOrEqual <= mid { + low = mid + 1 + } else { + high = mid + } + } + return low + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -866,6 +947,37 @@ class Solution { } ``` +```swift +class Solution { + func findDuplicate(_ nums: [Int]) -> Int { + let n = nums.count + var res = 0 + + for b in 0..<32 { + var x = 0, y = 0 + let mask = 1 << b + + for num in nums { + if num & mask != 0 { + x += 1 + } + } + + for num in 1.. y { + res |= mask + } + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -1052,6 +1164,31 @@ class Solution { } ``` +```swift +class Solution { + func findDuplicate(_ nums: [Int]) -> Int { + var slow = 0, fast = 0 + + while true { + slow = nums[slow] + fast = nums[nums[fast]] + if slow == fast { + break + } + } + + var slow2 = 0 + while true { + slow = nums[slow] + slow2 = nums[slow2] + if slow == slow2 { + return slow + } + } + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/find-median-in-a-data-stream.md b/articles/find-median-in-a-data-stream.md index ab246b370..ad27aa749 100644 --- a/articles/find-median-in-a-data-stream.md +++ b/articles/find-median-in-a-data-stream.md @@ -162,6 +162,30 @@ class MedianFinder() { } ``` +```swift +class MedianFinder { + private var data: [Int] + + init() { + self.data = [] + } + + func addNum(_ num: Int) { + data.append(num) + } + + func findMedian() -> Double { + data.sort() + let n = data.count + if n % 2 == 1 { + return Double(data[n / 2]) + } else { + return (Double(data[n / 2]) + Double(data[n / 2 - 1])) / 2.0 + } + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -447,6 +471,47 @@ class MedianFinder() { } ``` +```swift +class MedianFinder { + // two heaps, large, small, minheap, maxheap + // heaps should be equal size + private var small: Heap + private var large: Heap + + init() { + self.small = Heap() + self.large = Heap() + } + + func addNum(_ num: Int) { + if let top = large.min, num > top { + large.insert(num) + } else { + small.insert(num) + } + if small.count > large.count + 1 { + if let val = small.popMax() { + large.insert(val) + } + } + if large.count > small.count + 1 { + if let val = large.popMin() { + small.insert(val) + } + } + } + + func findMedian() -> Double { + if small.count > large.count { + return Double(small.max!) + } else if large.count > small.count { + return Double(large.min!) + } + return (Double(small.max!) + Double(large.min!)) / 2.0 + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/find-minimum-in-rotated-sorted-array.md b/articles/find-minimum-in-rotated-sorted-array.md index 3c4c59be9..9443959d2 100644 --- a/articles/find-minimum-in-rotated-sorted-array.md +++ b/articles/find-minimum-in-rotated-sorted-array.md @@ -65,6 +65,14 @@ class Solution { } ``` +```swift +class Solution { + func findMin(_ nums: [Int]) -> Int { + return nums.min()! + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -261,6 +269,32 @@ class Solution { } ``` +```swift +class Solution { + func findMin(_ nums: [Int]) -> Int { + var res = nums[0] + var l = 0, r = nums.count - 1 + + while l <= r { + if nums[l] < nums[r] { + res = min(res, nums[l]) + break + } + + let m = (l + r) / 2 + res = min(res, nums[m]) + + if nums[m] >= nums[l] { + l = m + 1 + } else { + r = m - 1 + } + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -396,6 +430,23 @@ class Solution { } ``` +```swift +class Solution { + func findMin(_ nums: [Int]) -> Int { + var l = 0, r = nums.count - 1 + while l < r { + let m = l + (r - l) / 2 + if nums[m] < nums[r] { + r = m + } else { + l = m + 1 + } + } + return nums[l] + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/find-target-in-rotated-sorted-array.md b/articles/find-target-in-rotated-sorted-array.md index 2e6dd37e5..b406838bb 100644 --- a/articles/find-target-in-rotated-sorted-array.md +++ b/articles/find-target-in-rotated-sorted-array.md @@ -93,6 +93,19 @@ class Solution { } ``` +```swift +class Solution { + func search(_ nums: [Int], _ target: Int) -> Int { + for i in 0.. Int { + var l = 0, r = nums.count - 1 + + while l < r { + let m = (l + r) / 2 + if nums[m] > nums[r] { + l = m + 1 + } else { + r = m + } + } + + let pivot = l + + func binarySearch(_ left: Int, _ right: Int) -> Int { + var l = left, r = right + while l <= r { + let mid = (l + r) / 2 + if nums[mid] == target { + return mid + } else if nums[mid] < target { + l = mid + 1 + } else { + r = mid - 1 + } + } + return -1 + } + + let result = binarySearch(0, pivot - 1) + if result != -1 { + return result + } + + return binarySearch(pivot, nums.count - 1) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -681,6 +735,46 @@ class Solution { } ``` +```swift +class Solution { + func search(_ nums: [Int], _ target: Int) -> Int { + var l = 0, r = nums.count - 1 + + while l < r { + let m = (l + r) / 2 + if nums[m] > nums[r] { + l = m + 1 + } else { + r = m + } + } + + let pivot = l + l = 0 + r = nums.count - 1 + + if target >= nums[pivot] && target <= nums[r] { + l = pivot + } else { + r = pivot - 1 + } + + while l <= r { + let m = (l + r) / 2 + if nums[m] == target { + return m + } else if nums[m] < target { + l = m + 1 + } else { + r = m - 1 + } + } + + return -1 + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -908,6 +1002,36 @@ class Solution { } ``` +```swift +class Solution { + func search(_ nums: [Int], _ target: Int) -> Int { + var l = 0, r = nums.count - 1 + + while l <= r { + let mid = (l + r) / 2 + if target == nums[mid] { + return mid + } + + if nums[l] <= nums[mid] { + if target > nums[mid] || target < nums[l] { + l = mid + 1 + } else { + r = mid - 1 + } + } else { + if target < nums[mid] || target > nums[r] { + r = mid - 1 + } else { + l = mid + 1 + } + } + } + return -1 + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/foreign-dictionary.md b/articles/foreign-dictionary.md index f1353b74a..1bb32e486 100644 --- a/articles/foreign-dictionary.md +++ b/articles/foreign-dictionary.md @@ -405,6 +405,65 @@ class Solution { } ``` +```swift +class Solution { + func foreignDictionary(_ words: [String]) -> String { + var adj = [Character: Set]() + for word in words { + for char in word { + if adj[char] == nil { + adj[char] = Set() + } + } + } + + for i in 0.. w2.count && String(w1.prefix(minLen)) == String(w2.prefix(minLen)) { + return "" + } + for j in 0.. Bool { + if let flag = visited[char] { + return flag + } + visited[char] = true + for neigh in adj[char]! { + if dfs(neigh) { + return true + } + } + visited[char] = false + res.append(char) + return false + } + + for char in adj.keys { + if dfs(char) { + return "" + } + } + + res.reverse() + return String(res) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -823,6 +882,69 @@ class Solution { } ``` +```swift +class Solution { + func foreignDictionary(_ words: [String]) -> String { + var adj = [Character: Set]() + for word in words { + for char in word { + adj[char] = Set() + } + } + + var indegree = [Character: Int]() + for key in adj.keys { + indegree[key] = 0 + } + + for i in 0.. w2.count && String(w1.prefix(minLen)) == String(w2.prefix(minLen)) { + return "" + } + let w1Arr = Array(w1) + let w2Arr = Array(w2) + for j in 0..() + for (c, deg) in indegree { + if deg == 0 { + q.append(c) + } + } + + var res = [Character]() + while !q.isEmpty { + let char = q.removeFirst() + res.append(char) + for neighbor in adj[char]! { + indegree[neighbor]! -= 1 + if indegree[neighbor]! == 0 { + q.append(neighbor) + } + } + } + + if res.count != indegree.count { + return "" + } + + return String(res) + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/gas-station.md b/articles/gas-station.md index cedbf31c2..9e779b1d8 100644 --- a/articles/gas-station.md +++ b/articles/gas-station.md @@ -11,6 +11,7 @@ class Solution: tank = gas[i] - cost[i] if tank < 0: continue + j = (i + 1) % n while j != i: tank += gas[j] @@ -19,6 +20,7 @@ class Solution: break j += 1 j %= n + if j == i: return i return -1 @@ -32,12 +34,14 @@ public class Solution { for (int i = 0; i < n; i++) { int tank = gas[i] - cost[i]; if (tank < 0) continue; + int j = (i + 1) % n; while (j != i) { tank += gas[j] - cost[j]; if (tank < 0) break; j = (j + 1) % n; } + if (j == i) return i; } return -1; @@ -54,12 +58,14 @@ public: for (int i = 0; i < n; i++) { int tank = gas[i] - cost[i]; if (tank < 0) continue; + int j = (i + 1) % n; while (j != i) { tank += gas[j] - cost[j]; if (tank < 0) break; j = (j + 1) % n; } + if (j == i) return i; } return -1; @@ -80,12 +86,14 @@ class Solution { for (let i = 0; i < n; i++) { let tank = gas[i] - cost[i]; if (tank < 0) continue; + let j = (i + 1) % n; while (j !== i) { tank += gas[j] - cost[j]; if (tank < 0) break; j = (j + 1) % n; } + if (j === i) return i; } return -1; @@ -101,14 +109,17 @@ public class Solution { for (int i = 0; i < n; i++) { int tank = gas[i] - cost[i]; if (tank < 0) continue; + int j = (i + 1) % n; while (j != i) { tank += gas[j] - cost[j]; if (tank < 0) break; j = (j + 1) % n; } + if (j == i) return i; } + return -1; } } @@ -117,11 +128,13 @@ public class Solution { ```go func canCompleteCircuit(gas []int, cost []int) int { n := len(gas) + for i := 0; i < n; i++ { tank := gas[i] - cost[i] if tank < 0 { continue } + j := (i + 1) % n for j != i { tank += gas[j] @@ -131,10 +144,12 @@ func canCompleteCircuit(gas []int, cost []int) int { } j = (j + 1) % n } + if j == i { return i } } + return -1 } ``` @@ -166,6 +181,38 @@ class Solution { } ``` +```swift +class Solution { + func canCompleteCircuit(_ gas: [Int], _ cost: [Int]) -> Int { + let n = gas.count + + for i in 0.. Int { + let n = gas.count + var start = n - 1 + var end = 0 + var tank = gas[start] - cost[start] + + while start > end { + if tank < 0 { + start -= 1 + tank += gas[start] - cost[start] + } else { + tank += gas[end] - cost[end] + end += 1 + } + } + + return tank >= 0 ? start : -1 + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -510,6 +580,29 @@ class Solution { } ``` +```swift +class Solution { + func canCompleteCircuit(_ gas: [Int], _ cost: [Int]) -> Int { + if gas.reduce(0, +) < cost.reduce(0, +) { + return -1 + } + + var total = 0 + var res = 0 + for i in 0.. [String] { + var res = [String]() + + func isValid(_ s: String) -> Bool { + var open = 0 + for c in s { + open += (c == "(") ? 1 : -1 + if open < 0 { + return false + } + } + return open == 0 + } + + func dfs(_ s: String) { + if s.count == n * 2 { + if isValid(s) { + res.append(s) + } + return + } + dfs(s + "(") + dfs(s + ")") + } + + dfs("") + return res + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -442,6 +475,37 @@ class Solution { } ``` +```swift +class Solution { + func generateParenthesis(_ n: Int) -> [String] { + var stack = [Character]() + var res = [String]() + + func backtrack(_ openN: Int, _ closedN: Int) { + if openN == n && closedN == n { + res.append(String(stack)) + return + } + + if openN < n { + stack.append("(") + backtrack(openN + 1, closedN) + stack.removeLast() + } + + if closedN < openN { + stack.append(")") + backtrack(openN, closedN + 1) + stack.removeLast() + } + } + + backtrack(0, 0) + return res + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -606,6 +670,27 @@ class Solution { } ``` +```swift +class Solution { + func generateParenthesis(_ n: Int) -> [String] { + var res = [[String]](repeating: [], count: n + 1) + res[0] = [""] + + for k in 0...n { + for i in 0.. count = new HashMap<>(); for (int num : hand) { count.put(num, count.getOrDefault(num, 0) + 1); } + Arrays.sort(hand); for (int num : hand) { if (count.get(num) > 0) { @@ -45,8 +48,10 @@ class Solution { public: bool isNStraightHand(vector& hand, int groupSize) { if (hand.size() % groupSize != 0) return false; + unordered_map count; for (int num : hand) count[num]++; + sort(hand.begin(), hand.end()); for (int num : hand) { if (count[num] > 0) { @@ -72,10 +77,12 @@ class Solution { if (hand.length % groupSize !== 0) { return false; } + const count = {}; for (const num of hand) { count[num] = (count[num] || 0) + 1; } + hand.sort((a, b) => a - b); for (const num of hand) { if (count[num] > 0) { @@ -94,10 +101,12 @@ class Solution { public class Solution { public bool IsNStraightHand(int[] hand, int groupSize) { if (hand.Length % groupSize != 0) return false; + var count = new Dictionary(); foreach (var num in hand) { count[num] = count.GetValueOrDefault(num, 0) + 1; } + Array.Sort(hand); foreach (var num in hand) { if (count[num] > 0) { @@ -164,6 +173,36 @@ class Solution { } ``` +```swift +class Solution { + func isNStraightHand(_ hand: [Int], _ groupSize: Int) -> Bool { + if hand.count % groupSize != 0 { + return false + } + + var count = [Int: Int]() + for num in hand { + count[num, default: 0] += 1 + } + + let sortedHand = hand.sorted() + for num in sortedHand { + if let freq = count[num], freq > 0 { + for i in num..<(num + groupSize) { + if let f = count[i], f > 0 { + count[i] = f - 1 + } else { + return false + } + } + } + } + + return true + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -410,6 +449,40 @@ class Solution { } ``` +```swift +class Solution { + func isNStraightHand(_ hand: [Int], _ groupSize: Int) -> Bool { + if hand.count % groupSize != 0 { + return false + } + + var count = [Int: Int]() + for n in hand { + count[n, default: 0] += 1 + } + + var minH = Heap(Array(count.keys)) + + while !minH.isEmpty { + guard let first = minH.min else { return false } + + for i in first..<(first + groupSize) { + guard let freq = count[i] else { return false } + count[i] = freq - 1 + if count[i] == 0 { + if i != minH.min { + return false + } + minH.removeMin() + } + } + } + + return true + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -655,6 +728,40 @@ class Solution { } ``` +```swift +class Solution { + func isNStraightHand(_ hand: [Int], _ groupSize: Int) -> Bool { + if hand.count % groupSize != 0 { + return false + } + + var count = [Int: Int]() + for num in hand { + count[num, default: 0] += 1 + } + + var queue = Deque() + var lastNum = -1 + var openGroups = 0 + + for (num, numCount) in count.sorted(by: { $0.key < $1.key }) { + if (openGroups > 0 && num > lastNum + 1) || openGroups > numCount { + return false + } + + queue.append(numCount - openGroups) + lastNum = num + openGroups = numCount + + if queue.count == groupSize { + openGroups -= queue.removeFirst() + } + } + return openGroups == 0 + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -673,6 +780,7 @@ class Solution: def isNStraightHand(self, hand: List[int], groupSize: int) -> bool: if len(hand) % groupSize != 0: return False + count = Counter(hand) for num in hand: start = num @@ -692,6 +800,7 @@ class Solution: public class Solution { public boolean isNStraightHand(int[] hand, int groupSize) { if (hand.length % groupSize != 0) return false; + Map count = new HashMap<>(); for (int num : hand) { count.put(num, count.getOrDefault(num, 0) + 1); @@ -720,6 +829,7 @@ class Solution { public: bool isNStraightHand(vector& hand, int groupSize) { if (hand.size() % groupSize != 0) return false; + unordered_map count; for (int num : hand) count[num]++; @@ -750,6 +860,7 @@ class Solution { */ isNStraightHand(hand, groupSize) { if (hand.length % groupSize !== 0) return false; + const count = new Map(); hand.forEach(num => count.set(num, (count.get(num) || 0) + 1)); @@ -775,6 +886,7 @@ class Solution { public class Solution { public bool IsNStraightHand(int[] hand, int groupSize) { if (hand.Length % groupSize != 0) return false; + Dictionary count = new Dictionary(); foreach (int num in hand) { if (!count.ContainsKey(num)) count[num] = 0; @@ -867,6 +979,41 @@ class Solution { } ``` +```swift +class Solution { + func isNStraightHand(_ hand: [Int], _ groupSize: Int) -> Bool { + if hand.count % groupSize != 0 { + return false + } + + var count = [Int: Int]() + for num in hand { + count[num, default: 0] += 1 + } + + for num in hand { + var start = num + while (count[start - 1] ?? 0) > 0 { + start -= 1 + } + while start <= num { + while (count[start] ?? 0) > 0 { + for i in start..<(start + groupSize) { + if (count[i] ?? 0) == 0 { + return false + } + count[i]! -= 1 + } + } + start += 1 + } + } + + return true + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/house-robber-ii.md b/articles/house-robber-ii.md index 9157646c6..0469d73df 100644 --- a/articles/house-robber-ii.md +++ b/articles/house-robber-ii.md @@ -131,6 +131,25 @@ class Solution { } ``` +```swift +class Solution { + func rob(_ nums: [Int]) -> Int { + if nums.count == 1 { + return nums[0] + } + + func dfs(_ i: Int, _ flag: Bool) -> Int { + if i >= nums.count || (flag && i == nums.count - 1) { + return 0 + } + return max(dfs(i + 1, flag), nums[i] + dfs(i + 2, flag || i == 0)) + } + + return max(dfs(0, true), dfs(1, false)) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -336,6 +355,35 @@ class Solution { } ``` +```swift +class Solution { + func rob(_ nums: [Int]) -> Int { + if nums.count == 1 { + return nums[0] + } + + var memo = Array(repeating: Array(repeating: -1, count: 2), count: nums.count) + + func dfs(_ i: Int, _ flag: Bool) -> Int { + if i >= nums.count || (flag && i == nums.count - 1) { + return 0 + } + if memo[i][flag ? 1 : 0] != -1 { + return memo[i][flag ? 1 : 0] + } + + memo[i][flag ? 1 : 0] = max( + dfs(i + 1, flag), nums[i] + dfs(i + 2, flag || i == 0) + ) + + return memo[i][flag ? 1 : 0] + } + + return max(dfs(0, true), dfs(1, false)) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -553,6 +601,36 @@ class Solution { } ``` +```swift +class Solution { + func rob(_ nums: [Int]) -> Int { + if nums.count == 1 { + return nums[0] + } + return max(helper(Array(nums[1...])), helper(Array(nums[..<(nums.count - 1)]))) + } + + func helper(_ nums: [Int]) -> Int { + if nums.isEmpty { + return 0 + } + if nums.count == 1 { + return nums[0] + } + + var dp = [Int](repeating: 0, count: nums.count) + dp[0] = nums[0] + dp[1] = max(nums[0], nums[1]) + + for i in 2.. Int { + if nums.isEmpty { + return 0 + } + if nums.count == 1 { + return nums[0] + } + + let candidate1 = nums[0] + let candidate2 = helper(Array(nums[1.. Int { + var rob1 = 0 + var rob2 = 0 + + for num in nums { + let newRob = max(rob1 + num, rob2) + rob1 = rob2 + rob2 = newRob + } + + return rob2 + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/house-robber.md b/articles/house-robber.md index 6122135cb..22be9ba02 100644 --- a/articles/house-robber.md +++ b/articles/house-robber.md @@ -118,6 +118,21 @@ class Solution { } ``` +```swift +class Solution { + func rob(_ nums: [Int]) -> Int { + func dfs(_ i: Int) -> Int { + if i >= nums.count { + return 0 + } + return max(dfs(i + 1), nums[i] + dfs(i + 2)) + } + + return dfs(0) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -291,6 +306,27 @@ class Solution { } ``` +```swift +class Solution { + func rob(_ nums: [Int]) -> Int { + var memo = Array(repeating: -1, count: nums.count) + + func dfs(_ i: Int) -> Int { + if i >= nums.count { + return 0 + } + if memo[i] != -1 { + return memo[i] + } + memo[i] = max(dfs(i + 1), nums[i] + dfs(i + 2)) + return memo[i] + } + + return dfs(0) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -455,6 +491,29 @@ class Solution { } ``` +```swift +class Solution { + func rob(_ nums: [Int]) -> Int { + if nums.isEmpty { + return 0 + } + if nums.count == 1 { + return nums[0] + } + + var dp = Array(repeating: 0, count: nums.count) + dp[0] = nums[0] + dp[1] = max(nums[0], nums[1]) + + for i in 2.. Int { + var rob1 = 0, rob2 = 0 + + for num in nums { + let temp = max(num + rob1, rob2) + rob1 = rob2 + rob2 = temp + } + + return rob2 + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/implement-prefix-tree.md b/articles/implement-prefix-tree.md index 493258c7b..3e4a303f2 100644 --- a/articles/implement-prefix-tree.md +++ b/articles/implement-prefix-tree.md @@ -363,6 +363,62 @@ class PrefixTree { } ``` +```swift +class TrieNode { + var children: [TrieNode?] + var endOfWord: Bool + + init() { + self.children = Array(repeating: nil, count: 26) + self.endOfWord = false + } +} + +class PrefixTree { + private let root: TrieNode + + init() { + self.root = TrieNode() + } + + func insert(_ word: String) { + var cur = root + for c in word { + let i = Int(c.asciiValue! - Character("a").asciiValue!) + if cur.children[i] == nil { + cur.children[i] = TrieNode() + } + cur = cur.children[i]! + } + cur.endOfWord = true + } + + func search(_ word: String) -> Bool { + var cur = root + for c in word { + let i = Int(c.asciiValue! - Character("a").asciiValue!) + if cur.children[i] == nil { + return false + } + cur = cur.children[i]! + } + return cur.endOfWord + } + + func startsWith(_ prefix: String) -> Bool { + var cur = root + for c in prefix { + let i = Int(c.asciiValue! - Character("a").asciiValue!) + if cur.children[i] == nil { + return false + } + cur = cur.children[i]! + } + return true + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -708,6 +764,59 @@ class PrefixTree { } ``` +```swift +class TrieNode { + var children: [Character: TrieNode] + var endOfWord: Bool + + init() { + self.children = [:] + self.endOfWord = false + } +} + +class PrefixTree { + private let root: TrieNode + + init() { + self.root = TrieNode() + } + + func insert(_ word: String) { + var cur = root + for c in word { + if cur.children[c] == nil { + cur.children[c] = TrieNode() + } + cur = cur.children[c]! + } + cur.endOfWord = true + } + + func search(_ word: String) -> Bool { + var cur = root + for c in word { + if cur.children[c] == nil { + return false + } + cur = cur.children[c]! + } + return cur.endOfWord + } + + func startsWith(_ prefix: String) -> Bool { + var cur = root + for c in prefix { + if cur.children[c] == nil { + return false + } + cur = cur.children[c]! + } + return true + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/insert-new-interval.md b/articles/insert-new-interval.md index 367a09391..13f29a037 100644 --- a/articles/insert-new-interval.md +++ b/articles/insert-new-interval.md @@ -216,6 +216,37 @@ class Solution { } ``` +```swift +class Solution { + func insert(_ intervals: [[Int]], _ newInterval: [Int]) -> [[Int]] { + var intervals = intervals + var newInterval = newInterval + var res: [[Int]] = [] + var i = 0 + let n = intervals.count + + while i < n && intervals[i][1] < newInterval[0] { + res.append(intervals[i]) + i += 1 + } + + while i < n && newInterval[1] >= intervals[i][0] { + newInterval[0] = min(newInterval[0], intervals[i][0]) + newInterval[1] = max(newInterval[1], intervals[i][1]) + i += 1 + } + res.append(newInterval) + + while i < n { + res.append(intervals[i]) + i += 1 + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -512,6 +543,41 @@ class Solution { } ``` +```swift +class Solution { + func insert(_ intervals: [[Int]], _ newInterval: [Int]) -> [[Int]] { + if intervals.isEmpty { + return [newInterval] + } + + var intervals = intervals + let target = newInterval[0] + var left = 0, right = intervals.count - 1 + + while left <= right { + let mid = (left + right) / 2 + if intervals[mid][0] < target { + left = mid + 1 + } else { + right = mid - 1 + } + } + + intervals.insert(newInterval, at: left) + + var res: [[Int]] = [] + for interval in intervals { + if res.isEmpty || res.last![1] < interval[0] { + res.append(interval) + } else { + res[res.count - 1][1] = max(res.last![1], interval[1]) + } + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -707,6 +773,31 @@ class Solution { } ``` +```swift +class Solution { + func insert(_ intervals: [[Int]], _ newInterval: [Int]) -> [[Int]] { + var res = [[Int]]() + var newInterval = newInterval + + for i in 0.. intervals[i][1] { + res.append(intervals[i]) + } else { + newInterval[0] = min(newInterval[0], intervals[i][0]) + newInterval[1] = max(newInterval[1], intervals[i][1]) + } + } + + res.append(newInterval) + return res + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/interleaving-string.md b/articles/interleaving-string.md index c5e0566de..3d124cd01 100644 --- a/articles/interleaving-string.md +++ b/articles/interleaving-string.md @@ -199,6 +199,39 @@ class Solution { } ``` +```swift +class Solution { + func isInterleave(_ s1: String, _ s2: String, _ s3: String) -> Bool { + let n1 = s1.count, n2 = s2.count, n3 = s3.count + if n1 + n2 != n3 { return false } + + let s1 = Array(s1), s2 = Array(s2), s3 = Array(s3) + + func dfs(_ i: Int, _ j: Int, _ k: Int) -> Bool { + if k == n3 { + return i == n1 && j == n2 + } + + if i < n1 && s1[i] == s3[k] { + if dfs(i + 1, j, k + 1) { + return true + } + } + + if j < n2 && s2[j] == s3[k] { + if dfs(i, j + 1, k + 1) { + return true + } + } + + return false + } + + return dfs(0, 0, 0) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -462,6 +495,40 @@ class Solution { } ``` +```swift +class Solution { + func isInterleave(_ s1: String, _ s2: String, _ s3: String) -> Bool { + let m = s1.count, n = s2.count, l = s3.count + if m + n != l { return false } + + let s1 = Array(s1), s2 = Array(s2), s3 = Array(s3) + var dp = Array(repeating: Array(repeating: nil as Bool?, count: n + 1), count: m + 1) + + func dfs(_ i: Int, _ j: Int, _ k: Int) -> Bool { + if k == l { + return i == m && j == n + } + if let cached = dp[i][j] { + return cached + } + + var res = false + if i < m && s1[i] == s3[k] { + res = dfs(i + 1, j, k + 1) + } + if !res && j < n && s2[j] == s3[k] { + res = dfs(i, j + 1, k + 1) + } + + dp[i][j] = res + return res + } + + return dfs(0, 0, 0) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -660,6 +727,31 @@ class Solution { } ``` +```swift +class Solution { + func isInterleave(_ s1: String, _ s2: String, _ s3: String) -> Bool { + let m = s1.count, n = s2.count, l = s3.count + if m + n != l { return false } + + let s1 = Array(s1), s2 = Array(s2), s3 = Array(s3) + var dp = Array(repeating: Array(repeating: false, count: n + 1), count: m + 1) + dp[m][n] = true + + for i in stride(from: m, through: 0, by: -1) { + for j in stride(from: n, through: 0, by: -1) { + if i < m && s1[i] == s3[i + j] && dp[i + 1][j] { + dp[i][j] = true + } + if j < n && s2[j] == s3[i + j] && dp[i][j + 1] { + dp[i][j] = true + } + } + } + return dp[0][0] + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -904,6 +996,38 @@ class Solution { } ``` +```swift +class Solution { + func isInterleave(_ s1: String, _ s2: String, _ s3: String) -> Bool { + var s1 = Array(s1), s2 = Array(s2), s3 = Array(s3) + var m = s1.count, n = s2.count + if m + n != s3.count { return false } + if n < m { + swap(&s1, &s2) + swap(&m, &n) + } + + var dp = Array(repeating: false, count: n + 1) + dp[n] = true + + for i in stride(from: m, through: 0, by: -1) { + var nextDp = Array(repeating: false, count: n + 1) + nextDp[n] = true + for j in stride(from: n, through: 0, by: -1) { + if i < m && s1[i] == s3[i + j] && dp[j] { + nextDp[j] = true + } + if j < n && s2[j] == s3[i + j] && nextDp[j + 1] { + nextDp[j] = true + } + } + dp = nextDp + } + return dp[0] + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -1155,6 +1279,39 @@ class Solution { } ``` +```swift +class Solution { + func isInterleave(_ s1: String, _ s2: String, _ s3: String) -> Bool { + var s1 = Array(s1), s2 = Array(s2), s3 = Array(s3) + var m = s1.count, n = s2.count + if m + n != s3.count { return false } + if n < m { + swap(&s1, &s2) + swap(&m, &n) + } + + var dp = Array(repeating: false, count: n + 1) + dp[n] = true + + for i in stride(from: m, through: 0, by: -1) { + var nextDp = true + for j in stride(from: n - 1, through: 0, by: -1) { + var res = false + if i < m && s1[i] == s3[i + j] && dp[j] { + res = true + } + if j < n && s2[j] == s3[i + j] && nextDp { + res = true + } + dp[j] = res + nextDp = dp[j] + } + } + return dp[0] + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/invert-a-binary-tree.md b/articles/invert-a-binary-tree.md index 2c7622067..33ee15f84 100644 --- a/articles/invert-a-binary-tree.md +++ b/articles/invert-a-binary-tree.md @@ -227,6 +227,44 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func invertTree(_ root: TreeNode?) -> TreeNode? { + guard let root = root else { return nil } + var queue = Deque() + queue.append(root) + + while !queue.isEmpty { + let node = queue.removeFirst() + (node.left, node.right) = (node.right, node.left) + + if let left = node.left { + queue.append(left) + } + if let right = node.right { + queue.append(right) + } + } + return root + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -253,10 +291,10 @@ class Solution: if not root: return None root.left, root.right = root.right, root.left - + self.invertTree(root.left) self.invertTree(root.right) - + return root ``` @@ -277,16 +315,18 @@ class Solution: * } */ -class Solution { +public class Solution { public TreeNode invertTree(TreeNode root) { if (root == null) return null; - - TreeNode node = new TreeNode(root.val); - node.right = invertTree(root.left); - node.left = invertTree(root.right); - - return node; + TreeNode temp = root.left; + root.left = root.right; + root.right = temp; + + invertTree(root.left); + invertTree(root.right); + + return root; } } ``` @@ -307,14 +347,13 @@ class Solution { class Solution { public: TreeNode* invertTree(TreeNode* root) { - if (root == nullptr) return nullptr; + if (!root) return nullptr; - TreeNode* node = new TreeNode(root->val); - - node->right = invertTree(root->left); - node->left = invertTree(root->right); + swap(root->left, root->right); + invertTree(root->left); + invertTree(root->right); - return node; + return root; } }; ``` @@ -337,14 +376,13 @@ class Solution { * @return {TreeNode} */ invertTree(root) { - if (root === null) return null; - - const node = new TreeNode(root.val); + if (!root) return null; - node.right = this.invertTree(root.left); - node.left = this.invertTree(root.right); + [root.left, root.right] = [root.right, root.left]; + this.invertTree(root.left); + this.invertTree(root.right); - return node; + return root; } } ``` @@ -368,12 +406,95 @@ public class Solution { public TreeNode InvertTree(TreeNode root) { if (root == null) return null; - TreeNode node = new TreeNode(root.val); - - node.right = InvertTree(root.left); - node.left = InvertTree(root.right); + TreeNode temp = root.left; + root.left = root.right; + root.right = temp; + + InvertTree(root.left); + InvertTree(root.right); - return node; + return root; + } +} +``` + +```go +/** + * Definition for a binary tree node. + * type TreeNode struct { + * Val int + * Left *TreeNode + * Right *TreeNode + * } + */ + +func invertTree(root *TreeNode) *TreeNode { + if root == nil { + return nil + } + + root.Left, root.Right = root.Right, root.Left + invertTree(root.Left) + invertTree(root.Right) + + return root +} +``` + +```kotlin +/** + * Example: + * var ti = TreeNode(5) + * var v = ti.`val` + * Definition for a binary tree node. + * class TreeNode(var `val`: Int) { + * var left: TreeNode? = null + * var right: TreeNode? = null + * } + */ + +class Solution { + fun invertTree(root: TreeNode?): TreeNode? { + if (root == null) return null + + val temp = root.left + root.left = root.right + root.right = temp + + invertTree(root.left) + invertTree(root.right) + + return root + } +} +``` + +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func invertTree(_ root: TreeNode?) -> TreeNode? { + guard let root = root else { return nil } + + (root.left, root.right) = (root.right, root.left) + + invertTree(root.left) + invertTree(root.right) + + return root } } ``` @@ -383,7 +504,7 @@ public class Solution { ### Time & Space Complexity * Time complexity: $O(n)$ -* Space complexity: $O(n)$ +* Space complexity: $O(n)$ for recursion stack. --- @@ -592,6 +713,43 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func invertTree(_ root: TreeNode?) -> TreeNode? { + guard let root = root else { return nil } + var stack: [TreeNode] = [root] + + while !stack.isEmpty { + let node = stack.removeLast() + (node.left, node.right) = (node.right, node.left) + + if let left = node.left { + stack.append(left) + } + if let right = node.right { + stack.append(right) + } + } + return root + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/is-anagram.md b/articles/is-anagram.md index ae3a44534..eb996634a 100644 --- a/articles/is-anagram.md +++ b/articles/is-anagram.md @@ -112,6 +112,14 @@ class Solution { } ``` +```swift +class Solution { + func isAnagram(_ s: String, _ t: String) -> Bool { + return s.count == t.count && s.sorted() == t.sorted() + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -123,7 +131,7 @@ class Solution { --- -## 2. Hash Table +## 2. Hash Map ::tabs-start @@ -266,6 +274,29 @@ class Solution { } ``` +```swift +class Solution { + func isAnagram(_ s: String, _ t: String) -> Bool { + if s.count != t.count { + return false + } + + var countS = [Character: Int]() + var countT = [Character: Int]() + + let sArray = Array(s) + let tArray = Array(t) + + for i in 0.. Bool { + if s.count != t.count { + return false + } + + var count = [Int](repeating: 0, count: 26) + let sArray = Array(s) + let tArray = Array(t) + + for i in 0.. Where $n$ is the length of string $s$ and $m$ is the length of string $t$. +> Where $n$ is the length of string $s$ and $m$ is the length of string $t$. \ No newline at end of file diff --git a/articles/is-palindrome.md b/articles/is-palindrome.md index e7675ceb9..9aea0c833 100644 --- a/articles/is-palindrome.md +++ b/articles/is-palindrome.md @@ -123,6 +123,22 @@ class Solution { } ``` +```swift +class Solution { + func isPalindrome(_ s: String) -> Bool { + var newStr = "" + + for c in s { + if c.isLetter || c.isNumber { + newStr.append(c.lowercased()) + } + } + + return newStr == String(newStr.reversed()) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -327,6 +343,34 @@ class Solution { } ``` +```swift +class Solution { + func isPalindrome(_ s: String) -> Bool { + let chars = Array(s) + var l = 0, r = chars.count - 1 + + while l < r { + while l < r && !isAlphaNum(chars[l]) { + l += 1 + } + while r > l && !isAlphaNum(chars[r]) { + r -= 1 + } + if chars[l].lowercased() != chars[r].lowercased() { + return false + } + l += 1 + r -= 1 + } + return true + } + + private func isAlphaNum(_ c: Character) -> Bool { + return c.isLetter || c.isNumber + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/islands-and-treasure.md b/articles/islands-and-treasure.md index ff99ef107..86e92192f 100644 --- a/articles/islands-and-treasure.md +++ b/articles/islands-and-treasure.md @@ -302,6 +302,43 @@ class Solution { } ``` +```swift +class Solution { + func islandsAndTreasure(_ grid: inout [[Int]]) { + let ROWS = grid.count + let COLS = grid[0].count + let INF = 2147483647 + let directions = [(1, 0), (-1, 0), (0, 1), (0, -1)] + var visit = Array(repeating: Array(repeating: false, count: COLS), count: ROWS) + + func dfs(_ r: Int, _ c: Int) -> Int { + if r < 0 || c < 0 || r >= ROWS || c >= COLS || grid[r][c] == -1 || visit[r][c] { + return INF + } + if grid[r][c] == 0 { + return 0 + } + + visit[r][c] = true + var res = INF + for (dx, dy) in directions { + res = min(res, 1 + dfs(r + dx, c + dy)) + } + visit[r][c] = false + return res + } + + for r in 0.. Int { + var q = Deque<(Int, Int)>() + q.append((r, c)) + var visit = Array(repeating: Array(repeating: false, count: COLS), count: ROWS) + visit[r][c] = true + var steps = 0 + while !q.isEmpty { + let levelCount = q.count + for _ in 0..= 0 && nr < ROWS && nc >= 0 && nc < COLS && + !visit[nr][nc] && grid[nr][nc] != -1) { + visit[nr][nc] = true + q.append((nr, nc)) + } + } + } + steps += 1 + } + return INF + } + + for r in 0..() + var q = Deque() + + func addCell(_ r: Int, _ c: Int) { + if r < 0 || c < 0 || r >= ROWS || c >= COLS { return } + let item = Item(r: r, c: c) + if visit.contains(item) || grid[r][c] == -1 { return } + visit.insert(item) + q.append(item) + } + + for r in 0.. Int { + func dfs(_ i: Int) -> Int { + if i == nums.count - 1 { + return 0 + } + if nums[i] == 0 { + return 1000000 + } + + let end = min(nums.count - 1, i + nums[i]) + var res = 1000000 + for j in i + 1..<(end + 1) { + res = min(res, 1 + dfs(j)) + } + + return res + } + + return dfs(0) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -382,6 +411,37 @@ class Solution { } ``` +```swift +class Solution { + var memo: [Int: Int] = [:] + + func jump(_ nums: [Int]) -> Int { + return dfs(nums, 0) + } + + private func dfs(_ nums: [Int], _ i: Int) -> Int { + if let cachedResult = memo[i] { + return cachedResult + } + if i == nums.count - 1 { + return 0 + } + if nums[i] == 0 { + return 1000000 + } + + var res = 1000000 + let end = min(nums.count, i + nums[i] + 1) + for j in i + 1.. Int { + let n = nums.count + var dp = Array(repeating: 1000000, count: n) + dp[n - 1] = 0 + + for i in stride(from: n - 2, through: 0, by: -1) { + let end = min(n, i + nums[i] + 1) + for j in i + 1.. Int { + var res = 0 + var l = 0 + var r = 0 + + while r < nums.count - 1 { + var farthest = 0 + for i in l...r { + farthest = max(farthest, i + nums[i]) + } + l = r + 1 + r = farthest + res += 1 + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/jump-game.md b/articles/jump-game.md index 850539bca..c5048055e 100644 --- a/articles/jump-game.md +++ b/articles/jump-game.md @@ -157,6 +157,29 @@ class Solution { } ``` +```swift +class Solution { + func canJump(_ nums: [Int]) -> Bool { + + func dfs(_ i: Int) -> Bool { + if i == nums.count - 1 { + return true + } + + let end = min(nums.count - 1, i + nums[i]) + for j in i + 1..<(end + 1) { + if dfs(j) { + return true + } + } + return false + } + + return dfs(0) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -397,6 +420,39 @@ class Solution { } ``` +```swift +class Solution { + func canJump(_ nums: [Int]) -> Bool { + var memo: [Int: Bool] = [:] + + func dfs(_ i: Int) -> Bool { + if let cachedResult = memo[i] { + return cachedResult + } + if i == nums.count - 1 { + return true + } + if nums[i] == 0 { + return false + } + + let end = min(nums.count, i + nums[i] + 1) + for j in i + 1.. Bool { + let n = nums.count + var dp = [Bool](repeating: false, count: n) + dp[n - 1] = true + + for i in (0.. Bool { + var goal = nums.count - 1 + + for i in stride(from: nums.count - 2, through: 0, by: -1) { + if i + nums[i] >= goal { + goal = i + } + } + + return goal == 0 + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/k-closest-points-to-origin.md b/articles/k-closest-points-to-origin.md index 823a5a33f..7882e7c18 100644 --- a/articles/k-closest-points-to-origin.md +++ b/articles/k-closest-points-to-origin.md @@ -75,6 +75,16 @@ class Solution { } ``` +```swift +class Solution { + func kClosest(_ points: [[Int]], _ k: Int) -> [[Int]] { + return points.sorted { ($0[0] * $0[0] + $0[1] * $0[1]) < ($1[0] * $1[0] + $1[1] * $1[1]) } + .prefix(k) + .map { $0 } + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -84,7 +94,7 @@ class Solution { --- -## 2. Min Heap +## 2. Min-Heap ::tabs-start @@ -242,6 +252,39 @@ class Solution { } ``` +```swift +struct Item: Comparable { + let dist: Int + let x: Int + let y: Int + + static func < (lhs: Item, rhs: Item) -> Bool { + return lhs.dist < rhs.dist + } +} + +class Solution { + func kClosest(_ points: [[Int]], _ k: Int) -> [[Int]] { + var minHeap = Heap() + + for point in points { + let x = point[0], y = point[1] + let dist = x * x + y * y + minHeap.insert(Item(dist: dist, x: x, y: y)) + } + + var res = [[Int]]() + for _ in 0.. Bool { + return lhs.dist > rhs.dist + } +} + +class Solution { + func kClosest(_ points: [[Int]], _ k: Int) -> [[Int]] { + var maxHeap = Heap() + + for point in points { + let x = point[0], y = point[1] + let dist = x * x + y * y + maxHeap.insert(Item(dist: dist, x: x, y: y)) + if maxHeap.count > k { + _ = maxHeap.popMin() + } + } + + var res = [[Int]]() + while !maxHeap.isEmpty { + if let item = maxHeap.popMin() { + res.append([item.x, item.y]) + } + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -721,6 +800,46 @@ class Solution { } ``` +```swift +class Solution { + func kClosest(_ points: [[Int]], _ k: Int) -> [[Int]] { + var points = points + + func euclidean(_ point: [Int]) -> Int { + return point[0] * point[0] + point[1] * point[1] + } + + func partition(_ l: Int, _ r: Int) -> Int { + let pivotIdx = r + let pivotDist = euclidean(points[pivotIdx]) + var i = l + for j in l.. Int { + let sortedNums = nums.sorted() + return sortedNums[sortedNums.count - k] + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -184,6 +193,23 @@ class Solution { } ``` +```swift +class Solution { + func findKthLargest(_ nums: [Int], _ k: Int) -> Int { + var minHeap = Heap() + + for num in nums { + minHeap.insert(num) + if minHeap.count > k { + _ = minHeap.removeMin() + } + } + + return minHeap.popMin()! + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -417,6 +443,38 @@ class Solution { } ``` +```swift +class Solution { + func findKthLargest(_ nums: [Int], _ k: Int) -> Int { + var nums = nums + let k = nums.count - k + + func quickSelect(_ l: Int, _ r: Int) -> Int { + let pivot = nums[r] + var p = l + + for i in l.. k { + return quickSelect(l, p - 1) + } else if p < k { + return quickSelect(p + 1, r) + } else { + return nums[p] + } + } + + return quickSelect(0, nums.count - 1) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -822,6 +880,70 @@ class Solution { } ``` +```swift +class Solution { + func partition(_ nums: inout [Int], _ left: Int, _ right: Int) -> Int { + let mid = (left + right) >> 1 + nums.swapAt(mid, left + 1) + + if nums[left] < nums[right] { + nums.swapAt(left, right) + } + if nums[left + 1] < nums[right] { + nums.swapAt(left + 1, right) + } + if nums[left] < nums[left + 1] { + nums.swapAt(left, left + 1) + } + + let pivot = nums[left + 1] + var i = left + 1 + var j = right + + while true { + repeat { i += 1 } while nums[i] > pivot + repeat { j -= 1 } while nums[j] < pivot + + if i > j { + break + } + nums.swapAt(i, j) + } + + nums.swapAt(left + 1, j) + return j + } + + func quickSelect(_ nums: inout [Int], _ k: Int) -> Int { + var left = 0 + var right = nums.count - 1 + + while true { + if right <= left + 1 { + if right == left + 1 && nums[right] > nums[left] { + nums.swapAt(left, right) + } + return nums[k] + } + + let j = partition(&nums, left, right) + + if j >= k { + right = j - 1 + } + if j <= k { + left = j + 1 + } + } + } + + func findKthLargest(_ nums: [Int], _ k: Int) -> Int { + var nums = nums + return quickSelect(&nums, k - 1) + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/kth-largest-integer-in-a-stream.md b/articles/kth-largest-integer-in-a-stream.md index 7913b93ca..42a4f617a 100644 --- a/articles/kth-largest-integer-in-a-stream.md +++ b/articles/kth-largest-integer-in-a-stream.md @@ -124,12 +124,32 @@ class KthLargest(k: Int, nums: IntArray) { } ``` +```swift +class KthLargest { + private var k: Int + private var arr: [Int] + + init(_ k: Int, _ nums: [Int]) { + self.k = k + self.arr = nums + } + + func add(_ val: Int) -> Int { + arr.append(val) + arr.sort() + return arr[arr.count - k] + } +} +``` + ::tabs-end ### Time & Space Complexity * Time complexity: $O(m * n\log n)$ -* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. +* Space complexity: + * $O(m)$ extra space. + * $O(1)$ or $O(n)$ space depending on the sorting algorithm. > Where $m$ is the number of calls made to $add()$ and $n$ is the current size of the array. @@ -324,6 +344,32 @@ class KthLargest(k: Int, nums: IntArray) { } ``` +```swift +class KthLargest { + private var minHeap: Heap + private let k: Int + + init(_ k: Int, _ nums: [Int]) { + self.k = k + self.minHeap = Heap() + for num in nums { + minHeap.insert(num) + if minHeap.count > k { + minHeap.popMin() + } + } + } + + func add(_ val: Int) -> Int { + minHeap.insert(val) + if minHeap.count > k { + minHeap.popMin() + } + return minHeap.min! + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/kth-smallest-integer-in-bst.md b/articles/kth-smallest-integer-in-bst.md index 1014ba6d4..ec5dfe795 100644 --- a/articles/kth-smallest-integer-in-bst.md +++ b/articles/kth-smallest-integer-in-bst.md @@ -225,6 +225,40 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func kthSmallest(_ root: TreeNode?, _ k: Int) -> Int { + var arr = [Int]() + + func dfs(_ node: TreeNode?) { + guard let node = node else { return } + arr.append(node.val) + dfs(node.left) + dfs(node.right) + } + + dfs(root) + arr.sort() + return arr[k - 1] + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -456,6 +490,39 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func kthSmallest(_ root: TreeNode?, _ k: Int) -> Int { + var arr = [Int]() + + func dfs(_ node: TreeNode?) { + guard let node = node else { return } + dfs(node.left) + arr.append(node.val) + dfs(node.right) + } + + dfs(root) + return arr[k - 1] + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -721,6 +788,45 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func kthSmallest(_ root: TreeNode?, _ k: Int) -> Int { + var cnt = k + var res = root!.val + + func dfs(_ node: TreeNode?) { + guard let node = node else { return } + + dfs(node.left) + cnt -= 1 + if cnt == 0 { + res = node.val + return + } + dfs(node.right) + } + + dfs(root) + return res + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -983,6 +1089,45 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func kthSmallest(_ root: TreeNode?, _ k: Int) -> Int { + var stack = [TreeNode]() + var curr = root + var k = k + + while !stack.isEmpty || curr != nil { + while curr != nil { + stack.append(curr!) + curr = curr?.left + } + curr = stack.removeLast() + k -= 1 + if k == 0 { + return curr!.val + } + curr = curr?.right + } + return -1 + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -1298,6 +1443,58 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func kthSmallest(_ root: TreeNode?, _ k: Int) -> Int { + var curr = root + var k = k + + while curr != nil { + if curr?.left == nil { + k -= 1 + if k == 0 { + return curr!.val + } + curr = curr?.right + } else { + var pred = curr?.left + while pred?.right != nil && pred?.right !== curr { + pred = pred?.right + } + + if pred?.right == nil { + pred?.right = curr + curr = curr?.left + } else { + pred?.right = nil + k -= 1 + if k == 0 { + return curr!.val + } + curr = curr?.right + } + } + } + return -1 + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/largest-rectangle-in-histogram.md b/articles/largest-rectangle-in-histogram.md index 54d44de5b..75df88ffe 100644 --- a/articles/largest-rectangle-in-histogram.md +++ b/articles/largest-rectangle-in-histogram.md @@ -203,6 +203,35 @@ class Solution { } ``` +```swift +class Solution { + func largestRectangleArea(_ heights: [Int]) -> Int { + let n = heights.count + var maxArea = 0 + + for i in 0..= height { + rightMost += 1 + } + + var leftMost = i + while leftMost >= 0 && heights[leftMost] >= height { + leftMost -= 1 + } + + rightMost -= 1 + leftMost += 1 + maxArea = max(maxArea, height * (rightMost - leftMost + 1)) + } + + return maxArea + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -767,6 +796,86 @@ class Solution { } ``` +```swift +class MinIdxSegmentTree { + private var n: Int + private var INF = Int(1e9) + private var A: [Int] + private var tree: [Int] + + init(_ N: Int, _ A: [Int]) { + self.n = N + self.A = A + while (self.n & (self.n - 1)) != 0 { + self.A.append(self.INF) + self.n += 1 + } + self.tree = [Int](repeating: 0, count: 2 * self.n) + build() + } + + private func build() { + for i in 0..> 1 + while j >= 1 { + let a = tree[j << 1] + let b = tree[(j << 1) + 1] + tree[j] = (A[a] <= A[b]) ? a : b + j >>= 1 + } + } + + func query(_ ql: Int, _ qh: Int) -> Int { + return _query(1, 0, n - 1, ql, qh) + } + + private func _query(_ node: Int, _ l: Int, _ h: Int, _ ql: Int, _ qh: Int) -> Int { + if ql > h || qh < l { + return INF + } + if l >= ql && h <= qh { + return tree[node] + } + let a = _query(node << 1, l, (l + h) >> 1, ql, qh) + let b = _query((node << 1) + 1, ((l + h) >> 1) + 1, h, ql, qh) + if a == INF { return b } + if b == INF { return a } + return (A[a] <= A[b]) ? a : b + } +} + +class Solution { + func getMaxArea(_ heights: [Int], _ l: Int, _ r: Int, _ st: MinIdxSegmentTree) -> Int { + if l > r { return 0 } + if l == r { return heights[l] } + + let minIdx = st.query(l, r) + return max( + max(getMaxArea(heights, l, minIdx - 1, st), + getMaxArea(heights, minIdx + 1, r, st)), + (r - l + 1) * heights[minIdx] + ) + } + + func largestRectangleArea(_ heights: [Int]) -> Int { + let n = heights.count + let st = MinIdxSegmentTree(n, heights) + return getMaxArea(heights, 0, n - 1, st) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -1075,6 +1184,46 @@ class Solution { } ``` +```swift +class Solution { + func largestRectangleArea(_ heights: [Int]) -> Int { + let n = heights.count + var stack = [Int]() + + var leftMost = [Int](repeating: -1, count: n) + for i in 0..= heights[i] { + stack.removeLast() + } + if !stack.isEmpty { + leftMost[i] = stack.last! + } + stack.append(i) + } + + stack.removeAll() + var rightMost = [Int](repeating: n, count: n) + for i in stride(from: n - 1, through: 0, by: -1) { + while !stack.isEmpty && heights[stack.last!] >= heights[i] { + stack.removeLast() + } + if !stack.isEmpty { + rightMost[i] = stack.last! + } + stack.append(i) + } + + var maxArea = 0 + for i in 0.. Int { + var maxArea = 0 + var stack = [(Int, Int)]() // Pair: (index, height) + + for (i, h) in heights.enumerated() { + var start = i + while !stack.isEmpty && stack.last!.1 > h { + let (index, height) = stack.removeLast() + maxArea = max(maxArea, height * (i - index)) + start = index + } + stack.append((start, h)) + } + + for (i, h) in stack { + maxArea = max(maxArea, h * (heights.count - i)) + } + + return maxArea + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -1292,7 +1466,7 @@ class Solution { --- -## 5. Stack (One Pass) +## 5. Stack (Optimal) ::tabs-start @@ -1453,6 +1627,26 @@ class Solution { } ``` +```swift +class Solution { + func largestRectangleArea(_ heights: [Int]) -> Int { + let n = heights.count + var maxArea = 0 + var stack = [Int]() + + for i in 0...n { + while !stack.isEmpty && (i == n || heights[stack.last!] >= heights[i]) { + let height = heights[stack.removeLast()] + let width = stack.isEmpty ? i : i - stack.last! - 1 + maxArea = max(maxArea, height * width) + } + stack.append(i) + } + return maxArea + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/last-stone-weight.md b/articles/last-stone-weight.md index da1ec745e..69ab3403a 100644 --- a/articles/last-stone-weight.md +++ b/articles/last-stone-weight.md @@ -127,6 +127,24 @@ class Solution { } ``` +```swift +class Solution { + func lastStoneWeight(_ stones: [Int]) -> Int { + var stones = stones + + while stones.count > 1 { + stones.sort() + let cur = stones.removeLast() - stones.removeLast() + if cur > 0 { + stones.append(cur) + } + } + + return stones.isEmpty ? 0 : stones[0] + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -368,6 +386,40 @@ class Solution { } ``` +```swift +class Solution { + func lastStoneWeight(_ stones: [Int]) -> Int { + var stones = stones.sorted() + var n = stones.count + + while n > 1 { + let cur = stones.removeLast() - stones.removeLast() + n -= 2 + if cur > 0 { + var l = 0, r = n + while l < r { + let mid = (l + r) / 2 + if stones[mid] < cur { + l = mid + 1 + } else { + r = mid + } + } + let pos = l + stones.append(0) + n += 1 + for i in stride(from: n - 1, to: pos, by: -1) { + stones[i] = stones[i - 1] + } + stones[pos] = cur + } + } + + return n > 0 ? stones[0] : 0 + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -543,6 +595,22 @@ class Solution { } ``` +```swift +class Solution { + func lastStoneWeight(_ stones: [Int]) -> Int { + var heap = Heap(stones) + while heap.count > 1 { + let first = heap.popMax()! + let second = heap.popMax()! + if first > second { + heap.insert(first - second) + } + } + return heap.isEmpty ? 0 : heap.popMax()! + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -843,6 +911,46 @@ class Solution { } ``` +```swift +class Solution { + func lastStoneWeight(_ stones: [Int]) -> Int { + guard let maxStone = stones.max() else { return 0 } + + var bucket = [Int](repeating: 0, count: maxStone + 1) + for stone in stones { + bucket[stone] += 1 + } + + var first = maxStone + var second = maxStone + + while first > 0 { + if bucket[first] % 2 == 0 { + first -= 1 + continue + } + + var j = min(first - 1, second) + while j > 0 && bucket[j] == 0 { + j -= 1 + } + + if j == 0 { + return first + } + + second = j + bucket[first] -= 1 + bucket[second] -= 1 + bucket[first - second] += 1 + first = max(first - second, second) + } + + return first + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/level-order-traversal-of-binary-tree.md b/articles/level-order-traversal-of-binary-tree.md index 3bb08fe9a..28df7fc5f 100644 --- a/articles/level-order-traversal-of-binary-tree.md +++ b/articles/level-order-traversal-of-binary-tree.md @@ -19,11 +19,11 @@ class Solution: return None if len(res) == depth: res.append([]) - + res[depth].append(node.val) dfs(node.left, depth + 1) dfs(node.right, depth + 1) - + dfs(root, 0) return res ``` @@ -251,6 +251,44 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func levelOrder(_ root: TreeNode?) -> [[Int]] { + var res = [[Int]]() + + func dfs(_ node: TreeNode?, _ depth: Int) { + guard let node = node else { return } + + if res.count == depth { + res.append([]) + } + + res[depth].append(node.val) + dfs(node.left, depth + 1) + dfs(node.right, depth + 1) + } + + dfs(root, 0) + return res + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -549,6 +587,48 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func levelOrder(_ root: TreeNode?) -> [[Int]] { + var res = [[Int]]() + var q = Deque() + q.append(root) + + while !q.isEmpty { + let qLen = q.count + var level = [Int]() + + for _ in 0.. Bool { + var seen = Set() + var cur = head + + while cur != nil { + let nodeId = ObjectIdentifier(cur!) + if seen.contains(nodeId) { + return true + } + seen.insert(nodeId) + cur = cur?.next + } + return false + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -387,6 +418,36 @@ class Solution { } ``` +```swift +/** + * Definition for singly-linked list. + * public class ListNode { + * public var val: Int + * public var next: ListNode? + * public init(_ val: Int) { + * self.val = val + * self.next = nil + * } + * } + */ + +class Solution { + func hasCycle(_ head: ListNode?) -> Bool { + var slow = head + var fast = head + + while fast != nil && fast?.next != nil { + slow = slow?.next + fast = fast?.next?.next + if slow === fast { + return true + } + } + return false + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/longest-common-subsequence.md b/articles/longest-common-subsequence.md index f75a48573..95c23cd86 100644 --- a/articles/longest-common-subsequence.md +++ b/articles/longest-common-subsequence.md @@ -136,6 +136,27 @@ class Solution { } ``` +```swift +class Solution { + func longestCommonSubsequence(_ text1: String, _ text2: String) -> Int { + let arr1 = Array(text1) + let arr2 = Array(text2) + + func dfs(_ i: Int, _ j: Int) -> Int { + if i == arr1.count || j == arr2.count { + return 0 + } + if arr1[i] == arr2[j] { + return 1 + dfs(i + 1, j + 1) + } + return max(dfs(i + 1, j), dfs(i, j + 1)) + } + + return dfs(0, 0) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -363,6 +384,35 @@ class Solution { } ``` +```swift +class Solution { + func longestCommonSubsequence(_ text1: String, _ text2: String) -> Int { + let arr1 = Array(text1) + let arr2 = Array(text2) + var memo = [String: Int]() + + func dfs(_ i: Int, _ j: Int) -> Int { + if i == arr1.count || j == arr2.count { + return 0 + } + let key = "\(i),\(j)" + if let val = memo[key] { + return val + } + + if arr1[i] == arr2[j] { + memo[key] = 1 + dfs(i + 1, j + 1) + } else { + memo[key] = max(dfs(i + 1, j), dfs(i, j + 1)) + } + return memo[key]! + } + + return dfs(0, 0) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -534,6 +584,31 @@ class Solution { } ``` +```swift +class Solution { + func longestCommonSubsequence(_ text1: String, _ text2: String) -> Int { + let m = text1.count + let n = text2.count + let arr1 = Array(text1) + let arr2 = Array(text2) + + var dp = Array(repeating: Array(repeating: 0, count: n + 1), count: m + 1) + + for i in stride(from: m - 1, through: 0, by: -1) { + for j in stride(from: n - 1, through: 0, by: -1) { + if arr1[i] == arr2[j] { + dp[i][j] = 1 + dp[i + 1][j + 1] + } else { + dp[i][j] = max(dp[i][j + 1], dp[i + 1][j]) + } + } + } + + return dp[0][0] + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -749,6 +824,35 @@ class Solution { } ``` +```swift +class Solution { + func longestCommonSubsequence(_ text1: String, _ text2: String) -> Int { + var t1 = Array(text1) + var t2 = Array(text2) + + if t1.count < t2.count { + swap(&t1, &t2) + } + + var prev = Array(repeating: 0, count: t2.count + 1) + var curr = Array(repeating: 0, count: t2.count + 1) + + for i in stride(from: t1.count - 1, through: 0, by: -1) { + for j in stride(from: t2.count - 1, through: 0, by: -1) { + if t1[i] == t2[j] { + curr[j] = 1 + prev[j + 1] + } else { + curr[j] = max(curr[j + 1], prev[j]) + } + } + swap(&prev, &curr) + } + + return prev[0] + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -966,6 +1070,36 @@ class Solution { } ``` +```swift +class Solution { + func longestCommonSubsequence(_ text1: String, _ text2: String) -> Int { + var t1 = Array(text1) + var t2 = Array(text2) + + if t1.count < t2.count { + swap(&t1, &t2) + } + + var dp = Array(repeating: 0, count: t2.count + 1) + + for i in stride(from: t1.count - 1, through: 0, by: -1) { + var prev = 0 + for j in stride(from: t2.count - 1, through: 0, by: -1) { + let temp = dp[j] + if t1[i] == t2[j] { + dp[j] = 1 + prev + } else { + dp[j] = max(dp[j], dp[j + 1]) + } + prev = temp + } + } + + return dp[0] + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/longest-consecutive-sequence.md b/articles/longest-consecutive-sequence.md index 9f7193486..22cd5db3f 100644 --- a/articles/longest-consecutive-sequence.md +++ b/articles/longest-consecutive-sequence.md @@ -143,6 +143,29 @@ class Solution { } ``` +```swift +class Solution { + func longestConsecutive(_ nums: [Int]) -> Int { + var res = 0 + let store = Set(nums) + + for num in nums { + var streak = 0 + var curr = num + + while store.contains(curr) { + streak += 1 + curr += 1 + } + + res = max(res, streak) + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -343,12 +366,44 @@ class Solution { } ``` +```swift +class Solution { + func longestConsecutive(_ nums: [Int]) -> Int { + if nums.isEmpty { + return 0 + } + + var res = 0 + var nums = nums.sorted() + + var curr = nums[0] + var streak = 0 + var i = 0 + + while i < nums.count { + if curr != nums[i] { + curr = nums[i] + streak = 0 + } + while i < nums.count && nums[i] == curr { + i += 1 + } + streak += 1 + curr += 1 + res = max(res, streak) + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity * Time complexity: $O(n \log n)$ -* Space complexity: $O(1)$ +* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. --- @@ -506,6 +561,27 @@ class Solution { } ``` +```swift +class Solution { + func longestConsecutive(_ nums: [Int]) -> Int { + let numSet = Set(nums) + var longest = 0 + + for num in numSet { + if !numSet.contains(num - 1) { + var length = 1 + while numSet.contains(num + length) { + length += 1 + } + longest = max(length, longest) + } + } + + return longest + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -662,6 +738,31 @@ class Solution { } ``` +```swift +class Solution { + func longestConsecutive(_ nums: [Int]) -> Int { + var mp = [Int: Int]() + var res = 0 + + for num in nums { + if mp[num] == nil { + let left = mp[num - 1] ?? 0 + let right = mp[num + 1] ?? 0 + let length = left + right + 1 + + mp[num] = length + mp[num - left] = length + mp[num + right] = length + + res = max(res, length) + } + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/longest-increasing-path-in-matrix.md b/articles/longest-increasing-path-in-matrix.md index 950ac6e73..e529b1ded 100644 --- a/articles/longest-increasing-path-in-matrix.md +++ b/articles/longest-increasing-path-in-matrix.md @@ -230,6 +230,35 @@ class Solution { } ``` +```swift +class Solution { + func longestIncreasingPath(_ matrix: [[Int]]) -> Int { + let rows = matrix.count, cols = matrix[0].count + let directions = [(-1, 0), (1, 0), (0, -1), (0, 1)] + + func dfs(_ r: Int, _ c: Int, _ prevVal: Int) -> Int { + if r < 0 || c < 0 || r >= rows || c >= cols || matrix[r][c] <= prevVal { + return 0 + } + + var res = 1 + for (dr, dc) in directions { + res = max(res, 1 + dfs(r + dr, c + dc, matrix[r][c])) + } + return res + } + + var lip = 0 + for r in 0.. Int { + let rows = matrix.count, cols = matrix[0].count + var dp = Array(repeating: Array(repeating: -1, count: cols), count: rows) + + func dfs(_ r: Int, _ c: Int, _ prevVal: Int) -> Int { + if r < 0 || r >= rows || c < 0 || c >= cols || matrix[r][c] <= prevVal { + return 0 + } + if dp[r][c] != -1 { + return dp[r][c] + } + + var res = 1 + res = max(res, 1 + dfs(r + 1, c, matrix[r][c])) + res = max(res, 1 + dfs(r - 1, c, matrix[r][c])) + res = max(res, 1 + dfs(r, c + 1, matrix[r][c])) + res = max(res, 1 + dfs(r, c - 1, matrix[r][c])) + + dp[r][c] = res + return res + } + + var maxPath = 0 + for r in 0.. Int { + let rows = matrix.count, cols = matrix[0].count + let directions = [(-1, 0), (1, 0), (0, -1), (0, 1)] + var indegree = Array(repeating: Array(repeating: 0, count: cols), count: rows) + + for r in 0..= 0 && nr < rows && nc >= 0 && nc < cols && + matrix[nr][nc] < matrix[r][c]) { + indegree[r][c] += 1 + } + } + } + } + + var q = Deque<(Int, Int)>() + for r in 0..= 0 && nr < rows && nc >= 0 && nc < cols && + matrix[nr][nc] > matrix[r][c]) { + indegree[nr][nc] -= 1 + if indegree[nr][nc] == 0 { + q.append((nr, nc)) + } + } + } + } + LIS += 1 + } + return LIS + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/longest-increasing-subsequence.md b/articles/longest-increasing-subsequence.md index 1b24412eb..79391921a 100644 --- a/articles/longest-increasing-subsequence.md +++ b/articles/longest-increasing-subsequence.md @@ -170,6 +170,28 @@ class Solution { } ``` +```swift +class Solution { + func lengthOfLIS(_ nums: [Int]) -> Int { + func dfs(_ i: Int, _ j: Int) -> Int { + if i == nums.count { + return 0 + } + + var LIS = dfs(i + 1, j) // not include + + if j == -1 || nums[j] < nums[i] { + LIS = max(LIS, 1 + dfs(i + 1, i)) // include + } + + return LIS + } + + return dfs(0, -1) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -179,7 +201,7 @@ class Solution { --- -## 2. Dynamic Programming (Top-Down) +## 2. Dynamic Programming (Top-Down) - I ::tabs-start @@ -410,6 +432,508 @@ class Solution { } ``` +```swift +class Solution { + func lengthOfLIS(_ nums: [Int]) -> Int { + let n = nums.count + var memo = Array(repeating: Array(repeating: -1, count: n + 1), count: n) + + func dfs(_ i: Int, _ j: Int) -> Int { + if i == n { + return 0 + } + if memo[i][j + 1] != -1 { + return memo[i][j + 1] + } + + var LIS = dfs(i + 1, j) // not include + + if j == -1 || nums[j] < nums[i] { + LIS = max(LIS, 1 + dfs(i + 1, i)) // include + } + + memo[i][j + 1] = LIS + return LIS + } + + return dfs(0, -1) + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n ^ 2)$ + +--- + +## 3. Dynamic Programming (Top-Down) - II + +::tabs-start + +```python +class Solution: + def lengthOfLIS(self, nums: List[int]) -> int: + n = len(nums) + memo = [-1] * n + + def dfs(i): + if memo[i] != -1: + return memo[i] + + LIS = 1 + for j in range(i + 1, n): + if nums[i] < nums[j]: + LIS = max(LIS, 1 + dfs(j)) + + memo[i] = LIS + return LIS + + return max(dfs(i) for i in range(n)) +``` + +```java +public class Solution { + private int[] memo; + + public int lengthOfLIS(int[] nums) { + int n = nums.length; + memo = new int[n]; + Arrays.fill(memo, -1); + + int maxLIS = 1; + for (int i = 0; i < n; i++) { + maxLIS = Math.max(maxLIS, dfs(nums, i)); + } + return maxLIS; + } + + private int dfs(int[] nums, int i) { + if (memo[i] != -1) { + return memo[i]; + } + + int LIS = 1; + for (int j = i + 1; j < nums.length; j++) { + if (nums[i] < nums[j]) { + LIS = Math.max(LIS, 1 + dfs(nums, j)); + } + } + + memo[i] = LIS; + return LIS; + } +} +``` + +```cpp +class Solution { +private: + vector memo; + + int dfs(vector& nums, int i) { + if (memo[i] != -1) { + return memo[i]; + } + + int LIS = 1; + for (int j = i + 1; j < nums.size(); j++) { + if (nums[i] < nums[j]) { + LIS = max(LIS, 1 + dfs(nums, j)); + } + } + + return memo[i] = LIS; + } + +public: + int lengthOfLIS(vector& nums) { + int n = nums.size(); + memo.assign(n, -1); + + int maxLIS = 1; + for (int i = 0; i < n; i++) { + maxLIS = max(maxLIS, dfs(nums, i)); + } + return maxLIS; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + lengthOfLIS(nums) { + const n = nums.length; + const memo = new Array(n).fill(-1); + + const dfs = (i) => { + if (memo[i] !== -1) { + return memo[i]; + } + + let LIS = 1; + for (let j = i + 1; j < n; j++) { + if (nums[i] < nums[j]) { + LIS = Math.max(LIS, 1 + dfs(j)); + } + } + + memo[i] = LIS; + return LIS; + }; + + return Math.max(...nums.map((_, i) => dfs(i))); + } +} +``` + +```csharp +public class Solution { + private int[] memo; + + public int LengthOfLIS(int[] nums) { + int n = nums.Length; + memo = new int[n]; + Array.Fill(memo, -1); + + int maxLIS = 1; + for (int i = 0; i < n; i++) { + maxLIS = Math.Max(maxLIS, Dfs(nums, i)); + } + return maxLIS; + } + + private int Dfs(int[] nums, int i) { + if (memo[i] != -1) { + return memo[i]; + } + + int LIS = 1; + for (int j = i + 1; j < nums.Length; j++) { + if (nums[i] < nums[j]) { + LIS = Math.Max(LIS, 1 + Dfs(nums, j)); + } + } + + memo[i] = LIS; + return LIS; + } +} +``` + +```go +func lengthOfLIS(nums []int) int { + n := len(nums) + memo := make([]int, n) + for i := range memo { + memo[i] = -1 + } + + var dfs func(int) int + dfs = func(i int) int { + if memo[i] != -1 { + return memo[i] + } + + LIS := 1 + for j := i + 1; j < n; j++ { + if nums[i] < nums[j] { + LIS = max(LIS, 1+dfs(j)) + } + } + + memo[i] = LIS + return LIS + } + + maxLIS := 1 + for i := 0; i < n; i++ { + maxLIS = max(maxLIS, dfs(i)) + } + + return maxLIS +} + +func max(a, b int) int { + if a > b { + return a + } + return b +} +``` + +```kotlin +class Solution { + private lateinit var memo: IntArray + + fun lengthOfLIS(nums: IntArray): Int { + val n = nums.size + memo = IntArray(n) { -1 } + + var maxLIS = 1 + for (i in nums.indices) { + maxLIS = maxOf(maxLIS, dfs(nums, i)) + } + return maxLIS + } + + private fun dfs(nums: IntArray, i: Int): Int { + if (memo[i] != -1) { + return memo[i] + } + + var LIS = 1 + for (j in i + 1 until nums.size) { + if (nums[i] < nums[j]) { + LIS = maxOf(LIS, 1 + dfs(nums, j)) + } + } + + memo[i] = LIS + return LIS + } +} +``` + +```swift +class Solution { + func lengthOfLIS(_ nums: [Int]) -> Int { + let n = nums.count + var memo = Array(repeating: -1, count: n) + + func dfs(_ i: Int) -> Int { + if memo[i] != -1 { + return memo[i] + } + + var LIS = 1 + for j in (i + 1)..= 0; i--) { + for (int j = i - 1; j >= -1; j--) { + int LIS = dp[i + 1][j + 1]; // Not including nums[i] + + if (j == -1 || nums[j] < nums[i]) { + LIS = Math.max(LIS, 1 + dp[i + 1][i + 1]); // Including nums[i] + } + + dp[i][j + 1] = LIS; + } + } + + return dp[0][0]; + } +} +``` + +```cpp +class Solution { +public: + int lengthOfLIS(vector& nums) { + int n = nums.size(); + vector> dp(n + 1, vector(n + 1, 0)); + + for (int i = n - 1; i >= 0; --i) { + for (int j = i - 1; j >= -1; --j) { + int LIS = dp[i + 1][j + 1]; // Not including nums[i] + + if (j == -1 || nums[j] < nums[i]) { + LIS = max(LIS, 1 + dp[i + 1][i + 1]); // Including nums[i] + } + + dp[i][j + 1] = LIS; + } + } + + return dp[0][0]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + lengthOfLIS(nums) { + const n = nums.length; + const dp = Array.from({ length: n + 1 }, () => new Array(n + 1).fill(0)); + + for (let i = n - 1; i >= 0; i--) { + for (let j = i - 1; j >= -1; j--) { + let LIS = dp[i + 1][j + 1]; // Not including nums[i] + + if (j === -1 || nums[j] < nums[i]) { + LIS = Math.max(LIS, 1 + dp[i + 1][i + 1]); // Including nums[i] + } + + dp[i][j + 1] = LIS; + } + } + + return dp[0][0]; + } +} +``` + +```csharp +public class Solution { + public int LengthOfLIS(int[] nums) { + int n = nums.Length; + int[,] dp = new int[n + 1, n + 1]; + + for (int i = n - 1; i >= 0; i--) { + for (int j = i - 1; j >= -1; j--) { + int LIS = dp[i + 1, j + 1]; // Not including nums[i] + + if (j == -1 || nums[j] < nums[i]) { + LIS = Math.Max(LIS, 1 + dp[i + 1, i + 1]); // Including nums[i] + } + + dp[i, j + 1] = LIS; + } + } + + return dp[0, 0]; + } +} +``` + +```go +func lengthOfLIS(nums []int) int { + n := len(nums) + dp := make([][]int, n+1) + for i := range dp { + dp[i] = make([]int, n+1) + } + + for i := n - 1; i >= 0; i-- { + for j := i - 1; j >= -1; j-- { + LIS := dp[i+1][j+1] // Not including nums[i] + + if j == -1 || nums[j] < nums[i] { + LIS = max(LIS, 1+dp[i+1][i+1]) // Including nums[i] + } + + dp[i][j+1] = LIS + } + } + + return dp[0][0] +} + +func max(a, b int) int { + if a > b { + return a + } + return b +} +``` + +```kotlin +class Solution { + fun lengthOfLIS(nums: IntArray): Int { + val n = nums.size + val dp = Array(n + 1) { IntArray(n + 1) } + + for (i in n - 1 downTo 0) { + for (j in i - 1 downTo -1) { + var LIS = dp[i + 1][j + 1] // Not including nums[i] + + if (j == -1 || nums[j] < nums[i]) { + LIS = maxOf(LIS, 1 + dp[i + 1][i + 1]) // Including nums[i] + } + + dp[i][j + 1] = LIS + } + } + + return dp[0][0] + } +} +``` + +```swift +class Solution { + func lengthOfLIS(_ nums: [Int]) -> Int { + let n = nums.count + var dp = Array(repeating: Array(repeating: 0, count: n + 1), count: n + 1) + + for i in stride(from: n - 1, through: 0, by: -1) { + for j in stride(from: i - 1, through: -1, by: -1) { + var LIS = dp[i + 1][j + 1] // Not including nums[i] + + if j == -1 || nums[j] < nums[i] { + LIS = max(LIS, 1 + dp[i + 1][i + 1]) // Including nums[i] + } + + dp[i][j + 1] = LIS + } + } + + return dp[0][0] + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -419,7 +943,7 @@ class Solution { --- -## 3. Dynamic Programming (Bottom-Up) +## 5. Dynamic Programming (Bottom-Up) - II ::tabs-start @@ -556,6 +1080,23 @@ class Solution { } ``` +```swift +class Solution { + func lengthOfLIS(_ nums: [Int]) -> Int { + var LIS = Array(repeating: 1, count: nums.count) + + for i in stride(from: nums.count - 1, through: 0, by: -1) { + for j in (i + 1)..> 1 + while j >= 1 { + tree[j] = max(tree[j << 1], tree[j << 1 | 1]) + j >>= 1 + } + } + + func query(_ l: Int, _ r: Int) -> Int { + if l > r { + return 0 + } + var res = Int.min + var l = l + n + var r = r + n + 1 + while l < r { + if l & 1 == 1 { + res = max(res, tree[l]) + l += 1 + } + if r & 1 == 1 { + r -= 1 + res = max(res, tree[r]) + } + l >>= 1 + r >>= 1 + } + return res + } +} + +class Solution { + func lengthOfLIS(_ nums: [Int]) -> Int { + func compress(_ arr: [Int]) -> [Int] { + let sortedArr = Array(Set(arr)).sorted() + return arr.map { sortedArr.firstIndex(of: $0)! } + } + + let nums = compress(nums) + let n = nums.count + let segTree = SegmentTree(n) + + var LIS = 0 + for num in nums { + let curLIS = segTree.query(0, num - 1) + 1 + segTree.update(num, curLIS) + LIS = max(LIS, curLIS) + } + return LIS + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -1059,7 +1667,7 @@ class Solution { --- -## 5. Binary Search +## 7. Dynamic Programming + Binary Search ::tabs-start @@ -1237,6 +1845,39 @@ class Solution { } ``` +```swift +class Solution { + func lengthOfLIS(_ nums: [Int]) -> Int { + var dp = [nums[0]] + var LIS = 1 + + for i in 1.. Int { + var left = 0, right = dp.count - 1 + while left < right { + let mid = (left + right) / 2 + if dp[mid] < target { + left = mid + 1 + } else { + right = mid + } + } + return left + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/longest-palindromic-substring.md b/articles/longest-palindromic-substring.md index 715d7c512..1d0f82c17 100644 --- a/articles/longest-palindromic-substring.md +++ b/articles/longest-palindromic-substring.md @@ -180,12 +180,38 @@ class Solution { } ``` +```swift +class Solution { + func longestPalindrome(_ s: String) -> String { + let chars = Array(s) + var res = "" + var resLen = 0 + + for i in 0..= r && resLen < (j - i + 1) { + res = String(chars[i...j]) + resLen = j - i + 1 + } + } + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity * Time complexity: $O(n ^ 3)$ -* Space complexity: $O(1)$ +* Space complexity: $O(n)$ --- @@ -377,6 +403,31 @@ class Solution { } ``` +```swift +class Solution { + func longestPalindrome(_ s: String) -> String { + let chars = Array(s) + let n = chars.count + var resIdx = 0, resLen = 0 + var dp = Array(repeating: Array(repeating: false, count: n), count: n) + + for i in stride(from: n - 1, through: 0, by: -1) { + for j in i.. String { + let chars = Array(s) + var resIdx = 0 + var resLen = 0 + + for i in 0..= 0 && r < chars.count && chars[l] == chars[r] { + if (r - l + 1) > resLen { + resIdx = l + resLen = r - l + 1 + } + l -= 1 + r += 1 + } + + // Even length palindrome + l = i + r = i + 1 + while l >= 0 && r < chars.count && chars[l] == chars[r] { + if (r - l + 1) > resLen { + resIdx = l + resLen = r - l + 1 + } + l -= 1 + r += 1 + } + } + + return String(chars[resIdx.. String { + func manacher(_ s: String) -> [Int] { + let t = "#" + s.map { String($0) }.joined(separator: "#") + "#" + let tArray = Array(t) + let n = tArray.count + var p = [Int](repeating: 0, count: n) + var l = 0, r = 0 + + for i in 0..= 0 && + tArray[i + p[i] + 1] == tArray[i - p[i] - 1]) { + p[i] += 1 + } + if i + p[i] > r { + l = i - p[i] + r = i + p[i] + } + } + return p + } + + let p = manacher(s) + var resLen = 0, centerIndex = 0 + for (i, v) in p.enumerated() { + if v > resLen { + resLen = v + centerIndex = i + } + } + let resIdx = (centerIndex - resLen) / 2 + let start = s.index(s.startIndex, offsetBy: resIdx) + let end = s.index(start, offsetBy: resLen) + return String(s[start.. Int { + var res = 0 + let chars = Array(s) + + for i in 0.. Int { + var res = 0 + let charSet = Set(s) + let chars = Array(s) + + for c in charSet { + var count = 0, l = 0 + + for r in 0.. k { + if chars[l] == c { + count -= 1 + } + l += 1 + } + + res = max(res, r - l + 1) + } + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -563,6 +617,30 @@ class Solution { } ``` +```swift +class Solution { + func characterReplacement(_ s: String, _ k: Int) -> Int { + var count = [Character: Int]() + var res = 0 + var l = 0, maxf = 0 + let chars = Array(s) + + for r in 0.. k { + count[chars[l], default: 0] -= 1 + l += 1 + } + res = max(res, r - l + 1) + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/longest-substring-without-duplicates.md b/articles/longest-substring-without-duplicates.md index a37747ed3..3d197dc21 100644 --- a/articles/longest-substring-without-duplicates.md +++ b/articles/longest-substring-without-duplicates.md @@ -137,6 +137,27 @@ class Solution { } ``` +```kotlin +class Solution { + func lengthOfLongestSubstring(_ s: String) -> Int { + var res = 0 + let chars = Array(s) + + for i in 0..() + for j in i.. Int { + var charSet = Set() + var l = 0, res = 0 + let chars = Array(s) + + for r in 0.. Int { + var mp = [Character: Int]() + var l = 0, res = 0 + let chars = Array(s) + + for r in 0.. TreeNode? { + guard let root = root, let p = p, let q = q else { + return nil + } + + if max(p.val, q.val) < root.val { + return lowestCommonAncestor(root.left, p, q) + } else if min(p.val, q.val) > root.val { + return lowestCommonAncestor(root.right, p, q) + } else { + return root + } + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -436,6 +468,41 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init(_ val: Int) { + * self.val = val + * self.left = nil + * self.right = nil + * } + * } + */ + +class Solution { + func lowestCommonAncestor(_ root: TreeNode?, _ p: TreeNode?, _ q: TreeNode?) -> TreeNode? { + var cur = root + + while let node = cur { + if let p = p, let q = q { + if p.val > node.val && q.val > node.val { + cur = node.right + } else if p.val < node.val && q.val < node.val { + cur = node.left + } else { + return node + } + } + } + return nil + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/lru-cache.md b/articles/lru-cache.md index d93c79886..2bd939f9c 100644 --- a/articles/lru-cache.md +++ b/articles/lru-cache.md @@ -279,6 +279,46 @@ class LRUCache(capacity: Int) { } ``` +```swift +class LRUCache { + private var cache: [(Int, Int)] + private let capacity: Int + + init(_ capacity: Int) { + self.cache = [] + self.capacity = capacity + } + + func get(_ key: Int) -> Int { + for i in 0.. Int { + if let node = cache[key] { + remove(node) + insert(node) + return node.val + } + return -1 + } + + func put(_ key: Int, _ value: Int) { + if let node = cache[key] { + remove(node) + } + let newNode = Node(key, value) + cache[key] = newNode + insert(newNode) + + if cache.count > cap { + if let lru = left.next { + remove(lru) + cache.removeValue(forKey: lru.key) + } + } + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -1002,6 +1112,45 @@ class LRUCache(capacity: Int) { } ``` +```swift +class LRUCache { + private var capacity: Int + private var cache: [Int: Int] = [:] + private var keyOrder: [Int] = [] + + init(_ capacity: Int) { + self.capacity = capacity + } + + func get(_ key: Int) -> Int { + if let value = cache[key] { + if let index = keyOrder.firstIndex(of: key) { + keyOrder.remove(at: index) + } + keyOrder.append(key) + return value + } + return -1 + } + + func put(_ key: Int, _ value: Int) { + if cache[key] != nil { + if let index = keyOrder.firstIndex(of: key) { + keyOrder.remove(at: index) + } + } else if cache.count >= capacity { + if let lruKey = keyOrder.first { + cache.removeValue(forKey: lruKey) + keyOrder.removeFirst() + } + } + + cache[key] = value + keyOrder.append(key) + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/max-area-of-island.md b/articles/max-area-of-island.md index 22f9f8b53..cb69ca56d 100644 --- a/articles/max-area-of-island.md +++ b/articles/max-area-of-island.md @@ -232,6 +232,34 @@ class Solution { } ``` +```swift +class Solution { + func maxAreaOfIsland(_ grid: [[Int]]) -> Int { + let ROWS = grid.count + let COLS = grid[0].count + var visit = Set<[Int]>() + var grid = grid + + func dfs(_ r: Int, _ c: Int) -> Int { + if (r < 0 || r == ROWS || c < 0 || c == COLS || + grid[r][c] == 0 || visit.contains([r, c])) { + return 0 + } + visit.insert([r, c]) + return 1 + dfs(r + 1, c) + dfs(r - 1, c) + dfs(r, c + 1) + dfs(r, c - 1) + } + + var area = 0 + for r in 0.. Int { + let directions = [[1, 0], [-1, 0], [0, 1], [0, -1]] + let ROWS = grid.count + let COLS = grid[0].count + var grid = grid + var area = 0 + + func bfs(_ r: Int, _ c: Int) -> Int { + var queue = Deque<(Int, Int)>() + grid[r][c] = 0 + queue.append((r, c)) + var res = 1 + + while !queue.isEmpty { + let (row, col) = queue.popFirst()! + for dir in directions { + let nr = row + dir[0] + let nc = col + dir[1] + if nr < 0 || nc < 0 || nr >= ROWS || nc >= COLS || grid[nr][nc] == 0 { + continue + } + queue.append((nr, nc)) + grid[nr][nc] = 0 + res += 1 + } + } + return res + } + + for r in 0.. Int { + if parent[node] != node { + parent[node] = find(parent[node]) + } + return parent[node] + } + + func union(_ u: Int, _ v: Int) -> Bool { + let pu = find(u) + let pv = find(v) + if pu == pv { + return false + } + if size[pu] >= size[pv] { + size[pu] += size[pv] + parent[pv] = pu + } else { + size[pv] += size[pu] + parent[pu] = pv + } + return true + } + + func getSize(_ node: Int) -> Int { + let par = find(node) + return size[par] + } +} + +class Solution { + func maxAreaOfIsland(_ grid: [[Int]]) -> Int { + var grid = grid + let ROWS = grid.count + let COLS = grid[0].count + let dsu = DSU(ROWS * COLS) + + func index(_ r: Int, _ c: Int) -> Int { + return r * COLS + c + } + + let directions = [(1, 0), (-1, 0), (0, 1), (0, -1)] + var area = 0 + + for r in 0..= ROWS || nc >= COLS || grid[nr][nc] == 0 { + continue + } + dsu.union(index(r, c), index(nr, nc)) + } + area = max(area, dsu.getSize(index(r, c))) + } + } + } + + return area + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/max-water-container.md b/articles/max-water-container.md index dfd046f07..bb1ea6083 100644 --- a/articles/max-water-container.md +++ b/articles/max-water-container.md @@ -110,6 +110,20 @@ class Solution { } ``` +```swift +class Solution { + func maxArea(_ heights: [Int]) -> Int { + var res = 0 + for i in 0.. Int { + var l = 0, r = heights.count - 1 + var res = 0 + + while l < r { + let area = min(heights[l], heights[r]) * (r - l) + res = max(res, area) + if heights[l] <= heights[r] { + l += 1 + } else { + r -= 1 + } + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/maximum-product-subarray.md b/articles/maximum-product-subarray.md index 5f5f0e299..f163b341f 100644 --- a/articles/maximum-product-subarray.md +++ b/articles/maximum-product-subarray.md @@ -137,6 +137,25 @@ class Solution { } ``` +```swift +class Solution { + func maxProduct(_ nums: [Int]) -> Int { + var res = nums[0] + + for i in 0.. Int { + var A = [[Int]]() + var cur = [Int]() + var res = Int.min + + for num in nums { + res = max(res, num) + if num == 0 { + if !cur.isEmpty { + A.append(cur) + } + cur = [] + } else { + cur.append(num) + } + } + + if !cur.isEmpty { + A.append(cur) + } + + for sub in A { + let negsCount = sub.filter { $0 < 0 }.count + var prod = 1 + var need = negsCount % 2 == 0 ? negsCount : negsCount - 1 + var negs = 0 + var j = 0 + + for i in 0.. need { + prod /= sub[j] + if sub[j] < 0 { + negs -= 1 + } + j += 1 + } + } + if j <= i { + res = max(res, prod) + } + } + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -642,6 +714,23 @@ class Solution { } ``` +```swift +class Solution { + func maxProduct(_ nums: [Int]) -> Int { + var res = nums[0] + var curMin = 1, curMax = 1 + + for num in nums { + let tmp = curMax * num + curMax = max(num * curMax, num * curMin, num) + curMin = min(tmp, num * curMin, num) + res = max(res, curMax) + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -791,6 +880,23 @@ class Solution { } ``` +```swift +class Solution { + func maxProduct(_ nums: [Int]) -> Int { + let n = nums.count + var res = nums[0] + var prefix = 0, suffix = 0 + + for i in 0.. Int { + let n = nums.count + var res = nums[0] + + for i in 0.. Int { + func dfs(_ i: Int, _ flag: Bool) -> Int { + if i == nums.count { + return flag ? 0 : Int.min + } + + if flag { + return max(0, nums[i] + dfs(i + 1, true)) + } + + return max(dfs(i + 1, false), nums[i] + dfs(i + 1, true)) + } + + return dfs(0, false) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -449,6 +488,33 @@ class Solution { } ``` +```swift +class Solution { + func maxSubArray(_ nums: [Int]) -> Int { + var memo = Array(repeating: [Int?](repeating: nil, count: 2), count: nums.count + 1) + + func dfs(_ i: Int, _ flag: Bool) -> Int { + if i == nums.count { + return flag ? 0 : Int.min + } + if let value = memo[i][flag ? 1 : 0] { + return value + } + + if flag { + memo[i][flag ? 1 : 0] = max(0, nums[i] + dfs(i + 1, true)) + } else { + memo[i][flag ? 1 : 0] = max(dfs(i + 1, false), nums[i] + dfs(i + 1, true)) + } + + return memo[i][flag ? 1 : 0]! + } + + return dfs(0, false) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -594,6 +660,24 @@ class Solution { } ``` +```swift +class Solution { + func maxSubArray(_ nums: [Int]) -> Int { + let n = nums.count + var dp = Array(repeating: [0, 0], count: n) + dp[n - 1][1] = nums[n - 1] + dp[n - 1][0] = nums[n - 1] + + for i in (0.. Int { + var dp = nums + + for i in 1.. Int { + var maxSub = nums[0] + var curSum = 0 + + for num in nums { + if curSum < 0 { + curSum = 0 + } + curSum += num + maxSub = max(maxSub, curSum) + } + + return maxSub + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -1092,6 +1209,39 @@ class Solution { } ``` +```swift +class Solution { + func maxSubArray(_ nums: [Int]) -> Int { + + func dfs(_ l: Int, _ r: Int) -> Int { + if l > r { + return Int.min + } + + let m = (l + r) / 2 + var leftSum = 0 + var rightSum = 0 + var curSum = 0 + + for i in stride(from: m - 1, through: l, by: -1) { + curSum += nums[i] + leftSum = max(leftSum, curSum) + } + + curSum = 0 + for i in stride(from: m + 1, to: r + 1, by: 1) { + curSum += nums[i] + rightSum = max(rightSum, curSum) + } + + return max(dfs(l, m - 1), dfs(m + 1, r), leftSum + nums[m] + rightSum) + } + + return dfs(0, nums.count - 1) + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/median-of-two-sorted-arrays.md b/articles/median-of-two-sorted-arrays.md index 6fb01b6af..3ac051111 100644 --- a/articles/median-of-two-sorted-arrays.md +++ b/articles/median-of-two-sorted-arrays.md @@ -127,6 +127,22 @@ class Solution { } ``` +```swift +class Solution { + func findMedianSortedArrays(_ nums1: [Int], _ nums2: [Int]) -> Double { + var merged = nums1 + nums2 + merged.sort() + + let totalLen = merged.count + if totalLen % 2 == 0 { + return (Double(merged[totalLen / 2 - 1]) + Double(merged[totalLen / 2])) / 2.0 + } else { + return Double(merged[totalLen / 2]) + } + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -391,6 +407,41 @@ class Solution { } ``` +```kotlin +class Solution { + func findMedianSortedArrays(_ nums1: [Int], _ nums2: [Int]) -> Double { + let len1 = nums1.count, len2 = nums2.count + var i = 0, j = 0 + var median1 = 0, median2 = 0 + + for _ in 0..<(len1 + len2) / 2 + 1 { + median2 = median1 + if i < len1 && j < len2 { + if nums1[i] > nums2[j] { + median1 = nums2[j] + j += 1 + } else { + median1 = nums1[i] + i += 1 + } + } else if i < len1 { + median1 = nums1[i] + i += 1 + } else { + median1 = nums2[j] + j += 1 + } + } + + if (len1 + len2) % 2 == 1 { + return Double(median1) + } else { + return (Double(median1) + Double(median2)) / 2.0 + } + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -653,12 +704,44 @@ class Solution { } ``` +```swift +class Solution { + func getKth(_ a: [Int], _ m: Int, _ b: [Int], _ n: Int, _ k: Int, _ aStart: Int = 0, _ bStart: Int = 0) -> Int { + if m > n { + return getKth(b, n, a, m, k, bStart, aStart) + } + if m == 0 { + return b[bStart + k - 1] + } + if k == 1 { + return min(a[aStart], b[bStart]) + } + + let i = min(m, k / 2) + let j = min(n, k / 2) + + if a[aStart + i - 1] > b[bStart + j - 1] { + return getKth(a, m, b, n - j, k - j, aStart, bStart + j) + } else { + return getKth(a, m - i, b, n, k - i, aStart + i, bStart) + } + } + + func findMedianSortedArrays(_ nums1: [Int], _ nums2: [Int]) -> Double { + let left = (nums1.count + nums2.count + 1) / 2 + let right = (nums1.count + nums2.count + 2) / 2 + return (Double(getKth(nums1, nums1.count, nums2, nums2.count, left)) + + Double(getKth(nums1, nums1.count, nums2, nums2.count, right))) / 2.0 + } +} +``` + ::tabs-end ### Time & Space Complexity * Time complexity: $O(\log (m + n))$ -* Space complexity: $O(\log (m + n))$ +* Space complexity: $O(\log (m + n))$ for recursion stack. > Where $n$ is the length of $nums1$ and $m$ is the length of $nums2$. @@ -969,6 +1052,44 @@ class Solution { } ``` +```swift +class Solution { + func findMedianSortedArrays(_ nums1: [Int], _ nums2: [Int]) -> Double { + var A = nums1, B = nums2 + if A.count > B.count { + swap(&A, &B) + } + + let total = A.count + B.count + let half = total / 2 + var l = 0 + var r = A.count + + while true { + let i = (l + r) / 2 + let j = half - i + + let Aleft = i > 0 ? Double(A[i - 1]) : -Double.infinity + let Aright = i < A.count ? Double(A[i]) : Double.infinity + let Bleft = j > 0 ? Double(B[j - 1]) : -Double.infinity + let Bright = j < B.count ? Double(B[j]) : Double.infinity + + if Aleft <= Bright && Bleft <= Aright { + if total % 2 == 1 { + return min(Aright, Bright) + } else { + return (max(Aleft, Bleft) + min(Aright, Bright)) / 2.0 + } + } else if Aleft > Bright { + r = i - 1 + } else { + l = i + 1 + } + } + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/meeting-schedule-ii.md b/articles/meeting-schedule-ii.md index ce53b1e92..afd50a48e 100644 --- a/articles/meeting-schedule-ii.md +++ b/articles/meeting-schedule-ii.md @@ -193,6 +193,34 @@ class Solution { } ``` +```swift +/** + * Definition of Interval: + * class Interval { + * var start: Int + * var end: Int + * init(start: Int, end: Int) { + * self.start = start + * self.end = end + * } + * } + */ + +class Solution { + func minMeetingRooms(_ intervals: [Interval]) -> Int { + let sortedIntervals = intervals.sorted { $0.start < $1.start } + var minHeap = Heap() + for interval in sortedIntervals { + if !minHeap.isEmpty, let earliest = minHeap.min!, earliest <= interval.start { + minHeap.removeMin() + } + minHeap.insert(interval.end) + } + return minHeap.count + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -414,6 +442,37 @@ class Solution { } ``` +```swift +/** + * Definition of Interval: + * class Interval { + * var start: Int + * var end: Int + * init(start: Int, end: Int) { + * self.start = start + * self.end = end + * } + * } + */ + +class Solution { + func minMeetingRooms(_ intervals: [Interval]) -> Int { + var mp = [Int: Int]() + for interval in intervals { + mp[interval.start, default: 0] += 1 + mp[interval.end, default: 0] -= 1 + } + var prev = 0 + var res = 0 + for key in mp.keys.sorted() { + prev += mp[key]! + res = max(res, prev) + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -689,6 +748,40 @@ class Solution { } ``` +```swift +/** + * Definition of Interval: + * class Interval { + * var start: Int + * var end: Int + * init(start: Int, end: Int) { + * self.start = start + * self.end = end + * } + * } + */ + +class Solution { + func minMeetingRooms(_ intervals: [Interval]) -> Int { + let starts = intervals.map { $0.start }.sorted() + let ends = intervals.map { $0.end }.sorted() + + var res = 0, count = 0, s = 0, e = 0 + while s < intervals.count { + if starts[s] < ends[e] { + count += 1 + s += 1 + } else { + count -= 1 + e += 1 + } + res = max(res, count) + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -929,6 +1022,47 @@ class Solution { } ``` +```swift +/** + * Definition of Interval: + * class Interval { + * var start: Int + * var end: Int + * init(start: Int, end: Int) { + * self.start = start + * self.end = end + * } + * } + */ + +class Solution { + func minMeetingRooms(_ intervals: [Interval]) -> Int { + var times = [(Int, Int)]() + for interval in intervals { + times.append((interval.start, 1)) + times.append((interval.end, -1)) + } + + times.sort { + if $0.0 != $1.0 { + return $0.0 < $1.0 + } else { + return $0.1 < $1.1 + } + } + + var count = 0 + var res = 0 + for t in times { + count += t.1 + res = max(res, count) + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/meeting-schedule.md b/articles/meeting-schedule.md index 735df876a..226a6a70f 100644 --- a/articles/meeting-schedule.md +++ b/articles/meeting-schedule.md @@ -205,6 +205,36 @@ class Solution { } ``` +```swift +/** + * Definition of Interval: + * class Interval { + * var start: Int + * var end: Int + * init(start: Int, end: Int) { + * self.start = start + * self.end = end + * } + * } + */ + +class Solution { + func canAttendMeetings(_ intervals: [Interval]) -> Bool { + let n = intervals.count + for i in 0.. max(A.start, B.start) { + return false + } + } + } + return true + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -400,6 +430,32 @@ class Solution { } ``` +```swift +/** + * Definition of Interval: + * class Interval { + * var start: Int + * var end: Int + * init(start: Int, end: Int) { + * self.start = start + * self.end = end + * } + * } + */ + +class Solution { + func canAttendMeetings(_ intervals: [Interval]) -> Bool { + let sortedIntervals = intervals.sorted { $0.start < $1.start } + for i in 1.. sortedIntervals[i].start { + return false + } + } + return true + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/merge-intervals.md b/articles/merge-intervals.md index 4ff97b569..100d894b6 100644 --- a/articles/merge-intervals.md +++ b/articles/merge-intervals.md @@ -164,6 +164,28 @@ class Solution { } ``` +```swift +class Solution { + func merge(_ intervals: [[Int]]) -> [[Int]] { + let intervals = intervals.sorted { $0[0] < $1[0] } + var output: [[Int]] = [intervals[0]] + + for interval in intervals { + let start = interval[0] + let end = interval[1] + var lastEnd = output.last![1] + + if start <= lastEnd { + output[output.count - 1][1] = max(lastEnd, end) + } else { + output.append([start, end]) + } + } + return output + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -383,6 +405,38 @@ class Solution { } ``` +```swift +class Solution { + func merge(_ intervals: [[Int]]) -> [[Int]] { + var mp = [Int: Int]() + + for interval in intervals { + let start = interval[0] + let end = interval[1] + mp[start, default: 0] += 1 + mp[end, default: 0] -= 1 + } + + var res = [[Int]]() + var interval = [Int]() + var have = 0 + + for i in mp.keys.sorted() { + if interval.isEmpty { + interval.append(i) + } + have += mp[i, default: 0] + if have == 0 { + interval.append(i) + res.append(interval) + interval = [] + } + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -678,6 +732,44 @@ class Solution { } ``` +```swift +class Solution { + func merge(_ intervals: [[Int]]) -> [[Int]] { + let maxVal = intervals.map { $0[0] }.max() ?? 0 + var mp = [Int](repeating: 0, count: maxVal + 1) + for interval in intervals { + let start = interval[0] + let end = interval[1] + mp[start] = max(end + 1, mp[start]) + } + + var res = [[Int]]() + var have = -1 + var intervalStart = -1 + + for i in 0.. ListNode? { + var nodes: [Int] = [] + + for list in lists { + var lst = list + while lst != nil { + nodes.append(lst!.val) + lst = lst?.next + } + } + + nodes.sort() + + let dummy = ListNode(0) + var cur = dummy + for node in nodes { + cur.next = ListNode(node) + cur = cur.next! + } + + return dummy.next + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -510,6 +547,47 @@ class Solution { } ``` +```swift +/** + * Definition for singly-linked list. + * public class ListNode { + * public var val: Int + * public var next: ListNode? + * public init() { self.val = 0; self.next = nil; } + * public init(_ val: Int) { self.val = val; self.next = nil; } + * public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; } + * } + */ +class Solution { + func mergeKLists(_ lists: [ListNode?]) -> ListNode? { + var lists = lists + let dummy = ListNode(0) + var cur = dummy + + while true { + var minNodeIndex: Int? = nil + for i in 0.. ListNode? { + if lists.isEmpty { + return nil + } + + var lists = lists + for i in 1.. ListNode? { + let dummy = ListNode(0) + var tail = dummy + var l1 = l1, l2 = l2 + + while l1 != nil && l2 != nil { + if l1!.val < l2!.val { + tail.next = l1 + l1 = l1?.next + } else { + tail.next = l2 + l2 = l2?.next + } + tail = tail.next! + } + + if l1 != nil { + tail.next = l1 + } + if l2 != nil { + tail.next = l2 + } + + return dummy.next + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -1157,6 +1288,60 @@ class Solution { } ``` +```swift +/** + * Definition for singly-linked list. + * public class ListNode { + * public var val: Int + * public var next: ListNode? + * public init() { self.val = 0; self.next = nil; } + * public init(_ val: Int) { self.val = val; self.next = nil; } + * public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; } + * } + */ +struct NodeWrapper: Comparable { + let node: ListNode + + init(_ node: ListNode) { + self.node = node + } + + static func < (lhs: NodeWrapper, rhs: NodeWrapper) -> Bool { + return lhs.node.val < rhs.node.val + } + + static func == (lhs: NodeWrapper, rhs: NodeWrapper) -> Bool { + return lhs.node.val == rhs.node.val + } +} + +class Solution { + func mergeKLists(_ lists: [ListNode?]) -> ListNode? { + var heap = Heap() + + for list in lists { + if let node = list { + heap.insert(NodeWrapper(node)) + } + } + + let dummy = ListNode(0) + var tail = dummy + + while let wrapper = heap.popMin() { + tail.next = wrapper.node + tail = tail.next! + + if let next = wrapper.node.next { + heap.insert(NodeWrapper(next)) + } + } + + return dummy.next + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -1190,14 +1375,17 @@ class Solution: return None if l == r: return lists[l] + mid = l + (r - l) // 2 left = self.divide(lists, l, mid) right = self.divide(lists, mid + 1, r) + return self.conquer(left, right) def conquer(self, l1, l2): dummy = ListNode(0) curr = dummy + while l1 and l2: if l1.val <= l2.val: curr.next = l1 @@ -1206,10 +1394,12 @@ class Solution: curr.next = l2 l2 = l2.next curr = curr.next + if l1: curr.next = l1 else: curr.next = l2 + return dummy.next ``` @@ -1240,9 +1430,11 @@ class Solution { if (l == r) { return lists[l]; } + int mid = l + (r - l) / 2; ListNode left = divide(lists, l, mid); ListNode right = divide(lists, mid + 1, r); + return conquer(left, right); } @@ -1302,15 +1494,18 @@ private: if (l == r) { return lists[l]; } + int mid = l + (r - l) / 2; ListNode* left = divide(lists, l, mid); ListNode* right = divide(lists, mid + 1, r); + return conquer(left, right); } ListNode* conquer(ListNode* l1, ListNode* l2) { ListNode dummy(0); ListNode* curr = &dummy; + while (l1 && l2) { if (l1->val <= l2->val) { curr->next = l1; @@ -1321,11 +1516,13 @@ private: } curr = curr->next; } + if (l1) { curr->next = l1; } else { curr->next = l2; } + return dummy.next; } }; @@ -1367,9 +1564,11 @@ class Solution { if (l === r) { return lists[l]; } + const mid = Math.floor(l + (r - l) / 2); const left = this.divide(lists, l, mid); const right = this.divide(lists, mid + 1, r); + return this.conquer(left, right); } @@ -1381,6 +1580,7 @@ class Solution { conquer(l1, l2) { const dummy = new ListNode(0); let curr = dummy; + while (l1 && l2) { if (l1.val <= l2.val) { curr.next = l1; @@ -1391,6 +1591,7 @@ class Solution { } curr = curr.next; } + curr.next = l1 ? l1 : l2; return dummy.next; } @@ -1425,9 +1626,11 @@ public class Solution { if (l == r) { return lists[l]; } + int mid = l + (r - l) / 2; ListNode left = Divide(lists, l, mid); ListNode right = Divide(lists, mid + 1, r); + return Conquer(left, right); } @@ -1479,15 +1682,18 @@ func divide(lists []*ListNode, left, right int) *ListNode { if left == right { return lists[left] } + mid := left + (right-left)/2 l1 := divide(lists, left, mid) l2 := divide(lists, mid+1, right) + return conquer(l1, l2) } func conquer(l1, l2 *ListNode) *ListNode { dummy := &ListNode{} curr := dummy + for l1 != nil && l2 != nil { if l1.Val <= l2.Val { curr.Next = l1 @@ -1498,11 +1704,13 @@ func conquer(l1, l2 *ListNode) *ListNode { } curr = curr.Next } + if l1 != nil { curr.Next = l1 } else { curr.Next = l2 } + return dummy.Next } ``` @@ -1526,9 +1734,11 @@ class Solution { private fun divide(lists: Array, left: Int, right: Int): ListNode? { if (left > right) return null if (left == right) return lists[left] + val mid = left + (right - left) / 2 val l1 = divide(lists, left, mid) val l2 = divide(lists, mid + 1, right) + return conquer(l1, l2) } @@ -1537,6 +1747,7 @@ class Solution { var curr = dummy var list1 = l1 var list2 = l2 + while (list1 != null && list2 != null) { if (list1.`val` <= list2.`val`) { curr.next = list1 @@ -1547,12 +1758,68 @@ class Solution { } curr = curr.next!! } + curr.next = list1 ?: list2 return dummy.next } } ``` +```swift +/** + * Definition for singly-linked list. + * public class ListNode { + * public var val: Int + * public var next: ListNode? + * public init() { self.val = 0; self.next = nil; } + * public init(_ val: Int) { self.val = val; self.next = nil; } + * public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; } + * } + */ +class Solution { + func mergeKLists(_ lists: [ListNode?]) -> ListNode? { + if lists.isEmpty { + return nil + } + return divide(lists, 0, lists.count - 1) + } + + private func divide(_ lists: [ListNode?], _ l: Int, _ r: Int) -> ListNode? { + if l > r { + return nil + } + if l == r { + return lists[l] + } + + let mid = l + (r - l) / 2 + let left = divide(lists, l, mid) + let right = divide(lists, mid + 1, r) + return conquer(left, right) + } + + private func conquer(_ l1: ListNode?, _ l2: ListNode?) -> ListNode? { + let dummy = ListNode(0) + var curr = dummy + var l1 = l1, l2 = l2 + + while let node1 = l1, let node2 = l2 { + if node1.val <= node2.val { + curr.next = node1 + l1 = node1.next + } else { + curr.next = node2 + l2 = node2.next + } + curr = curr.next! + } + + curr.next = l1 ?? l2 + return dummy.next + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -1602,10 +1869,12 @@ class Solution: tail.next = l2 l2 = l2.next tail = tail.next + if l1: tail.next = l1 if l2: tail.next = l2 + return dummy.next ``` @@ -1653,12 +1922,14 @@ public class Solution { } tail = tail.next; } + if (l1 != null) { tail.next = l1; } if (l2 != null) { tail.next = l2; } + return dummy.next; } } @@ -1710,12 +1981,14 @@ private: } tail = tail->next; } + if (l1) { tail->next = l1; } if (l2) { tail->next = l2; } + return dummy.next; } }; @@ -1762,6 +2035,7 @@ class Solution { mergeList(l1, l2) { const dummy = new ListNode(0); let curr = dummy; + while (l1 && l2) { if (l1.val <= l2.val) { curr.next = l1; @@ -1772,6 +2046,7 @@ class Solution { } curr = curr.next; } + curr.next = l1 ? l1 : l2; return dummy.next; } @@ -1823,12 +2098,14 @@ public class Solution { } tail = tail.next; } + if (l1 != null) { tail.next = l1; } if (l2 != null) { tail.next = l2; } + return dummy.next; } } @@ -1876,11 +2153,13 @@ func mergeList(l1, l2 *ListNode) *ListNode { } tail = tail.Next } + if l1 != nil { tail.Next = l1 } else { tail.Next = l2 } + return dummy.Next } ``` @@ -1928,12 +2207,69 @@ class Solution { } tail = tail.next!! } + tail.next = list1 ?: list2 return dummy.next } } ``` +```swift +/** + * Definition for singly-linked list. + * public class ListNode { + * public var val: Int + * public var next: ListNode? + * public init() { self.val = 0; self.next = nil; } + * public init(_ val: Int) { self.val = val; self.next = nil; } + * public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; } + * } + */ +class Solution { + func mergeKLists(_ lists: [ListNode?]) -> ListNode? { + if lists.isEmpty { + return nil + } + + var lists = lists + + while lists.count > 1 { + var mergedLists: [ListNode?] = [] + + for i in stride(from: 0, to: lists.count, by: 2) { + let l1 = lists[i] + let l2 = i + 1 < lists.count ? lists[i + 1] : nil + mergedLists.append(mergeList(l1, l2)) + } + + lists = mergedLists + } + + return lists[0] + } + + private func mergeList(_ l1: ListNode?, _ l2: ListNode?) -> ListNode? { + let dummy = ListNode(0) + var tail = dummy + var l1 = l1, l2 = l2 + + while let node1 = l1, let node2 = l2 { + if node1.val < node2.val { + tail.next = node1 + l1 = node1.next + } else { + tail.next = node2 + l2 = node2.next + } + tail = tail.next! + } + + tail.next = l1 ?? l2 + return dummy.next + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/merge-triplets-to-form-target.md b/articles/merge-triplets-to-form-target.md index 4fe080b4c..268d8ae9d 100644 --- a/articles/merge-triplets-to-form-target.md +++ b/articles/merge-triplets-to-form-target.md @@ -138,6 +138,27 @@ class Solution { } ``` +```swift +class Solution { + func mergeTriplets(_ triplets: [[Int]], _ target: [Int]) -> Bool { + var good = Set() + + for t in triplets { + if t[0] > target[0] || t[1] > target[1] || t[2] > target[2] { + continue + } + for (i, v) in t.enumerated() { + if v == target[i] { + good.insert(i) + } + } + } + + return good.count == 3 + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -268,6 +289,28 @@ class Solution { } ``` +```swift +class Solution { + func mergeTriplets(_ triplets: [[Int]], _ target: [Int]) -> Bool { + var x = false, y = false, z = false + + for t in triplets { + if t[0] <= target[0] && t[1] <= target[1] && t[2] <= target[2] { + if t[0] == target[0] { x = true } + if t[1] == target[1] { y = true } + if t[2] == target[2] { z = true } + } + + if x && y && z { + return true + } + } + + return false + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/merge-two-sorted-linked-lists.md b/articles/merge-two-sorted-linked-lists.md index bffc3e16f..b65407ade 100644 --- a/articles/merge-two-sorted-linked-lists.md +++ b/articles/merge-two-sorted-linked-lists.md @@ -203,6 +203,36 @@ class Solution { } ``` +```swift +/** + * Definition for singly-linked list. + * public class ListNode { + * public var val: Int + * public var next: ListNode? + * public init() { self.val = 0; self.next = nil; } + * public init(_ val: Int) { self.val = val; self.next = nil; } + * public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; } + * } + */ +class Solution { + func mergeTwoLists(_ list1: ListNode?, _ list2: ListNode?) -> ListNode? { + if list1 == nil { + return list2 + } + if list2 == nil { + return list1 + } + if list1!.val <= list2!.val { + list1!.next = mergeTwoLists(list1!.next, list2) + return list1 + } else { + list2!.next = mergeTwoLists(list1, list2!.next) + return list2 + } + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -473,6 +503,42 @@ class Solution { } ``` +```swift +/** + * Definition for singly-linked list. + * public class ListNode { + * public var val: Int + * public var next: ListNode? + * public init() { self.val = 0; self.next = nil; } + * public init(_ val: Int) { self.val = val; self.next = nil; } + * public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; } + * } + */ +class Solution { + func mergeTwoLists(_ list1: ListNode?, _ list2: ListNode?) -> ListNode? { + let dummy = ListNode(0) + var node = dummy + var l1 = list1 + var l2 = list2 + + while l1 != nil && l2 != nil { + if l1!.val < l2!.val { + node.next = l1 + l1 = l1?.next + } else { + node.next = l2 + l2 = l2?.next + } + node = node.next! + } + + node.next = l1 ?? l2 + + return dummy.next + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/min-cost-climbing-stairs.md b/articles/min-cost-climbing-stairs.md index 3c7139726..9433d007b 100644 --- a/articles/min-cost-climbing-stairs.md +++ b/articles/min-cost-climbing-stairs.md @@ -118,6 +118,21 @@ class Solution { } ``` +```swift +class Solution { + func minCostClimbingStairs(_ cost: [Int]) -> Int { + func dfs(_ i: Int) -> Int { + if i >= cost.count { + return 0 + } + return cost[i] + min(dfs(i + 1), dfs(i + 2)) + } + + return min(dfs(0), dfs(1)) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -291,6 +306,27 @@ class Solution { } ``` +```swift +class Solution { + func minCostClimbingStairs(_ cost: [Int]) -> Int { + var memo = Array(repeating: -1, count: cost.count) + + func dfs(_ i: Int) -> Int { + if i >= cost.count { + return 0 + } + if memo[i] != -1 { + return memo[i] + } + memo[i] = cost[i] + min(dfs(i + 1), dfs(i + 2)) + return memo[i] + } + + return min(dfs(0), dfs(1)) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -423,6 +459,22 @@ class Solution { } ``` +```swift +class Solution { + func minCostClimbingStairs(_ cost: [Int]) -> Int { + let n = cost.count + var dp = Array(repeating: 0, count: n + 1) + + for i in 2...n { + dp[i] = min(dp[i - 1] + cost[i - 1], + dp[i - 2] + cost[i - 2]) + } + + return dp[n] + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -523,6 +575,17 @@ class Solution { } ``` +```swift +class Solution { + func minCostClimbingStairs(_ cost: inout [Int]) -> Int { + for i in stride(from: cost.count - 3, through: 0, by: -1) { + cost[i] += min(cost[i + 1], cost[i + 2]) + } + return min(cost[0], cost[1]) + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/min-cost-to-connect-points.md b/articles/min-cost-to-connect-points.md index 8e9e5226a..6688ee3a1 100644 --- a/articles/min-cost-to-connect-points.md +++ b/articles/min-cost-to-connect-points.md @@ -45,7 +45,7 @@ class Solution: ``` ```java -public class DSU { +class DSU { int[] Parent, Size; public DSU(int n) { @@ -398,6 +398,68 @@ class Solution { } ``` +```swift +class DSU { + private var parent: [Int] + private var size: [Int] + + init(_ n: Int) { + parent = Array(0...n) + size = Array(repeating: 1, count: n + 1) + } + + func find(_ node: Int) -> Int { + if parent[node] != node { + parent[node] = find(parent[node]) + } + return parent[node] + } + + func union(_ u: Int, _ v: Int) -> Bool { + let pu = find(u) + let pv = find(v) + if pu == pv { + return false + } + if size[pu] < size[pv] { + parent[pu] = pv + size[pv] += size[pu] + } else { + parent[pv] = pu + size[pu] += size[pv] + } + return true + } +} + +class Solution { + func minCostConnectPoints(_ points: [[Int]]) -> Int { + let n = points.count + let dsu = DSU(n) + var edges = [(Int, Int, Int)]() + + for i in 0.. Bool { + return lhs.cost < rhs.cost + } +} + +class Solution { + func minCostConnectPoints(_ points: [[Int]]) -> Int { + let N = points.count + var adj = [Int: [(Int, Int)]]() + + for i in 0..() + var minHeap = Heap() + minHeap.insert(Item(cost: 0, node: 0)) + + while visit.count < N { + guard let item = minHeap.popMin() else { break } + let cost = item.cost + let i = item.node + + if visit.contains(i) { + continue + } + + res += cost + visit.insert(i) + + if let neighbors = adj[i] { + for (neiCost, nei) in neighbors { + if !visit.contains(nei) { + minHeap.insert(Item(cost: neiCost, node: nei)) + } + } + } + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -940,6 +1058,42 @@ class Solution { } ``` +```swift +class Solution { + func minCostConnectPoints(_ points: [[Int]]) -> Int { + let n = points.count + var node = 0 + var dist = Array(repeating: 100000000, count: n) + var visit = Array(repeating: false, count: n) + var edges = 0 + var res = 0 + + while edges < n - 1 { + visit[node] = true + var nextNode = -1 + + for i in 0.. [Int] { + var res = [Int]() + + for q in queries { + var cur = -1 + for interval in intervals { + let l = interval[0] + let r = interval[1] + + if l <= q && q <= r { + if cur == -1 || (r - l + 1) < cur { + cur = r - l + 1 + } + } + } + res.append(cur) + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity * Time complexity: $O(m * n)$ -* Space complexity: $O(1)$ +* Space complexity: + * $O(1)$ extra space. + * $O(m)$ space for the output array. > Where $m$ is the length of the array $queries$ and $n$ is the length of the array $intervals$. @@ -508,6 +535,78 @@ class Solution { } ``` +```swift +struct Event { + let time: Int + let type: Int // 0: interval start, 1: query, 2: interval end + let size: Int? // interval size for start/end events + let idx: Int? // index for interval (for start/end) or query index (for query) +} + +struct Item: Comparable { + let size: Int + let idx: Int + + static func < (lhs: Item, rhs: Item) -> Bool { + return lhs.size < rhs.size + } +} + +class Solution { + func minInterval(_ intervals: [[Int]], _ queries: [Int]) -> [Int] { + var events = [Event]() + + // Create events for intervals + for (idx, interval) in intervals.enumerated() { + let start = interval[0] + let end = interval[1] + let intervalSize = end - start + 1 + events.append(Event(time: start, type: 0, size: intervalSize, idx: idx)) + events.append(Event(time: end, type: 2, size: intervalSize, idx: idx)) + } + + // Create events for queries + for (i, q) in queries.enumerated() { + events.append(Event(time: q, type: 1, size: nil, idx: i)) + } + + // Sort by time and type (end before query) + events.sort { (a, b) in + if a.time != b.time { + return a.time < b.time + } + return a.type < b.type + } + + // Min heap storing [size, index] + var sizes = Heap() + var ans = Array(repeating: -1, count: queries.count) + var inactive = Array(repeating: false, count: intervals.count) + + for event in events { + if event.type == 0 { // Interval start + let intervalSize = event.size! + let idx = event.idx! + sizes.insert(Item(size: intervalSize, idx: idx)) + } else if event.type == 2 { // Interval end + let idx = event.idx! + inactive[idx] = true + } else { // Query + let queryIdx = event.idx! + while !sizes.isEmpty, inactive[sizes.min!.idx] { + sizes.removeMin() + } + if !sizes.isEmpty { + ans[queryIdx] = sizes.min!.size + } + } + } + + return ans + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -779,6 +878,44 @@ class Solution { } ``` +```swift +struct HeapItem: Comparable { + let size: Int + let end: Int + static func < (lhs: HeapItem, rhs: HeapItem) -> Bool { + if lhs.size == rhs.size { + return lhs.end < rhs.end + } + return lhs.size < rhs.size + } +} + +class Solution { + func minInterval(_ intervals: [[Int]], _ queries: [Int]) -> [Int] { + let sortedIntervals = intervals.sorted { $0[0] < $1[0] } + var minHeap = Heap() + var res = [Int: Int]() + var i = 0 + + for q in queries.sorted() { + while i < sortedIntervals.count && sortedIntervals[i][0] <= q { + let l = sortedIntervals[i][0] + let r = sortedIntervals[i][1] + minHeap.insert(HeapItem(size: r - l + 1, end: r)) + i += 1 + } + + while !minHeap.isEmpty, minHeap.min!.end < q { + minHeap.removeMin() + } + res[q] = minHeap.isEmpty ? -1 : minHeap.min!.size + } + + return queries.map { res[$0] ?? -1 } + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -871,7 +1008,7 @@ class Solution: ``` ```java -public class SegmentTree { +class SegmentTree { int n; int[] tree; int[] lazy; @@ -1471,11 +1608,120 @@ class Solution { } ``` +```swift +class SegmentTree { + let n: Int + var tree: [Int] + var lazy: [Int] + let INF = Int.max + + init(_ N: Int) { + self.n = N + self.tree = [Int](repeating: INF, count: 4 * N) + self.lazy = [Int](repeating: INF, count: 4 * N) + } + + // Propagate lazy value at tree index over range [lo, hi] + func propagate(_ treeidx: Int, _ lo: Int, _ hi: Int) { + if lazy[treeidx] != INF { + tree[treeidx] = min(tree[treeidx], lazy[treeidx]) + if lo != hi { + lazy[2 * treeidx + 1] = min(lazy[2 * treeidx + 1], lazy[treeidx]) + lazy[2 * treeidx + 2] = min(lazy[2 * treeidx + 2], lazy[treeidx]) + } + lazy[treeidx] = INF + } + } + + // Update the segment tree over range [left, right] with value val + func update(_ treeidx: Int, _ lo: Int, _ hi: Int, _ left: Int, _ right: Int, _ val: Int) { + propagate(treeidx, lo, hi) + if lo > right || hi < left { + return + } + if lo >= left && hi <= right { + lazy[treeidx] = min(lazy[treeidx], val) + propagate(treeidx, lo, hi) + return + } + let mid = (lo + hi) / 2 + update(2 * treeidx + 1, lo, mid, left, right, val) + update(2 * treeidx + 2, mid + 1, hi, left, right, val) + tree[treeidx] = min(tree[2 * treeidx + 1], tree[2 * treeidx + 2]) + } + + // Query the value at index idx in the original array + func query(_ treeidx: Int, _ lo: Int, _ hi: Int, _ idx: Int) -> Int { + propagate(treeidx, lo, hi) + if lo == hi { + return tree[treeidx] + } + let mid = (lo + hi) / 2 + if idx <= mid { + return query(2 * treeidx + 1, lo, mid, idx) + } else { + return query(2 * treeidx + 2, mid + 1, hi, idx) + } + } + + func update_range(_ left: Int, _ right: Int, _ val: Int) { + update(0, 0, n - 1, left, right, val) + } + + func query_point(_ idx: Int) -> Int { + return query(0, 0, n - 1, idx) + } +} + +class Solution { + func minInterval(_ intervals: [[Int]], _ queries: [Int]) -> [Int] { + var points = [Int]() + // Create events for intervals + for interval in intervals { + points.append(interval[0]) + points.append(interval[1]) + } + // Create events for queries + for q in queries { + points.append(q) + } + + // Compress the coordinates + let sortedPoints = Array(Set(points)).sorted() + var compress = [Int: Int]() + for (i, point) in sortedPoints.enumerated() { + compress[point] = i + } + + // Lazy Segment Tree + let segTree = SegmentTree(sortedPoints.count) + + for interval in intervals { + let start = compress[interval[0]]! + let end = compress[interval[1]]! + let length = interval[1] - interval[0] + 1 + segTree.update_range(start, end, length) + } + + var ans = [Int]() + for q in queries { + let idx = compress[q]! + // Query for minSize + let res = segTree.query_point(idx) + ans.append(res == segTree.INF ? -1 : res) + } + return ans + } +} +``` + ::tabs-end ### Time & Space Complexity * Time complexity: $O((n + m)\log k)$ -* Space complexity: $O(k)$ +* Space complexity: + * $O(k)$ extra space. + * $O(m)$ space for the output array. > Where $m$ is the length of the array $queries$, $n$ is the length of the array $intervals$ and $k$ is the number of unique points. \ No newline at end of file diff --git a/articles/minimum-stack.md b/articles/minimum-stack.md index 28527e995..29041a02c 100644 --- a/articles/minimum-stack.md +++ b/articles/minimum-stack.md @@ -278,6 +278,42 @@ class MinStack() { } ``` +```swift +class MinStack { + private var stack: [Int] = [] + + init() {} + + func push(_ val: Int) { + stack.append(val) + } + + func pop() { + stack.popLast() + } + + func top() -> Int { + return stack.last! + } + + func getMin() -> Int { + var tmp = [Int]() + var mini = stack.last! + + while !stack.isEmpty { + mini = min(mini, stack.last!) + tmp.append(stack.removeLast()) + } + + while !tmp.isEmpty { + stack.append(tmp.removeLast()) + } + + return mini + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -524,6 +560,34 @@ class MinStack() { } ``` +```swift +class MinStack { + private var stack: [Int] = [] + private var minStack: [Int] = [] + + init() {} + + func push(_ val: Int) { + stack.append(val) + let minVal = min(val, minStack.last ?? val) + minStack.append(minVal) + } + + func pop() { + stack.popLast() + minStack.popLast() + } + + func top() -> Int { + return stack.last! + } + + func getMin() -> Int { + return minStack.last! + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -543,14 +607,14 @@ class MinStack: self.min = float('inf') self.stack = [] - def push(self, x: int) -> None: + def push(self, val: int) -> None: if not self.stack: self.stack.append(0) - self.min = x + self.min = val else: - self.stack.append(x - self.min) - if x < self.min: - self.min = x + self.stack.append(val - self.min) + if val < self.min: + self.min = val def pop(self) -> None: if not self.stack: @@ -581,13 +645,13 @@ public class MinStack { stack = new Stack<>(); } - public void push(int x) { + public void push(int val) { if (stack.isEmpty()) { stack.push(0L); - min = x; + min = val; } else { - stack.push(x - min); - if (x < min) min = x; + stack.push(val - min); + if (val < min) min = val; } } @@ -621,9 +685,7 @@ private: std::stack stack; public: - MinStack() { - - } + MinStack() {} void push(int val) { if (stack.empty()) { @@ -755,14 +817,14 @@ func Constructor() MinStack { } } -func (this *MinStack) Push(x int) { +func (this *MinStack) Push(val int) { if len(this.stack) == 0 { this.stack = append(this.stack, 0) - this.min = x + this.min = val } else { - this.stack = append(this.stack, x - this.min) - if x < this.min { - this.min = x + this.stack = append(this.stack, val - this.min) + if val < this.min { + this.min = val } } } @@ -796,8 +858,8 @@ class MinStack() { private var min: Long = Long.MAX_VALUE private val stack = ArrayDeque() - fun push(x: Int) { - val valAsLong = x.toLong() + fun push(`val`: Int) { + val valAsLong = `val`.toLong() if (stack.isEmpty()) { stack.addLast(0L) min = valAsLong @@ -828,6 +890,48 @@ class MinStack() { } ``` +```swift +class MinStack { + private var minVal: Int = Int.max + private var stack: [Int] = [] + + init() {} + + func push(_ val: Int) { + if stack.isEmpty { + stack.append(0) + minVal = val + } else { + stack.append(val - minVal) + if val < minVal { + minVal = val + } + } + } + + func pop() { + if stack.isEmpty { + return + } + + let pop = stack.removeLast() + + if pop < 0 { + minVal -= pop + } + } + + func top() -> Int { + let top = stack.last! + return top > 0 ? top + minVal : minVal + } + + func getMin() -> Int { + return minVal + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/minimum-window-with-characters.md b/articles/minimum-window-with-characters.md index 9e0b36005..887cb769c 100644 --- a/articles/minimum-window-with-characters.md +++ b/articles/minimum-window-with-characters.md @@ -279,6 +279,48 @@ class Solution { } ``` +```swift +class Solution { + func minWindow(_ s: String, _ t: String) -> String { + if t.isEmpty { + return "" + } + + var countT = [Character: Int]() + for c in t { + countT[c, default: 0] += 1 + } + + var res = [-1, -1] + var resLen = Int.max + let chars = Array(s) + + for i in 0.. countS[c, default: 0] { + flag = false + break + } + } + + if flag && (j - i + 1) < resLen { + resLen = j - i + 1 + res = [i, j] + } + } + } + + let (l, r) = (res[0], res[1]) + return resLen != Int.max ? String(chars[l...r]) : "" + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -608,6 +650,53 @@ class Solution { } ``` +```swift +class Solution { + func minWindow(_ s: String, _ t: String) -> String { + if t.isEmpty { + return "" + } + + var countT = [Character: Int]() + var window = [Character: Int]() + for c in t { + countT[c, default: 0] += 1 + } + + var have = 0, need = countT.count + var res = [-1, -1], resLen = Int.max + let chars = Array(s) + var l = 0 + + for r in 0.. Int { + var nums = nums.sorted() + let n = nums.count + for i in 0.. Int { + let numSet = Set(nums) + let n = nums.count + for i in 0...n { + if !numSet.contains(i) { + return i + } + } + return -1 + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -331,6 +361,21 @@ class Solution { } ``` +```swift +class Solution { + func missingNumber(_ nums: [Int]) -> Int { + let n = nums.count + var xorr = n + + for i in 0.. Int { + var res = nums.count + + for i in 0.. String { + if num1 == "0" || num2 == "0" { + return "0" + } + if num1.count < num2.count { + return multiply(num2, num1) + } + + var res = "" + var zero = 0 + let num2Arr = Array(num2) + + for i in stride(from: num2Arr.count - 1, through: 0, by: -1) { + let cur = mul(num1, num2Arr[i], zero) + res = add(res, cur) + zero += 1 + } + + return res + } + + func mul(_ s: String, _ d: Character, _ zero: Int) -> String { + var i = s.count - 1 + var carry = 0 + let dInt = Int(String(d))! + let sArr = Array(s) + var cur = [String]() + + while i >= 0 || carry > 0 { + let n = i >= 0 ? Int(String(sArr[i]))! : 0 + let prod = n * dInt + carry + cur.append(String(prod % 10)) + carry = prod / 10 + i -= 1 + } + + let prodStr = cur.reversed().joined() + let zeros = String(repeating: "0", count: zero) + return prodStr + zeros + } + + func add(_ num1: String, _ num2: String) -> String { + let s1 = Array(num1) + let s2 = Array(num2) + var i = s1.count - 1 + var j = s2.count - 1 + var carry = 0 + var res = [String]() + + while i >= 0 || j >= 0 || carry > 0 { + let n1 = i >= 0 ? Int(String(s1[i]))! : 0 + let n2 = j >= 0 ? Int(String(s2[j]))! : 0 + let total = n1 + n2 + carry + res.append(String(total % 10)) + carry = total / 10 + i -= 1 + j -= 1 + } + + return res.reversed().joined() + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -667,6 +733,37 @@ class Solution { } ``` +```swift +class Solution { + func multiply(_ num1: String, _ num2: String) -> String { + if num1 == "0" || num2 == "0" { + return "0" + } + + let n1 = Array(num1.reversed()).map { Int(String($0))! } + let n2 = Array(num2.reversed()).map { Int(String($0))! } + var res = [Int](repeating: 0, count: num1.count + num2.count) + + for i1 in 0.. [[String]] { + var res = [[String]]() + var board = Array(repeating: Array(repeating: ".", count: n), count: n) + + func backtrack(_ r: Int) { + if r == n { + let copy = board.map { $0.joined() } + res.append(copy) + return + } + for c in 0.. Bool { + var row = r - 1 + while row >= 0 { + if board[row][c] == "Q" { return false } + row -= 1 + } + + var row1 = r - 1, col1 = c - 1 + while row1 >= 0, col1 >= 0 { + if board[row1][col1] == "Q" { return false } + row1 -= 1 + col1 -= 1 + } + + var row2 = r - 1, col2 = c + 1 + while row2 >= 0, col2 < board.count { + if board[row2][col2] == "Q" { return false } + row2 -= 1 + col2 += 1 + } + + return true + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -666,6 +717,47 @@ class Solution { } ``` +```swift +class Solution { + func solveNQueens(_ n: Int) -> [[String]] { + var col = Set() + var posDiag = Set() + var negDiag = Set() + var res = [[String]]() + var board = Array(repeating: Array(repeating: ".", count: n), count: n) + + func backtrack(_ r: Int) { + if r == n { + let copy = board.map { $0.joined() } + res.append(copy) + return + } + + for c in 0.. [[String]] { + var col = Array(repeating: false, count: n) + var posDiag = Array(repeating: false, count: 2 * n) + var negDiag = Array(repeating: false, count: 2 * n) + var res = [[String]]() + var board = Array(repeating: Array(repeating: ".", count: n), count: n) + + func backtrack(_ r: Int) { + if r == n { + let copy = board.map { $0.joined() } + res.append(copy) + return + } + + for c in 0.. [[String]] { + var col = 0 + var posDiag = 0 + var negDiag = 0 + var res = [[String]]() + var board = Array(repeating: Array(repeating: ".", count: n), count: n) + + func backtrack(_ r: Int) { + if r == n { + let copy = board.map { $0.joined() } + res.append(copy) + return + } + + for c in 0.. Int { + var adj = [Int: [(Int, Int)]]() + for time in times { + let u = time[0], v = time[1], w = time[2] + adj[u, default: []].append((v, w)) + } + + var dist = [Int: Int]() + for node in 1...n { + dist[node] = Int.max + } + + func dfs(_ node: Int, _ time: Int) { + if time >= dist[node]! { + return + } + + dist[node] = time + if let neighbors = adj[node] { + for (nei, w) in neighbors { + dfs(nei, time + w) + } + } + } + + dfs(k, 0) + let res = dist.values.max()! + return res == Int.max ? -1 : res + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -450,6 +484,34 @@ class Solution { } ``` +```swift +class Solution { + func networkDelayTime(_ times: [[Int]], _ n: Int, _ k: Int) -> Int { + let inf = Int.max / 2 + var dist = Array(repeating: Array(repeating: inf, count: n), count: n) + + for time in times { + let u = time[0] - 1, v = time[1] - 1, w = time[2] + dist[u][v] = w + } + for i in 0..= inf ? -1 : res + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -621,6 +683,32 @@ class Solution { } ``` +```swift +class Solution { + func networkDelayTime(_ times: [[Int]], _ n: Int, _ k: Int) -> Int { + var dist = Array(repeating: Int.max, count: n) + dist[k - 1] = 0 + + for _ in 0.. Int { + var adj = [Int: [(Int, Int)]]() + for time in times { + let u = time[0], v = time[1], w = time[2] + adj[u, default: []].append((v, w)) + } + + var dist = [Int: Int]() + for node in 1...n { + dist[node] = Int.max + } + dist[k] = 0 + + var queue = Deque<(Int, Int)>() + queue.append((k, 0)) + + while !queue.isEmpty { + let (node, time) = queue.popFirst()! + if dist[node]! < time { + continue + } + if let neighbors = adj[node] { + for (nei, w) in neighbors { + if time + w < dist[nei]! { + dist[nei] = time + w + queue.append((nei, time + w)) + } + } + } + } + + let res = dist.values.max()! + return res == Int.max ? -1 : res + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -1175,6 +1302,53 @@ class Solution { } ``` +```swift +struct Item: Comparable { + let weight: Int + let node: Int + + static func < (lhs: Item, rhs: Item) -> Bool { + return lhs.weight < rhs.weight + } +} + +class Solution { + func networkDelayTime(_ times: [[Int]], _ n: Int, _ k: Int) -> Int { + var edges = [Int: [(Int, Int)]]() + for time in times { + let u = time[0], v = time[1], w = time[2] + edges[u, default: []].append((v, w)) + } + + var minHeap = Heap() + minHeap.insert(Item(weight: 0, node: k)) + var visit = Set() + var t = 0 + + while !minHeap.isEmpty { + let item = minHeap.removeMin() + let w1 = item.weight + let n1 = item.node + + if visit.contains(n1) { + continue + } + visit.insert(n1) + t = w1 + + if let neighbors = edges[n1] { + for (n2, w2) in neighbors { + if !visit.contains(n2) { + minHeap.insert(Item(weight: w1 + w2, node: n2)) + } + } + } + } + return visit.count == n ? t : -1 + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/non-cyclical-number.md b/articles/non-cyclical-number.md index 5290a69a7..6b3053011 100644 --- a/articles/non-cyclical-number.md +++ b/articles/non-cyclical-number.md @@ -206,6 +206,36 @@ class Solution { } ``` +```swift +class Solution { + func isHappy(_ n: Int) -> Bool { + var visit = Set() + var num = n + + while !visit.contains(num) { + visit.insert(num) + num = sumOfSquares(num) + if num == 1 { + return true + } + } + return false + } + + private func sumOfSquares(_ n: Int) -> Int { + var num = n + var output = 0 + + while num > 0 { + let digit = num % 10 + output += digit * digit + num /= 10 + } + return output + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -404,6 +434,34 @@ class Solution { } ``` +```swift +class Solution { + func isHappy(_ n: Int) -> Bool { + var slow = n + var fast = sumOfSquares(n) + + while slow != fast { + fast = sumOfSquares(fast) + fast = sumOfSquares(fast) + slow = sumOfSquares(slow) + } + return fast == 1 + } + + private func sumOfSquares(_ n: Int) -> Int { + var num = n + var output = 0 + + while num > 0 { + let digit = num % 10 + output += digit * digit + num /= 10 + } + return output + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -636,6 +694,40 @@ class Solution { } ``` +```swift +class Solution { + func isHappy(_ n: Int) -> Bool { + var slow = n + var fast = sumOfSquares(n) + var power = 1 + var lam = 1 + + while slow != fast { + if power == lam { + slow = fast + power *= 2 + lam = 0 + } + fast = sumOfSquares(fast) + lam += 1 + } + return fast == 1 + } + + private func sumOfSquares(_ n: Int) -> Int { + var num = n + var output = 0 + + while num > 0 { + let digit = num % 10 + output += digit * digit + num /= 10 + } + return output + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/non-overlapping-intervals.md b/articles/non-overlapping-intervals.md index 7970155cb..60f0b89a1 100644 --- a/articles/non-overlapping-intervals.md +++ b/articles/non-overlapping-intervals.md @@ -147,6 +147,28 @@ class Solution { } ``` +```swift +class Solution { + func eraseOverlapIntervals(_ intervals: [[Int]]) -> Int { + var intervals = intervals + intervals.sort { $0[0] < $1[0] } + + func dfs(_ i: Int, _ prev: Int) -> Int { + if i == intervals.count { + return 0 + } + var res = dfs(i + 1, prev) + if prev == -1 || intervals[prev][1] <= intervals[i][0] { + res = max(res, 1 + dfs(i + 1, i)) + } + return res + } + + return intervals.count - dfs(0, -1) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -365,6 +387,34 @@ class Solution { } ``` +```swift +class Solution { + func eraseOverlapIntervals(_ intervals: [[Int]]) -> Int { + var intervals = intervals + intervals.sort { $0[1] < $1[1] } + let n = intervals.count + var memo = [Int: Int]() + + func dfs(_ i: Int) -> Int { + if let result = memo[i] { + return result + } + + var res = 1 + for j in i + 1.. Int { + var intervals = intervals + intervals.sort { $0[1] < $1[1] } + let n = intervals.count + var dp = [Int](repeating: 0, count: n) + + for i in 0.. Int { + var intervals = intervals + intervals.sort { $0[1] < $1[1] } + let n = intervals.count + var dp = [Int](repeating: 0, count: n) + dp[0] = 1 + + func bs(_ r: Int, _ target: Int) -> Int { + var l = 0 + var r = r + while l < r { + let m = (l + r) >> 1 + if intervals[m][1] <= target { + l = m + 1 + } else { + r = m + } + } + return l + } + + for i in 1.. Int { + var intervals = intervals + intervals.sort { $0[0] < $1[0] } + + var res = 0 + var prevEnd = intervals[0][1] + + for i in 1..= prevEnd { + prevEnd = end + } else { + res += 1 + prevEnd = min(end, prevEnd) + } + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -1142,6 +1275,28 @@ class Solution { } ``` +```swift +class Solution { + func eraseOverlapIntervals(_ intervals: [[Int]]) -> Int { + var intervals = intervals + intervals.sort { $0[1] < $1[1] } + + var prevEnd = intervals[0][1] + var res = 0 + + for i in 1.. intervals[i][0] { + res += 1 + } else { + prevEnd = intervals[i][1] + } + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/number-of-one-bits.md b/articles/number-of-one-bits.md index 9468bf89b..4ea545b0d 100644 --- a/articles/number-of-one-bits.md +++ b/articles/number-of-one-bits.md @@ -99,6 +99,20 @@ class Solution { } ``` +```swift +class Solution { + func hammingWeight(_ n: Int) -> Int { + var res = 0 + for i in 0..<32 { + if (1 << i) & n != 0 { + res += 1 + } + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -208,6 +222,20 @@ class Solution { } ``` +```swift +class Solution { + func hammingWeight(_ n: Int) -> Int { + var n = n + var res = 0 + while n != 0 { + res += (n & 1) != 0 ? 1 : 0 + n >>= 1 + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -313,6 +341,20 @@ class Solution { } ``` +```swift +class Solution { + func hammingWeight(_ n: Int) -> Int { + var n = n + var res = 0 + while n != 0 { + n &= (n - 1) + res += 1 + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -383,6 +425,14 @@ class Solution { } ``` +```swift +class Solution { + func hammingWeight(_ n: Int) -> Int { + return n.nonzeroBitCount + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/pacific-atlantic-water-flow.md b/articles/pacific-atlantic-water-flow.md index 1b718571a..1245a570d 100644 --- a/articles/pacific-atlantic-water-flow.md +++ b/articles/pacific-atlantic-water-flow.md @@ -351,6 +351,57 @@ class Solution { } ``` +```swift +class Solution { + func pacificAtlantic(_ heights: [[Int]]) -> [[Int]] { + var heights = heights + let ROWS = heights.count + let COLS = heights[0].count + let directions = [(1, 0), (-1, 0), (0, 1), (0, -1)] + + var pacific = false + var atlantic = false + + func dfs(_ r: Int, _ c: Int, _ prevVal: Int) { + if r < 0 || c < 0 { + pacific = true + return + } + if r >= ROWS || c >= COLS { + atlantic = true + return + } + if heights[r][c] > prevVal { + return + } + + let tmp = heights[r][c] + heights[r][c] = Int.max + for dir in directions { + dfs(r + dir.0, c + dir.1, tmp) + if pacific && atlantic { + break + } + } + heights[r][c] = tmp + } + + var res = [[Int]]() + for r in 0.. [[Int]] { + let ROWS = heights.count + let COLS = heights[0].count + var pac = Set<[Int]>() + var atl = Set<[Int]>() + + func dfs(_ r: Int, _ c: Int, _ visit: inout Set<[Int]>, _ prevHeight: Int) { + if (visit.contains([r, c]) || r < 0 || c < 0 || r == ROWS || + c == COLS || heights[r][c] < prevHeight) { + return + } + visit.insert([r, c]) + dfs(r + 1, c, &visit, heights[r][c]) + dfs(r - 1, c, &visit, heights[r][c]) + dfs(r, c + 1, &visit, heights[r][c]) + dfs(r, c - 1, &visit, heights[r][c]) + } + + for c in 0.. [[Int]] { + let ROWS = heights.count + let COLS = heights[0].count + let directions = [(1, 0), (-1, 0), (0, 1), (0, -1)] + + var pac = Array(repeating: Array(repeating: false, count: COLS), count: ROWS) + var atl = Array(repeating: Array(repeating: false, count: COLS), count: ROWS) + + func bfs(_ source: [(Int, Int)], _ ocean: inout [[Bool]]) { + var queue = Deque(source) + while !queue.isEmpty { + let (r, c) = queue.popFirst()! + ocean[r][c] = true + for dir in directions { + let nr = r + dir.0 + let nc = c + dir.1 + if nr >= 0, nr < ROWS, nc >= 0, nc < COLS, + !ocean[nr][nc], heights[nr][nc] >= heights[r][c] { + queue.append((nr, nc)) + } + } + } + } + + var pacific: [(Int, Int)] = [] + var atlantic: [(Int, Int)] = [] + + for c in 0.. [[String]] { + var res = [[String]]() + var part = [String]() + let sArray = Array(s) + + func dfs(_ j: Int, _ i: Int) { + if i >= sArray.count { + if i == j { + res.append(part) + } + return + } + + if isPali(sArray, j, i) { + part.append(String(sArray[j...i])) + dfs(i + 1, i + 1) + part.removeLast() + } + + dfs(j, i + 1) + } + + func isPali(_ s: [Character], _ l: Int, _ r: Int) -> Bool { + var l = l, r = r + while l < r { + if s[l] != s[r] { + return false + } + l += 1 + r -= 1 + } + return true + } + + dfs(0, 0) + return res + } +} +``` + ::tabs-end ### Time & Space Complexity * Time complexity: $O(n * 2 ^ n)$ -* Space complexity: $O(n)$ +* Space complexity: + * $O(n)$ extra space. + * $O(n * 2 ^ n)$ space for the output list. --- -## 2. Backtracking +## 2. Backtracking - II ::tabs-start @@ -562,12 +606,53 @@ class Solution { } ``` +```swift +class Solution { + func partition(_ s: String) -> [[String]] { + var res = [[String]]() + var part = [String]() + let sArray = Array(s) + + func dfs(_ i: Int) { + if i >= sArray.count { + res.append(part) + return + } + for j in i.. Bool { + var l = l, r = r + while l < r { + if s[l] != s[r] { + return false + } + l += 1 + r -= 1 + } + return true + } + + dfs(0) + return res + } +} +``` + ::tabs-end ### Time & Space Complexity * Time complexity: $O(n * 2 ^ n)$ -* Space complexity: $O(n)$ +* Space complexity: + * $O(n)$ extra space. + * $O(n * 2 ^ n)$ space for the output list. --- @@ -823,12 +908,51 @@ class Solution { } ``` +```swift +class Solution { + func partition(_ s: String) -> [[String]] { + let n = s.count + let sArray = Array(s) + var dp = Array(repeating: Array(repeating: false, count: n), count: n) + + for l in 1...n { + for i in 0...(n - l) { + dp[i][i + l - 1] = (sArray[i] == sArray[i + l - 1] && + (i + 1 > (i + l - 2) || dp[i + 1][i + l - 2])) + } + } + + var res = [[String]]() + var part = [String]() + + func dfs(_ i: Int) { + if i >= sArray.count { + res.append(part) + return + } + for j in i.. [[String]] { + let n = s.count + let sArray = Array(s) + var dp = Array(repeating: Array(repeating: false, count: n), count: n) + + for l in 1...n { + for i in 0...(n - l) { + dp[i][i + l - 1] = (sArray[i] == sArray[i + l - 1] && + (i + 1 > (i + l - 2) || dp[i + 1][i + l - 2])) + } + } + + func dfs(_ i: Int) -> [[String]] { + if i >= n { + return [[]] + } + + var ret = [[String]]() + for j in i.. Int { + let chars = Array(s) + var res = 0 + + for i in 0..= r { + res += 1 + } + } + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -313,6 +337,28 @@ class Solution { } ``` +```swift +class Solution { + func countSubstrings(_ s: String) -> Int { + let n = s.count + var res = 0 + var dp = Array(repeating: Array(repeating: false, count: n), count: n) + let chars = Array(s) + + for i in stride(from: n - 1, through: 0, by: -1) { + for j in i.. Int { + let chars = Array(s) + var res = 0 + + for i in 0..= 0 && r < chars.count && chars[l] == chars[r] { + res += 1 + l -= 1 + r += 1 + } + + // Even length palindromes + l = i + r = i + 1 + while l >= 0 && r < chars.count && chars[l] == chars[r] { + res += 1 + l -= 1 + r += 1 + } + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -722,6 +798,33 @@ class Solution { } ``` +```swift +class Solution { + func countSubstrings(_ s: String) -> Int { + var res = 0 + let chars = Array(s) + + for i in 0.. Int { + var res = 0 + var left = l, right = r + + while left >= 0 && right < s.count && s[left] == s[right] { + res += 1 + left -= 1 + right += 1 + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -982,6 +1085,42 @@ class Solution { } ``` +```swift +class Solution { + func countSubstrings(_ s: String) -> Int { + func manacher(_ s: String) -> [Int] { + let t = "#" + s.map { "\($0)#" }.joined() + let chars = Array(t) + let n = chars.count + var p = Array(repeating: 0, count: n) + var l = 0, r = 0 + + for i in 0..= 0, + chars[i + p[i] + 1] == chars[i - p[i] - 1] { + p[i] += 1 + } + if i + p[i] > r { + l = i - p[i] + r = i + p[i] + } + } + return p + } + + let p = manacher(s) + var res = 0 + for i in p { + res += (i + 1) / 2 + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/partition-equal-subset-sum.md b/articles/partition-equal-subset-sum.md index d51654692..6d6fd0caa 100644 --- a/articles/partition-equal-subset-sum.md +++ b/articles/partition-equal-subset-sum.md @@ -194,6 +194,33 @@ class Solution { } ``` +```swift +class Solution { + func canPartition(_ nums: [Int]) -> Bool { + let totalSum = nums.reduce(0, +) + if totalSum % 2 != 0 { + return false + } + + let target = totalSum / 2 + let n = nums.count + + func dfs(_ i: Int, _ target: Int) -> Bool { + if i >= n { + return target == 0 + } + if target < 0 { + return false + } + + return dfs(i + 1, target) || dfs(i + 1, target - nums[i]) + } + + return dfs(0, target) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -454,6 +481,39 @@ class Solution { } ``` +```swift +class Solution { + func canPartition(_ nums: [Int]) -> Bool { + let total = nums.reduce(0, +) + if total % 2 != 0 { + return false + } + + let target = total / 2 + let n = nums.count + var memo = Array(repeating: Array(repeating: -1, count: target + 1), count: n + 1) + + func dfs(_ i: Int, _ target: Int) -> Bool { + if target == 0 { + return true + } + if i >= n || target < 0 { + return false + } + if memo[i][target] != -1 { + return memo[i][target] == 1 + } + + let result = dfs(i + 1, target) || dfs(i + 1, target - nums[i]) + memo[i][target] = result ? 1 : 0 + return result + } + + return dfs(0, target) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -702,6 +762,37 @@ class Solution { } ``` +```swift +class Solution { + func canPartition(_ nums: [Int]) -> Bool { + let total = nums.reduce(0, +) + if total % 2 != 0 { + return false + } + + let target = total / 2 + let n = nums.count + var dp = Array(repeating: Array(repeating: false, count: target + 1), count: n + 1) + + for i in 0...n { + dp[i][0] = true + } + + for i in 1...n { + for j in 1...target { + if nums[i - 1] <= j { + dp[i][j] = dp[i - 1][j] || dp[i - 1][j - nums[i - 1]] + } else { + dp[i][j] = dp[i - 1][j] + } + } + } + + return dp[n][target] + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -940,6 +1031,34 @@ class Solution { } ``` +```swift +class Solution { + func canPartition(_ nums: [Int]) -> Bool { + if nums.reduce(0, +) % 2 != 0 { + return false + } + + let target = nums.reduce(0, +) / 2 + var dp = Array(repeating: false, count: target + 1) + var nextDp = Array(repeating: false, count: target + 1) + + dp[0] = true + for num in nums { + for j in stride(from: target, through: 1, by: -1) { + if j >= num { + nextDp[j] = dp[j] || dp[j - num] + } else { + nextDp[j] = dp[j] + } + } + swap(&dp, &nextDp) + } + + return dp[target] + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -1147,6 +1266,32 @@ class Solution { } ``` +```swift +class Solution { + func canPartition(_ nums: [Int]) -> Bool { + if nums.reduce(0, +) % 2 != 0 { + return false + } + + var dp: Set = [0] + let target = nums.reduce(0, +) / 2 + + for i in stride(from: nums.count - 1, through: 0, by: -1) { + var nextDP: Set = [] + for t in dp { + if t + nums[i] == target { + return true + } + nextDP.insert(t + nums[i]) + nextDP.insert(t) + } + dp = nextDP + } + return false + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -1342,6 +1487,28 @@ class Solution { } ``` +```swift +class Solution { + func canPartition(_ nums: [Int]) -> Bool { + if nums.reduce(0, +) % 2 != 0 { + return false + } + + let target = nums.reduce(0, +) / 2 + var dp = Array(repeating: false, count: target + 1) + + dp[0] = true + for num in nums { + for j in stride(from: target, through: num, by: -1) { + dp[j] = dp[j] || dp[j - num] + } + } + + return dp[target] + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -1366,10 +1533,10 @@ class Solution: target = total // 2 dp = 1 << 0 - + for num in nums: dp |= dp << num - + return (dp & (1 << target)) != 0 ``` diff --git a/articles/partition-labels.md b/articles/partition-labels.md index 5eb089e85..1e4e2b3a1 100644 --- a/articles/partition-labels.md +++ b/articles/partition-labels.md @@ -169,6 +169,31 @@ class Solution { } ``` +```swift +class Solution { + func partitionLabels(_ s: String) -> [Int] { + var lastIndex = [Character: Int]() + for (i, c) in s.enumerated() { + lastIndex[c] = i + } + + var res = [Int]() + var size = 0 + var end = 0 + for (i, c) in s.enumerated() { + size += 1 + end = max(end, lastIndex[c]!) + + if i == end { + res.append(size) + size = 0 + } + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/permutation-string.md b/articles/permutation-string.md index 07e79c7ef..482890ee4 100644 --- a/articles/permutation-string.md +++ b/articles/permutation-string.md @@ -149,6 +149,25 @@ class Solution { } ``` +```swift +class Solution { + func checkInclusion(_ s1: String, _ s2: String) -> Bool { + let s1Sorted = s1.sorted() + let chars = Array(s2) + + for i in 0.. Bool { + var count1 = [Character: Int]() + for c in s1 { + count1[c, default: 0] += 1 + } + + let need = count1.count + let chars = Array(s2) + + for i in 0.. Where $n$ is the length of the string1 and $m$ is the length of string2. @@ -736,6 +788,61 @@ class Solution { } ``` +```swift +class Solution { + func checkInclusion(_ s1: String, _ s2: String) -> Bool { + if s1.count > s2.count { + return false + } + + var s1Count = [Int](repeating: 0, count: 26) + var s2Count = [Int](repeating: 0, count: 26) + let aAscii = Int(Character("a").asciiValue!) + + let s1Array = Array(s1) + let s2Array = Array(s2) + + for i in 0.. [[Int]] { + if nums.isEmpty { + return [[]] + } + + let perms = permute(Array(nums.dropFirst())) + var res = [[Int]]() + + for p in perms { + for i in 0...p.count { + var pCopy = p + pCopy.insert(nums[0], at: i) + res.append(pCopy) + } + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -303,6 +326,28 @@ class Solution { } ``` +```swift +class Solution { + func permute(_ nums: [Int]) -> [[Int]] { + var perms: [[Int]] = [[]] + + for num in nums { + var newPerms = [[Int]]() + for p in perms { + for i in 0...p.count { + var pCopy = p + pCopy.insert(num, at: i) + newPerms.append(pCopy) + } + } + perms = newPerms + } + + return perms + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -501,6 +546,35 @@ class Solution { } ``` +```swift +class Solution { + func permute(_ nums: [Int]) -> [[Int]] { + var res = [[Int]]() + var pick = [Bool](repeating: false, count: nums.count) + + func backtrack(_ perm: inout [Int]) { + if perm.count == nums.count { + res.append(perm) + return + } + for i in 0.. [[Int]] { + var res = [[Int]]() + + func backtrack(_ perm: inout [Int], _ mask: Int) { + if perm.count == nums.count { + res.append(perm) + return + } + for i in 0.. [[Int]] { + var res = [[Int]]() + var nums = nums + + func backtrack(_ idx: Int) { + if idx == nums.count { + res.append(nums) + return + } + for i in idx.. [Int] { + if digits.isEmpty { + return [1] + } + + var digits = digits + if digits[digits.count - 1] < 9 { + digits[digits.count - 1] += 1 + return digits + } else { + return plusOne(Array(digits.dropLast())) + [0] + } + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -341,6 +359,35 @@ class Solution { } ``` +```swift +class Solution { + func plusOne(_ digits: [Int]) -> [Int] { + var digits = digits + var one = 1 + var i = 0 + digits.reverse() + + while one > 0 { + if i < digits.count { + if digits[i] == 9 { + digits[i] = 0 + } else { + digits[i] += 1 + one = 0 + } + } else { + digits.append(one) + one = 0 + } + i += 1 + } + + digits.reverse() + return digits + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -476,6 +523,25 @@ class Solution { } ``` +```swift +class Solution { + func plusOne(_ digits: [Int]) -> [Int] { + var digits = digits + let n = digits.count + + for i in stride(from: n - 1, through: 0, by: -1) { + if digits[i] < 9 { + digits[i] += 1 + return digits + } + digits[i] = 0 + } + + return [1] + digits + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/pow-x-n.md b/articles/pow-x-n.md index 341e3ae9d..50beeb0f4 100644 --- a/articles/pow-x-n.md +++ b/articles/pow-x-n.md @@ -139,6 +139,25 @@ class Solution { } ``` +```swift +class Solution { + func myPow(_ x: Double, _ n: Int) -> Double { + if x == 0 { + return 0 + } + if n == 0 { + return 1 + } + + var res: Double = 1 + for _ in 0..= 0 ? res : 1 / res + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -320,12 +339,33 @@ class Solution { } ``` +```swift +class Solution { + func myPow(_ x: Double, _ n: Int) -> Double { + func helper(_ x: Double, _ n: Int) -> Double { + if x == 0 { + return 0 + } + if n == 0 { + return 1 + } + + let res = helper(x * x, n / 2) + return n % 2 == 0 ? res : x * res + } + + let res = helper(x, abs(n)) + return n >= 0 ? res : 1 / res + } +} +``` + ::tabs-end ### Time & Space Complexity * Time complexity: $O(\log n)$ -* Space complexity: $O(\log n)$ +* Space complexity: $O(\log n)$ for recursion stack. --- @@ -501,6 +541,33 @@ class Solution { } ``` +```swift +class Solution { + func myPow(_ x: Double, _ n: Int) -> Double { + if x == 0 { + return 0 + } + if n == 0 { + return 1 + } + + var res: Double = 1 + var base = x + var power = abs(n) + + while power > 0 { + if power & 1 == 1 { + res *= base + } + base *= base + power >>= 1 + } + + return n >= 0 ? res : 1 / res + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/products-of-array-discluding-self.md b/articles/products-of-array-discluding-self.md index 1a74a5c68..1370fac97 100644 --- a/articles/products-of-array-discluding-self.md +++ b/articles/products-of-array-discluding-self.md @@ -142,12 +142,37 @@ class Solution { } ``` +```swift +class Solution { + func productExceptSelf(_ nums: [Int]) -> [Int] { + let n = nums.count + var res = [Int](repeating: 0, count: n) + + for i in 0.. [Int] { + var prod = 1 + var zeroCount = 0 + + for num in nums { + if num != 0 { + prod *= num + } else { + zeroCount += 1 + } + } + + if zeroCount > 1 { + return [Int](repeating: 0, count: nums.count) + } + + var res = [Int](repeating: 0, count: nums.count) + for (i, num) in nums.enumerated() { + if zeroCount > 0 { + res[i] = num == 0 ? prod : 0 + } else { + res[i] = prod / num + } + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity * Time complexity: $O(n)$ -* Space complexity: $O(1)$ since the output array is excluded from space analysis. +* Space complexity: + * $O(1)$ extra space. + * $O(n)$ space for the output array. --- @@ -533,6 +592,34 @@ class Solution { } ``` +```swift +class Solution { + func productExceptSelf(_ nums: [Int]) -> [Int] { + let n = nums.count + var res = [Int](repeating: 0, count: n) + var pref = [Int](repeating: 0, count: n) + var suff = [Int](repeating: 0, count: n) + + pref[0] = 1 + suff[n - 1] = 1 + + for i in 1.. [Int] { + var res = [Int](repeating: 1, count: nums.count) + + var prefix = 1 + for i in 0.. [String] { + var adj = [String: [String]]() + for ticket in tickets { + adj[ticket[0], default: []].append(ticket[1]) + } + + for key in adj.keys { + adj[key]?.sort() + } + + var res = ["JFK"] + + func dfs(_ src: String) -> Bool { + if res.count == tickets.count + 1 { + return true + } + guard let destinations = adj[src] else { + return false + } + + var temp = destinations + for i in 0.. [String] { + var adj = [String: [String]]() + for ticket in tickets.sorted(by: { $0[1] > $1[1] }) { + adj[ticket[0], default: []].append(ticket[1]) + } + + var res = [String]() + + func dfs(_ src: String) { + while let destinations = adj[src], !destinations.isEmpty { + let dst = adj[src]!.removeLast() + dfs(dst) + } + res.append(src) + } + + dfs("JFK") + return res.reversed() + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -718,6 +782,31 @@ class Solution { } ``` +```swift +class Solution { + func findItinerary(_ tickets: [[String]]) -> [String] { + var adj = [String: [String]]() + for ticket in tickets.sorted(by: { $0[1] > $1[1] }) { + adj[ticket[0], default: []].append(ticket[1]) + } + + var stack = ["JFK"] + var res = [String]() + + while !stack.isEmpty { + let curr = stack.last! + if adj[curr] == nil || adj[curr]!.isEmpty { + res.append(stack.removeLast()) + } else { + stack.append(adj[curr]!.removeLast()) + } + } + + return res.reversed() + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/redundant-connection.md b/articles/redundant-connection.md index 81a67ff84..154493da7 100644 --- a/articles/redundant-connection.md +++ b/articles/redundant-connection.md @@ -247,6 +247,45 @@ class Solution { } ``` +```swift +class Solution { + func findRedundantConnection(_ edges: [[Int]]) -> [Int] { + let n = edges.count + var adj = Array(repeating: [Int](), count: n + 1) + + func dfs(_ node: Int, _ par: Int, _ visit: inout [Bool]) -> Bool { + if visit[node] { + return true + } + + visit[node] = true + for nei in adj[node] { + if nei == par { + continue + } + if dfs(nei, node, &visit) { + return true + } + } + return false + } + + for edge in edges { + let u = edge[0] + let v = edge[1] + adj[u].append(v) + adj[v].append(u) + var visit = Array(repeating: false, count: n + 1) + + if dfs(u, -1, &visit) { + return [u, v] + } + } + return [] + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -606,6 +645,62 @@ class Solution { } ``` +```swift +class Solution { + func findRedundantConnection(_ edges: [[Int]]) -> [Int] { + let n = edges.count + var adj = Array(repeating: [Int](), count: n + 1) + + for edge in edges { + let u = edge[0] + let v = edge[1] + adj[u].append(v) + adj[v].append(u) + } + + var visit = Array(repeating: false, count: n + 1) + var cycle = Set() + var cycleStart = -1 + + func dfs(_ node: Int, _ par: Int) -> Bool { + if visit[node] { + cycleStart = node + return true + } + + visit[node] = true + for nei in adj[node] { + if nei == par { + continue + } + if dfs(nei, node) { + if cycleStart != -1 { + cycle.insert(node) + } + if node == cycleStart { + cycleStart = -1 + } + return true + } + } + return false + } + + dfs(1, -1) + + for edge in edges.reversed() { + let u = edge[0] + let v = edge[1] + if cycle.contains(u) && cycle.contains(v) { + return [u, v] + } + } + + return [] + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -895,6 +990,52 @@ class Solution { } ``` +```swift +class Solution { + func findRedundantConnection(_ edges: [[Int]]) -> [Int] { + let n = edges.count + var indegree = Array(repeating: 0, count: n + 1) + var adj = Array(repeating: [Int](), count: n + 1) + + for edge in edges { + let u = edge[0] + let v = edge[1] + adj[u].append(v) + adj[v].append(u) + indegree[u] += 1 + indegree[v] += 1 + } + + var queue = Deque() + for i in 1...n { + if indegree[i] == 1 { + queue.append(i) + } + } + + while !queue.isEmpty { + let node = queue.popFirst()! + indegree[node] -= 1 + for nei in adj[node] { + indegree[nei] -= 1 + if indegree[nei] == 1 { + queue.append(nei) + } + } + } + + for edge in edges.reversed() { + let u = edge[0] + let v = edge[1] + if indegree[u] == 2 && indegree[v] > 0 { + return [u, v] + } + } + return [] + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -1212,6 +1353,50 @@ class Solution { } ``` +```swift +class Solution { + func findRedundantConnection(_ edges: [[Int]]) -> [Int] { + var par = Array(0...edges.count) + var rank = Array(repeating: 1, count: edges.count + 1) + + func find(_ n: Int) -> Int { + var p = par[n] + while p != par[p] { + par[p] = par[par[p]] + p = par[p] + } + return p + } + + func union(_ n1: Int, _ n2: Int) -> Bool { + let p1 = find(n1) + let p2 = find(n2) + + if p1 == p2 { + return false + } + if rank[p1] > rank[p2] { + par[p2] = p1 + rank[p1] += rank[p2] + } else { + par[p1] = p2 + rank[p2] += rank[p1] + } + return true + } + + for edge in edges { + let n1 = edge[0] + let n2 = edge[1] + if !union(n1, n2) { + return [n1, n2] + } + } + return [] + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/regular-expression-matching.md b/articles/regular-expression-matching.md index 31b2a26a4..fd4bfda86 100644 --- a/articles/regular-expression-matching.md +++ b/articles/regular-expression-matching.md @@ -184,6 +184,35 @@ class Solution { } ``` +```swift +class Solution { + func isMatch(_ s: String, _ p: String) -> Bool { + let sArr = Array(s), pArr = Array(p) + let m = sArr.count, n = pArr.count + + func dfs(_ i: Int, _ j: Int) -> Bool { + if j == n { + return i == m + } + + let match = i < m && (sArr[i] == pArr[j] || pArr[j] == ".") + + if j + 1 < n && pArr[j + 1] == "*" { + return dfs(i, j + 2) || (match && dfs(i + 1, j)) + } + + if match { + return dfs(i + 1, j + 1) + } + + return false + } + + return dfs(0, 0) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -432,6 +461,42 @@ class Solution { } ``` +```swift +class Solution { + func isMatch(_ s: String, _ p: String) -> Bool { + let sArr = Array(s), pArr = Array(p) + let m = sArr.count, n = pArr.count + var cache = [[Bool?]](repeating: [Bool?](repeating: nil, count: n + 1), count: m + 1) + + func dfs(_ i: Int, _ j: Int) -> Bool { + if j == n { + return i == m + } + if let cached = cache[i][j] { + return cached + } + + let match = i < m && (sArr[i] == pArr[j] || pArr[j] == ".") + + if j + 1 < n && pArr[j + 1] == "*" { + cache[i][j] = dfs(i, j + 2) || (match && dfs(i + 1, j)) + return cache[i][j]! + } + + if match { + cache[i][j] = dfs(i + 1, j + 1) + return cache[i][j]! + } + + cache[i][j] = false + return false + } + + return dfs(0, 0) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -635,6 +700,34 @@ class Solution { } ``` +```swift +class Solution { + func isMatch(_ s: String, _ p: String) -> Bool { + let sArr = Array(s), pArr = Array(p) + let m = sArr.count, n = pArr.count + var dp = Array(repeating: Array(repeating: false, count: n + 1), count: m + 1) + dp[m][n] = true + + for i in stride(from: m, through: 0, by: -1) { + for j in stride(from: n - 1, through: 0, by: -1) { + let match = i < m && (sArr[i] == pArr[j] || pArr[j] == ".") + + if j + 1 < n && pArr[j + 1] == "*" { + dp[i][j] = dp[i][j + 2] + if match { + dp[i][j] = dp[i][j] || dp[i + 1][j] + } + } else if match { + dp[i][j] = dp[i + 1][j + 1] + } + } + } + + return dp[0][0] + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -862,6 +955,38 @@ class Solution { } ``` +```swift +class Solution { + func isMatch(_ s: String, _ p: String) -> Bool { + let sArr = Array(s), pArr = Array(p) + var dp = Array(repeating: false, count: pArr.count + 1) + dp[pArr.count] = true + + for i in stride(from: sArr.count, through: 0, by: -1) { + var nextDp = Array(repeating: false, count: pArr.count + 1) + nextDp[pArr.count] = (i == sArr.count) + + for j in stride(from: pArr.count - 1, through: 0, by: -1) { + let match = i < sArr.count && (sArr[i] == pArr[j] || pArr[j] == ".") + + if j + 1 < pArr.count && pArr[j + 1] == "*" { + nextDp[j] = nextDp[j + 2] + if match { + nextDp[j] = nextDp[j] || dp[j] + } + } else if match { + nextDp[j] = dp[j + 1] + } + } + + dp = nextDp + } + + return dp[0] + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -1096,6 +1221,39 @@ class Solution { } ``` +```swift +class Solution { + func isMatch(_ s: String, _ p: String) -> Bool { + let sArr = Array(s) + let pArr = Array(p) + var dp = [Bool](repeating: false, count: pArr.count + 1) + dp[pArr.count] = true + + for i in stride(from: sArr.count, through: 0, by: -1) { + var dp1 = dp[pArr.count] + dp[pArr.count] = (i == sArr.count) + + for j in stride(from: pArr.count - 1, through: 0, by: -1) { + let match = i < sArr.count && (sArr[i] == pArr[j] || pArr[j] == ".") + var res = false + if j + 1 < pArr.count && pArr[j + 1] == "*" { + res = dp[j + 2] + if match { + res = res || dp[j] + } + } else if match { + res = dp1 + } + dp1 = dp[j] + dp[j] = res + } + } + + return dp[0] + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/remove-node-from-end-of-linked-list.md b/articles/remove-node-from-end-of-linked-list.md index 141817504..ee936f416 100644 --- a/articles/remove-node-from-end-of-linked-list.md +++ b/articles/remove-node-from-end-of-linked-list.md @@ -216,6 +216,38 @@ class Solution { } ``` +```swift +/** + * Definition for singly-linked list. + * public class ListNode { + * public var val: Int + * public var next: ListNode? + * public init() { self.val = 0; self.next = nil; } + * public init(_ val: Int) { self.val = val; self.next = nil; } + * public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; } + * } + */ +class Solution { + func removeNthFromEnd(_ head: ListNode?, _ n: Int) -> ListNode? { + var nodes: [ListNode] = [] + var cur = head + + while cur != nil { + nodes.append(cur!) + cur = cur?.next + } + + let removeIndex = nodes.count - n + if removeIndex == 0 { + return head?.next + } + + nodes[removeIndex - 1].next = nodes[removeIndex].next + return head + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -490,6 +522,44 @@ class Solution { } ``` +```swift +/** + * Definition for singly-linked list. + * public class ListNode { + * public var val: Int + * public var next: ListNode? + * public init() { self.val = 0; self.next = nil; } + * public init(_ val: Int) { self.val = val; self.next = nil; } + * public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; } + * } + */ +class Solution { + func removeNthFromEnd(_ head: ListNode?, _ n: Int) -> ListNode? { + var N = 0 + var cur = head + while cur != nil { + N += 1 + cur = cur?.next + } + + let removeIndex = N - n + if removeIndex == 0 { + return head?.next + } + + cur = head + for i in 0..<(N - 1) { + if (i + 1) == removeIndex { + cur?.next = cur?.next?.next + break + } + cur = cur?.next + } + return head + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -723,12 +793,44 @@ class Solution { } ``` +```swift +/** + * Definition for singly-linked list. + * public class ListNode { + * public var val: Int + * public var next: ListNode? + * public init() { self.val = 0; self.next = nil; } + * public init(_ val: Int) { self.val = val; self.next = nil; } + * public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; } + * } + */ +class Solution { + func rec(_ head: ListNode?, _ n: inout Int) -> ListNode? { + if head == nil { + return nil + } + + head?.next = rec(head?.next, &n) + n -= 1 + if n == 0 { + return head?.next + } + return head + } + + func removeNthFromEnd(_ head: ListNode?, _ n: Int) -> ListNode? { + var n = n + return rec(head, &n) + } +} +``` + ::tabs-end ### Time & Space Complexity * Time complexity: $O(N)$ -* Space complexity: $O(N)$ +* Space complexity: $O(N)$ for recursion stack. --- @@ -964,6 +1066,40 @@ class Solution { } ``` +```swift +/** + * Definition for singly-linked list. + * public class ListNode { + * public var val: Int + * public var next: ListNode? + * public init() { self.val = 0; self.next = nil; } + * public init(_ val: Int) { self.val = val; self.next = nil; } + * public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; } + * } + */ +class Solution { + func removeNthFromEnd(_ head: ListNode?, _ n: Int) -> ListNode? { + let dummy = ListNode(0, head) + var left: ListNode? = dummy + var right: ListNode? = head + var n = n + + while n > 0 { + right = right?.next + n -= 1 + } + + while right != nil { + left = left?.next + right = right?.next + } + + left?.next = left?.next?.next + return dummy.next + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/reorder-linked-list.md b/articles/reorder-linked-list.md index 399860a22..75e0ef82c 100644 --- a/articles/reorder-linked-list.md +++ b/articles/reorder-linked-list.md @@ -260,6 +260,47 @@ class Solution { } ``` +```swift +/** + * Definition for singly-linked list. + * public class ListNode { + * public var val: Int + * public var next: ListNode? + * public init() { self.val = 0; self.next = nil; } + * public init(_ val: Int) { self.val = val; self.next = nil; } + * public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; } + * } + */ +class Solution { + func reorderList(_ head: ListNode?) { + if head == nil { + return + } + + var nodes: [ListNode] = [] + var cur = head + + while cur != nil { + nodes.append(cur!) + cur = cur?.next + } + + var i = 0, j = nodes.count - 1 + while i < j { + nodes[i].next = nodes[j] + i += 1 + if i >= j { + break + } + nodes[j].next = nodes[i] + j -= 1 + } + + nodes[i].next = nil + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -286,10 +327,11 @@ class Solution: def rec(root: ListNode, cur: ListNode) -> ListNode: if not cur: return root - root = rec(root, cur.next) + root = rec(root, cur.next) if not root: return None + tmp = None if root == cur or root.next == cur: cur.next = None @@ -297,8 +339,9 @@ class Solution: tmp = root.next root.next = cur cur.next = tmp + return tmp - + head = rec(head, head.next) ``` @@ -323,10 +366,12 @@ public class Solution { if (cur == null) { return root; } + root = rec(root, cur.next); if (root == null) { return null; } + ListNode tmp = null; if (root == cur || root.next == cur) { cur.next = null; @@ -335,6 +380,7 @@ public class Solution { root.next = cur; cur.next = tmp; } + return tmp; } } @@ -363,10 +409,12 @@ private: if (cur == nullptr) { return root; } + root = rec(root, cur->next); if (root == nullptr) { return nullptr; } + ListNode* tmp = nullptr; if (root == cur || root->next == cur) { cur->next = nullptr; @@ -375,6 +423,7 @@ private: root->next = cur; cur->next = tmp; } + return tmp; } }; @@ -409,10 +458,12 @@ class Solution { if (cur === null) { return root; } + root = this.rec(root, cur.next); if (root === null) { return null; } + let tmp = null; if (root === cur || root.next === cur) { cur.next = null; @@ -421,6 +472,7 @@ class Solution { root.next = cur; cur.next = tmp; } + return tmp; } } @@ -448,10 +500,12 @@ public class Solution { if (cur == null) { return root; } + root = Rec(root, cur.next); if (root == null) { return null; } + ListNode tmp = null; if (root == cur || root.next == cur) { cur.next = null; @@ -460,6 +514,7 @@ public class Solution { root.next = cur; cur.next = tmp; } + return tmp; } } @@ -483,11 +538,12 @@ func reorderList(head *ListNode) { if cur == nil { return root } - root = rec(root, cur.Next) + root = rec(root, cur.Next) if root == nil { return nil } + var tmp *ListNode if root == cur || root.Next == cur { cur.Next = nil @@ -496,6 +552,7 @@ func reorderList(head *ListNode) { root.Next = cur cur.Next = tmp } + return tmp } @@ -521,11 +578,12 @@ class Solution { if (cur == null) { return root } - var updatedRoot = rec(root, cur.next) + var updatedRoot = rec(root, cur.next) if (updatedRoot == null) { return null } + var tmp: ListNode? = null if (updatedRoot == cur || updatedRoot?.next == cur) { cur.next = null @@ -534,6 +592,7 @@ class Solution { updatedRoot.next = cur cur.next = tmp } + return tmp } @@ -542,6 +601,46 @@ class Solution { } ``` +```swift +/** + * Definition for singly-linked list. + * public class ListNode { + * public var val: Int + * public var next: ListNode? + * public init() { self.val = 0; self.next = nil; } + * public init(_ val: Int) { self.val = val; self.next = nil; } + * public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; } + * } + */ +class Solution { + func reorderList(_ head: ListNode?) { + func rec(_ root: ListNode?, _ cur: ListNode?) -> ListNode? { + if cur == nil { + return root + } + + var root = rec(root, cur?.next) + if root == nil { + return nil + } + + var tmp: ListNode? = nil + if root === cur || root?.next === cur { + cur?.next = nil + } else { + tmp = root?.next + root?.next = cur + cur?.next = tmp + } + + return tmp + } + + rec(head, head?.next) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -852,6 +951,51 @@ class Solution { } ``` +```swift +/** + * Definition for singly-linked list. + * public class ListNode { + * public var val: Int + * public var next: ListNode? + * public init() { self.val = 0; self.next = nil; } + * public init(_ val: Int) { self.val = val; self.next = nil; } + * public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; } + * } + */ +class Solution { + func reorderList(_ head: ListNode?) { + var slow = head, fast = head?.next + while fast != nil && fast?.next != nil { + slow = slow?.next + fast = fast?.next?.next + } + + var second = slow?.next + var prev: ListNode? = nil + slow?.next = nil + + while second != nil { + let tmp = second?.next + second?.next = prev + prev = second + second = tmp + } + + var first = head + second = prev + + while second != nil { + let tmp1 = first?.next + let tmp2 = second?.next + first?.next = second + second?.next = tmp1 + first = tmp1 + second = tmp2 + } + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/reverse-a-linked-list.md b/articles/reverse-a-linked-list.md index 98f5ee98d..3a205a543 100644 --- a/articles/reverse-a-linked-list.md +++ b/articles/reverse-a-linked-list.md @@ -200,6 +200,35 @@ class Solution { } ``` +```swift +/** + * Definition for singly-linked list. + * public class ListNode { + * public var val: Int + * public var next: ListNode? + * public init() { self.val = 0; self.next = nil; } + * public init(_ val: Int) { self.val = val; self.next = nil; } + * public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; } + * } + */ +class Solution { + func reverseList(_ head: ListNode?) -> ListNode? { + if head == nil { + return nil + } + + var newHead = head + if head?.next != nil { + newHead = reverseList(head?.next) + head?.next?.next = head + } + head?.next = nil + + return newHead + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -397,6 +426,33 @@ class Solution { } ``` +```swift +/** + * Definition for singly-linked list. + * public class ListNode { + * public var val: Int + * public var next: ListNode? + * public init() { self.val = 0; self.next = nil; } + * public init(_ val: Int) { self.val = val; self.next = nil; } + * public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; } + * } + */ +class Solution { + func reverseList(_ head: ListNode?) -> ListNode? { + var prev: ListNode? = nil + var curr = head + + while curr != nil { + let temp = curr?.next + curr?.next = prev + prev = curr + curr = temp + } + return prev + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/reverse-bits.md b/articles/reverse-bits.md index d5267bf19..84cbe88ce 100644 --- a/articles/reverse-bits.md +++ b/articles/reverse-bits.md @@ -162,6 +162,30 @@ class Solution { } ``` +```swift +class Solution { + func reverseBits(_ n: Int) -> Int { + var binary = "" + for i in 0..<32 { + if (n & (1 << i)) != 0 { + binary += "1" + } else { + binary += "0" + } + } + + var res = 0 + for (i, bit) in binary.reversed().enumerated() { + if bit == "1" { + res |= (1 << i) + } + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -266,6 +290,20 @@ class Solution { } ``` +```swift +class Solution { + func reverseBits(_ n: Int) -> Int { + var res = 0 + var num = n + for i in 0..<32 { + let bit = (num >> i) & 1 + res |= (bit << (31 - i)) + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -378,6 +416,20 @@ class Solution { } ``` +```swift +class Solution { + func reverseBits(_ n: Int) -> Int { + var res = n + res = (res >> 16) | (res << 16) & 0xFFFFFFFF + res = ((res & 0xff00ff00) >> 8) | ((res & 0x00ff00ff) << 8) + res = ((res & 0xf0f0f0f0) >> 4) | ((res & 0x0f0f0f0f) << 4) + res = ((res & 0xcccccccc) >> 2) | ((res & 0x33333333) << 2) + res = ((res & 0xaaaaaaaa) >> 1) | ((res & 0x55555555) << 1) + return res & 0xFFFFFFFF + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/reverse-integer.md b/articles/reverse-integer.md index f6d060a33..c388a821f 100644 --- a/articles/reverse-integer.md +++ b/articles/reverse-integer.md @@ -147,6 +147,25 @@ class Solution { } ``` +```swift +class Solution { + func reverse(_ x: Int) -> Int { + let org = x + var x = abs(x) + var res = Int(String(String(x).reversed()))! + + if org < 0 { + res *= -1 + } + if res < Int32.min || res > Int32.max { + return 0 + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -310,6 +329,28 @@ class Solution { } ``` +```swift +class Solution { + func reverse(_ x: Int) -> Int { + func rec(_ n: Int, _ rev: Int) -> Int { + if n == 0 { + return rev + } + return rec(n / 10, rev * 10 + n % 10) + } + + let sign = x < 0 ? -1 : 1 + let reversedNum = rec(abs(x), 0) * sign + + if reversedNum < Int32.min || reversedNum > Int32.max { + return 0 + } + + return reversedNum + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -489,6 +530,33 @@ class Solution { } ``` +```swift +class Solution { + func reverse(_ x: Int) -> Int { + let MIN = Int32.min + let MAX = Int32.max + + var res = 0 + var num = x + + while num != 0 { + let digit = num % 10 + num /= 10 + + if res > MAX / 10 || (res == MAX / 10 && digit > MAX % 10) { + return 0 + } + if res < MIN / 10 || (res == MIN / 10 && digit < MIN % 10) { + return 0 + } + res = res * 10 + digit + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/reverse-nodes-in-k-group.md b/articles/reverse-nodes-in-k-group.md index ad54de13e..f5836142d 100644 --- a/articles/reverse-nodes-in-k-group.md +++ b/articles/reverse-nodes-in-k-group.md @@ -251,6 +251,47 @@ class Solution { } ``` +```swift +/** + * Definition for singly-linked list. + * public class ListNode { + * public var val: Int + * public var next: ListNode? + * public init() { self.val = 0; self.next = nil; } + * public init(_ val: Int) { self.val = val; self.next = nil; } + * public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; } + * } + */ +class Solution { + func reverseKGroup(_ head: ListNode?, _ k: Int) -> ListNode? { + var cur = head + var group = 0 + + while cur != nil && group < k { + cur = cur!.next + group += 1 + } + + if group == k { + cur = reverseKGroup(cur, k) + + var tempHead = head + while group > 0 { + let tmp = tempHead!.next + tempHead!.next = cur + cur = tempHead + tempHead = tmp + group -= 1 + } + + return cur + } + + return head + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -603,6 +644,57 @@ class Solution { } ``` +```swift +/** + * Definition for singly-linked list. + * public class ListNode { + * public var val: Int + * public var next: ListNode? + * public init() { self.val = 0; self.next = nil; } + * public init(_ val: Int) { self.val = val; self.next = nil; } + * public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; } + * } + */ +class Solution { + func reverseKGroup(_ head: ListNode?, _ k: Int) -> ListNode? { + let dummy = ListNode(0, head) + var groupPrev: ListNode? = dummy + + while true { + guard let kth = getKth(groupPrev, k) else { + break + } + let groupNext = kth.next + + var prev: ListNode? = kth.next + var curr = groupPrev?.next + + while curr !== groupNext { + let tmp = curr?.next + curr?.next = prev + prev = curr + curr = tmp + } + + let tmp = groupPrev?.next + groupPrev?.next = kth + groupPrev = tmp + } + return dummy.next + } + + private func getKth(_ curr: ListNode?, _ k: Int) -> ListNode? { + var curr = curr + var k = k + while curr != nil && k > 0 { + curr = curr?.next + k -= 1 + } + return curr + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/rotate-matrix.md b/articles/rotate-matrix.md index 2f050d984..c7ea787f1 100644 --- a/articles/rotate-matrix.md +++ b/articles/rotate-matrix.md @@ -145,6 +145,27 @@ class Solution { } ``` +```swift +class Solution { + func rotate(_ matrix: inout [[Int]]) { + let n = matrix.count + var rotated = Array(repeating: Array(repeating: 0, count: n), count: n) + + for i in 0.. Int { + var grid = grid + var queue = Deque<(Int, Int)>() + var fresh = 0 + var time = 0 + + let ROWS = grid.count + let COLS = grid[0].count + + for r in 0.. 0 && !queue.isEmpty { + let length = queue.count + for _ in 0..= 0 && row < ROWS && col >= 0 && col < COLS && grid[row][col] == 1 { + grid[row][col] = 2 + queue.append((row, col)) + fresh -= 1 + } + } + } + time += 1 + } + + return fresh == 0 ? time : -1 + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -704,6 +752,64 @@ class Solution { } ``` +```swift +class Solution { + func orangesRotting(_ grid: [[Int]]) -> Int { + var grid = grid + let ROWS = grid.count + let COLS = grid[0].count + var fresh = 0 + var time = 0 + + for r in 0.. 0 { + var flag = false + for r in 0..= 0 && row < ROWS && col >= 0 && + col < COLS && grid[row][col] == 1) { + grid[row][col] = 3 + fresh -= 1 + flag = true + } + } + } + } + } + + if !flag { + return -1 + } + + for r in 0.. Bool { + if p == nil && q == nil { + return true + } + if let p = p, let q = q, p.val == q.val { + return isSameTree(p.left, q.left) && isSameTree(p.right, q.right) + } else { + return false + } + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -444,6 +474,45 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func isSameTree(_ p: TreeNode?, _ q: TreeNode?) -> Bool { + var stack: [(TreeNode?, TreeNode?)] = [(p, q)] + + while !stack.isEmpty { + let (node1, node2) = stack.removeLast() + + if node1 == nil && node2 == nil { + continue + } + if node1 == nil || node2 == nil || node1!.val != node2!.val { + return false + } + + stack.append((node1!.right, node2!.right)) + stack.append((node1!.left, node2!.left)) + } + + return true + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -742,6 +811,51 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func isSameTree(_ p: TreeNode?, _ q: TreeNode?) -> Bool { + var q1 = Deque() + var q2 = Deque() + q1.append(p) + q2.append(q) + + while !q1.isEmpty && !q2.isEmpty { + let nodeP = q1.removeFirst() + let nodeQ = q2.removeFirst() + + if nodeP == nil && nodeQ == nil { + continue + } + if nodeP == nil || nodeQ == nil || nodeP!.val != nodeQ!.val { + return false + } + + q1.append(nodeP!.left) + q1.append(nodeP!.right) + q2.append(nodeQ!.left) + q2.append(nodeQ!.right) + } + + return true + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/search-2d-matrix.md b/articles/search-2d-matrix.md index 722cbe2b6..45181e5df 100644 --- a/articles/search-2d-matrix.md +++ b/articles/search-2d-matrix.md @@ -106,6 +106,21 @@ class Solution { } ``` +```swift +class Solution { + func searchMatrix(_ matrix: [[Int]], _ target: Int) -> Bool { + for r in 0.. Bool { + let m = matrix.count + let n = matrix[0].count + var r = 0, c = n - 1 + + while r < m && c >= 0 { + if matrix[r][c] > target { + c -= 1 + } else if matrix[r][c] < target { + r += 1 + } else { + return true + } + } + return false + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -546,6 +582,44 @@ class Solution { } ``` +```swift +class Solution { + func searchMatrix(_ matrix: [[Int]], _ target: Int) -> Bool { + let ROWS = matrix.count + let COLS = matrix[0].count + + var top = 0, bot = ROWS - 1 + while top <= bot { + let row = (top + bot) / 2 + if target > matrix[row][COLS - 1] { + top = row + 1 + } else if target < matrix[row][0] { + bot = row - 1 + } else { + break + } + } + + if !(top <= bot) { + return false + } + let row = (top + bot) / 2 + var l = 0, r = COLS - 1 + while l <= r { + let m = (l + r) / 2 + if target > matrix[row][m] { + l = m + 1 + } else if target < matrix[row][m] { + r = m - 1 + } else { + return true + } + } + return false + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -718,6 +792,31 @@ class Solution { } ``` +```swift +class Solution { + func searchMatrix(_ matrix: [[Int]], _ target: Int) -> Bool { + let ROWS = matrix.count + let COLS = matrix[0].count + + var l = 0, r = ROWS * COLS - 1 + while l <= r { + let m = l + (r - l) / 2 + let row = m / COLS + let col = m % COLS + + if target > matrix[row][col] { + l = m + 1 + } else if target < matrix[row][col] { + r = m - 1 + } else { + return true + } + } + return false + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/search-for-word-ii.md b/articles/search-for-word-ii.md index d304ea983..519307f04 100644 --- a/articles/search-for-word-ii.md +++ b/articles/search-for-word-ii.md @@ -282,6 +282,53 @@ class Solution { } ``` +```swift +class Solution { + func findWords(_ board: [[Character]], _ words: [String]) -> [String] { + let ROWS = board.count + let COLS = board[0].count + var res: [String] = [] + var board = board + + func backtrack(_ r: Int, _ c: Int, _ i: Int, _ word: [Character]) -> Bool { + if i == word.count { + return true + } + if r < 0 || c < 0 || r >= ROWS || c >= COLS || board[r][c] != word[i] { + return false + } + + board[r][c] = "*" + let ret = backtrack(r + 1, c, i + 1, word) || + backtrack(r - 1, c, i + 1, word) || + backtrack(r, c + 1, i + 1, word) || + backtrack(r, c - 1, i + 1, word) + board[r][c] = word[i] + return ret + } + + for word in words { + var flag = false + let wordArray = Array(word) + for r in 0.. children; boolean isWord; @@ -743,6 +790,68 @@ class Solution { } ``` +```swift +class TrieNode { + var children: [Character: TrieNode] = [:] + var isWord: Bool = false + + func addWord(_ word: String) { + var current = self + for char in word { + if current.children[char] == nil { + current.children[char] = TrieNode() + } + current = current.children[char]! + } + current.isWord = true + } +} + +class Solution { + func findWords(_ board: [[Character]], _ words: [String]) -> [String] { + let root = TrieNode() + for word in words { + root.addWord(word) + } + + let ROWS = board.count + let COLS = board[0].count + var result = Set() + var visited = Set<[Int]>() + + func dfs(_ r: Int, _ c: Int, _ node: TrieNode, _ word: String) { + if r < 0 || c < 0 || r >= ROWS || c >= COLS || + visited.contains([r, c]) || node.children[board[r][c]] == nil { + return + } + + visited.insert([r, c]) + let nextNode = node.children[board[r][c]]! + let newWord = word + String(board[r][c]) + + if nextNode.isWord { + result.insert(newWord) + } + + dfs(r + 1, c, nextNode, newWord) + dfs(r - 1, c, nextNode, newWord) + dfs(r, c + 1, nextNode, newWord) + dfs(r, c - 1, nextNode, newWord) + + visited.remove([r, c]) + } + + for r in 0.. [String] { + let root = TrieNode() + for i in 0.. Int { + return Int(c.asciiValue! - Character("a").asciiValue!) + } + + func dfs(_ r: Int, _ c: Int, _ node: TrieNode) { + if r < 0 || c < 0 || r >= ROWS || c >= COLS || + boardCopy[r][c] == "*" || + node.children[getIndex(boardCopy[r][c])] == nil { + return + } + + let tmp = boardCopy[r][c] + boardCopy[r][c] = "*" + let prev = node + let nextNode = node.children[getIndex(tmp)]! + + if nextNode.idx != -1 { + res.append(words[nextNode.idx]) + nextNode.idx = -1 + nextNode.refs -= 1 + if nextNode.refs == 0 { + prev.children[getIndex(tmp)] = nil + boardCopy[r][c] = tmp + return + } + } + + dfs(r + 1, c, nextNode) + dfs(r - 1, c, nextNode) + dfs(r, c + 1, nextNode) + dfs(r, c - 1, nextNode) + + boardCopy[r][c] = tmp + } + + for r in 0.. Bool { + let ROWS = board.count + let COLS = board[0].count + var path = Set<[Int]>() + let wordArray = Array(word) + + func dfs(_ r: Int, _ c: Int, _ i: Int) -> Bool { + if i == wordArray.count { + return true + } + if (r < 0 || c < 0 || r >= ROWS || c >= COLS || + board[r][c] != wordArray[i] || path.contains([r, c])) { + return false + } + + path.insert([r, c]) + let res = dfs(r + 1, c, i + 1) || + dfs(r - 1, c, i + 1) || + dfs(r, c + 1, i + 1) || + dfs(r, c - 1, i + 1) + path.remove([r, c]) + return res + } + + for r in 0.. Bool { + let ROWS = board.count + let COLS = board[0].count + var visited = Array(repeating: Array(repeating: false, count: COLS), count: ROWS) + let wordArray = Array(word) + + func dfs(_ r: Int, _ c: Int, _ i: Int) -> Bool { + if i == wordArray.count { + return true + } + if (r < 0 || c < 0 || r >= ROWS || c >= COLS || + board[r][c] != wordArray[i] || visited[r][c]) { + return false + } + + visited[r][c] = true + let res = dfs(r + 1, c, i + 1) || + dfs(r - 1, c, i + 1) || + dfs(r, c + 1, i + 1) || + dfs(r, c - 1, i + 1) + visited[r][c] = false + return res + } + + for r in 0.. Bool { + let ROWS = board.count + let COLS = board[0].count + let wordArray = Array(word) + var board = board + + func dfs(_ r: Int, _ c: Int, _ i: Int) -> Bool { + if i == wordArray.count { + return true + } + if (r < 0 || c < 0 || r >= ROWS || c >= COLS || + board[r][c] != wordArray[i] || board[r][c] == "#") { + return false + } + + let temp = board[r][c] + board[r][c] = "#" + let res = dfs(r + 1, c, i + 1) || + dfs(r - 1, c, i + 1) || + dfs(r, c + 1, i + 1) || + dfs(r, c - 1, i + 1) + board[r][c] = temp + return res + } + + for r in 0.. String { + var res = [String]() + + func dfs(_ node: TreeNode?) { + guard let node = node else { + res.append("N") + return + } + res.append("\(node.val)") + dfs(node.left) + dfs(node.right) + } + + dfs(root) + return res.joined(separator: ",") + } + + func deserialize(_ data: String) -> TreeNode? { + var vals = data.split(separator: ",").map { String($0) } + var i = 0 + + func dfs() -> TreeNode? { + if vals[i] == "N" { + i += 1 + return nil + } + let node = TreeNode(Int(vals[i])!) + i += 1 + node.left = dfs() + node.right = dfs() + return node + } + + return dfs() + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -863,6 +918,76 @@ class Codec { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init(_ val: Int) { + * self.val = val + * self.left = nil + * self.right = nil + * } + * } + */ + +class Codec { + + func serialize(_ root: TreeNode?) -> String { + guard let root = root else { + return "N" + } + + var res = [String]() + var queue: Deque = [root] + + while !queue.isEmpty { + let node = queue.removeFirst() + if let node = node { + res.append("\(node.val)") + queue.append(node.left) + queue.append(node.right) + } else { + res.append("N") + } + } + + return res.joined(separator: ",") + } + + func deserialize(_ data: String) -> TreeNode? { + let vals = data.split(separator: ",").map { String($0) } + guard vals[0] != "N" else { + return nil + } + + let root = TreeNode(Int(vals[0])!) + var queue: Deque = [root] + var index = 1 + + while !queue.isEmpty { + let node = queue.popFirst()! + + if vals[index] != "N" { + node.left = TreeNode(Int(vals[index])!) + queue.append(node.left!) + } + index += 1 + + if vals[index] != "N" { + node.right = TreeNode(Int(vals[index])!) + queue.append(node.right!) + } + index += 1 + } + + return root + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/set-zeroes-in-matrix.md b/articles/set-zeroes-in-matrix.md index 5a265e1f5..72cef4283 100644 --- a/articles/set-zeroes-in-matrix.md +++ b/articles/set-zeroes-in-matrix.md @@ -208,6 +208,35 @@ class Solution { } ``` +```swift +class Solution { + func setZeroes(_ matrix: inout [[Int]]) { + let rows = matrix.count + let cols = matrix[0].count + var mark = matrix + + for r in 0.. 0 { + matrix[r][0] = 0 + } else { + rowZero = true + } + } + } + } + + for r in 1.. Int { + for i in 0.. Int { + var seen = Set() + + for num in nums { + if seen.contains(num) { + seen.remove(num) + } else { + seen.insert(num) + } + } + + return seen.first! + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -397,6 +435,25 @@ class Solution { } ``` +```swift +class Solution { + func singleNumber(_ nums: [Int]) -> Int { + var nums = nums.sorted() + var i = 0 + + while i < nums.count - 1 { + if nums[i] == nums[i + 1] { + i += 2 + } else { + return nums[i] + } + } + + return nums[i] + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -494,6 +551,18 @@ class Solution { } ``` +```swift +class Solution { + func singleNumber(_ nums: [Int]) -> Int { + var res = 0 + for num in nums { + res ^= num + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/sliding-window-maximum.md b/articles/sliding-window-maximum.md index c4accb268..a7af08296 100644 --- a/articles/sliding-window-maximum.md +++ b/articles/sliding-window-maximum.md @@ -133,12 +133,32 @@ class Solution { } ``` +```swift +class Solution { + func maxSlidingWindow(_ nums: [Int], _ k: Int) -> [Int] { + var output = [Int]() + + for i in 0...(nums.count - k) { + var maxi = nums[i] + for j in i..<(i + k) { + maxi = max(maxi, nums[j]) + } + output.append(maxi) + } + + return output + } +} +``` + ::tabs-end ### Time & Space Complexity * Time complexity: $O(n * k)$ -* Space complexity: $O(1)$ +* Space complexity: + * $O(1)$ extra space. + * $O(n - k + 1)$ space for the output array. > Where $n$ is the length of the array and $k$ is the size of the window. @@ -537,6 +557,64 @@ class Solution { } ``` +```swift +class SegmentTree { + private var n: Int + private var tree: [Int] + + init(_ N: Int, _ A: [Int]) { + self.n = N + while (self.n & (self.n - 1)) != 0 { + self.n += 1 + } + self.tree = [Int](repeating: Int.min, count: 2 * self.n) + build(N, A) + } + + private func build(_ N: Int, _ A: [Int]) { + for i in 0.. Int { + var res = Int.min + var l = l + n + var r = r + n + 1 + while l < r { + if l & 1 != 0 { + res = max(res, tree[l]) + l += 1 + } + if r & 1 != 0 { + r -= 1 + res = max(res, tree[r]) + } + l >>= 1 + r >>= 1 + } + return res + } +} + +class Solution { + func maxSlidingWindow(_ nums: [Int], _ k: Int) -> [Int] { + let n = nums.count + let segTree = SegmentTree(n, nums) + var output = [Int]() + + for i in 0...(n - k) { + output.append(segTree.query(i, i + k - 1)) + } + + return output + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -635,8 +713,9 @@ class Solution { ```csharp public class Solution { public int[] MaxSlidingWindow(int[] nums, int k) { - PriorityQueue<(int val, int idx), int> pq = new PriorityQueue<(int val, int idx), int> - (Comparer.Create((a, b) => b.CompareTo(a))); + PriorityQueue<(int val, int idx), int> pq = new PriorityQueue<(int val, int idx), int>( + Comparer.Create((a, b) => b.CompareTo(a)) + ); int[] output = new int[nums.Length - k + 1]; int idx = 0; @@ -700,6 +779,36 @@ class Solution { } ``` +```swift +class Solution { + func maxSlidingWindow(_ nums: [Int], _ k: Int) -> [Int] { + var heap = Heap() + var output = [Int]() + + for i in 0..= k - 1 { + while heap.max!.index <= i - k { + heap.removeMax() + } + output.append(heap.max!.num) + } + } + return output + } +} + +struct Item: Comparable { + let num: Int + let index: Int + + static func < (lhs: Item, rhs: Item) -> Bool { + return lhs.num < rhs.num + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -963,6 +1072,41 @@ class Solution { } ``` +```swift +class Solution { + func maxSlidingWindow(_ nums: [Int], _ k: Int) -> [Int] { + let n = nums.count + var leftMax = [Int](repeating: 0, count: n) + var rightMax = [Int](repeating: 0, count: n) + + leftMax[0] = nums[0] + rightMax[n - 1] = nums[n - 1] + + for i in 1.. [Int] { + var output = [Int]() + var deque = [Int]() // Index + var l = 0, r = 0 + + while r < nums.count { + while !deque.isEmpty && nums[deque.last!] < nums[r] { + deque.removeLast() + } + deque.append(r) + + if l > deque.first! { + deque.removeFirst() + } + + if (r + 1) >= k { + output.append(nums[deque.first!]) + l += 1 + } + r += 1 + } + + return output + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/spiral-matrix.md b/articles/spiral-matrix.md index 7935874fc..2e82fff76 100644 --- a/articles/spiral-matrix.md +++ b/articles/spiral-matrix.md @@ -198,6 +198,39 @@ class Solution { } ``` +```swift +class Solution { + func spiralOrder(_ matrix: [[Int]]) -> [Int] { + var m = matrix.count + var n = matrix[0].count + var res: [Int] = [] + + // append all the elements in the given direction + func dfs(_ row: Int, _ col: Int, _ r: inout Int, _ c: inout Int, _ dr: Int, _ dc: Int) { + if row == 0 || col == 0 { + return + } + + for _ in 0.. [Int] { + var res: [Int] = [] + var left = 0, right = matrix[0].count + var top = 0, bottom = matrix.count + + while left < right && top < bottom { + for i in left.. [Int] { + var res: [Int] = [] + let directions = [(0, 1), (1, 0), (0, -1), (-1, 0)] + var steps = [matrix[0].count, matrix.count - 1] + + var r = 0, c = -1, d = 0 + while steps[d & 1] > 0 { + for _ in 0.. String { + if strs.isEmpty { return "" } + + var sizes: [Int] = [] + var res = "" + for s in strs { + sizes.append(s.count) + } + for sz in sizes { + res += String(sz) + res += "," + } + + res += "#" + for s in strs { + res += s + } + return res + } + + func decode(_ s: String) -> [String] { + if s.isEmpty { return [] } + let sArr = Array(s) + var sizes: [Int] = [] + var res: [String] = [] + var i = 0 + + while sArr[i] != "#" { + var cur = "" + while sArr[i] != "," { + cur.append(sArr[i]) + i += 1 + } + sizes.append(Int(cur)!) + i += 1 + } + + i += 1 + for sz in sizes { + let substring = String(sArr[i.. String { + var res = "" + for s in strs { + res += "\(s.count)#\(s)" + } + return res + } + + func decode(_ s: String) -> [String] { + var res = [String]() + let sArr = Array(s) + var i = 0 + + while i < sArr.count { + var j = i + while sArr[j] != "#" { + j += 1 + } + let lengthStr = String(sArr[i.. [[Int]] { + var res = Set<[Int]>() + var subset = [Int]() + let nums = nums.sorted() + + func backtrack(_ i: Int) { + if i == nums.count { + res.insert(subset) + return + } + + subset.append(nums[i]) + backtrack(i + 1) + subset.removeLast() + backtrack(i + 1) + } + + backtrack(0) + return Array(res) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -202,7 +227,7 @@ class Solution { --- -## 2. Backtracking (Pick / Not Pick) +## 2. Backtracking - I ::tabs-start @@ -405,16 +430,48 @@ class Solution { } ``` +```swift +class Solution { + func subsetsWithDup(_ nums: [Int]) -> [[Int]] { + var res = [[Int]]() + var subset = [Int]() + let nums = nums.sorted() + + func backtrack(_ i: Int) { + if i == nums.count { + res.append(subset) + return + } + + subset.append(nums[i]) + backtrack(i + 1) + subset.removeLast() + + var j = i + while j + 1 < nums.count && nums[j] == nums[j + 1] { + j += 1 + } + backtrack(j + 1) + } + + backtrack(0) + return res + } +} +``` + ::tabs-end ### Time & Space Complexity * Time complexity: $O(n * 2 ^ n)$ -* Space complexity: $O(n)$ +* Space complexity: + * $O(n)$ extra space. + * $O(2 ^ n)$ space for the output list. --- -## 3. Backtracking +## 3. Backtracking - II ::tabs-start @@ -595,12 +652,40 @@ class Solution { } ``` +```swift +class Solution { + func subsetsWithDup(_ nums: [Int]) -> [[Int]] { + var res = [[Int]]() + var subset = [Int]() + let nums = nums.sorted() + + func backtrack(_ i: Int) { + res.append(subset) + + for j in i.. i && nums[j] == nums[j - 1] { + continue + } + subset.append(nums[j]) + backtrack(j + 1) + subset.removeLast() + } + } + + backtrack(0) + return res + } +} +``` + ::tabs-end ### Time & Space Complexity * Time complexity: $O(n * 2 ^ n)$ -* Space complexity: $O(n)$ +* Space complexity: + * $O(n)$ extra space. + * $O(2 ^ n)$ space for the output list. --- @@ -614,6 +699,7 @@ class Solution: nums.sort() res = [[]] prev_Idx = idx = 0 + for i in range(len(nums)): idx = prev_idx if i >= 1 and nums[i] == nums[i - 1] else 0 prev_idx = len(res) @@ -621,6 +707,7 @@ class Solution: tmp = res[j].copy() tmp.append(nums[i]) res.append(tmp) + return res ``` @@ -632,6 +719,7 @@ public class Solution { res.add(new ArrayList<>()); int prevIdx = 0; int idx = 0; + for (int i = 0; i < nums.length; i++) { idx = (i >= 1 && nums[i] == nums[i - 1]) ? prevIdx : 0; prevIdx = res.size(); @@ -641,6 +729,7 @@ public class Solution { res.add(tmp); } } + return res; } } @@ -654,6 +743,7 @@ public: vector> res = {{}}; int prevIdx = 0; int idx = 0; + for (int i = 0; i < nums.size(); i++) { idx = (i >= 1 && nums[i] == nums[i - 1]) ? prevIdx : 0; prevIdx = res.size(); @@ -663,6 +753,7 @@ public: res.push_back(tmp); } } + return res; } }; @@ -679,6 +770,7 @@ class Solution { const res = [[]]; let prevIdx = 0; let idx = 0; + for (let i = 0; i < nums.length; i++) { idx = (i >= 1 && nums[i] === nums[i - 1]) ? prevIdx : 0; prevIdx = res.length; @@ -688,6 +780,7 @@ class Solution { res.push(tmp); } } + return res; } } @@ -700,6 +793,7 @@ public class Solution { var res = new List> { new List() }; int prevIdx = 0; int idx = 0; + for (int i = 0; i < nums.Length; i++) { idx = (i >= 1 && nums[i] == nums[i - 1]) ? prevIdx : 0; prevIdx = res.Count; @@ -709,6 +803,7 @@ public class Solution { res.Add(tmp); } } + return res; } } @@ -761,9 +856,35 @@ class Solution { } ``` +```swift +class Solution { + func subsetsWithDup(_ nums: [Int]) -> [[Int]] { + let nums = nums.sorted() + var res: [[Int]] = [[]] + var prevIdx = 0 + var idx = 0 + + for i in 0..= 1 && nums[i] == nums[i - 1]) ? prevIdx : 0 + prevIdx = res.count + + for j in idx.. List[List[int]]: res = [] - subset = [] def dfs(i): @@ -172,12 +171,37 @@ class Solution { } ``` +```swift +class Solution { + func subsets(_ nums: [Int]) -> [[Int]] { + var res = [[Int]]() + var subset = [Int]() + + func dfs(_ i: Int) { + if i >= nums.count { + res.append(subset) + return + } + subset.append(nums[i]) + dfs(i + 1) + subset.removeLast() + dfs(i + 1) + } + + dfs(0) + return res + } +} +``` + ::tabs-end ### Time & Space Complexity * Time complexity: $O(n * 2 ^ n)$ -* Space complexity: $O(n)$ +* Space complexity: + * $O(n)$ extra space. + * $O(2 ^ n)$ for the output list. --- @@ -316,12 +340,28 @@ class Solution { } ``` +```swift +class Solution { + func subsets(_ nums: [Int]) -> [[Int]] { + var res: [[Int]] = [[]] + + for num in nums { + res += res.map { $0 + [num] } + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity * Time complexity: $O(n * 2 ^ n)$ -* Space complexity: $O(n)$ +* Space complexity: + * $O(n)$ extra space. + * $O(2 ^ n)$ for the output list. --- @@ -461,9 +501,32 @@ class Solution { } ``` +```swift +class Solution { + func subsets(_ nums: [Int]) -> [[Int]] { + let n = nums.count + var res: [[Int]] = [] + + for i in 0..<(1 << n) { + var subset: [Int] = [] + for j in 0.. Bool { + if subRoot == nil { + return true + } + if root == nil { + return false + } + if sameTree(root, subRoot) { + return true + } + return isSubtree(root?.left, subRoot) || isSubtree(root?.right, subRoot) + } + + func sameTree(_ root: TreeNode?, _ subRoot: TreeNode?) -> Bool { + if root == nil && subRoot == nil { + return true + } + if let root = root, let subRoot = subRoot, root.val == subRoot.val { + return sameTree(root.left, subRoot.left) && sameTree(root.right, subRoot.right) + } + return false + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -319,11 +361,10 @@ class Solution { class Solution: def serialize(self, root: Optional[TreeNode]) -> str: - if root == None: - return "$#" - - return ("$" + str(root.val) + - self.serialize(root.left) + self.serialize(root.right)) + if root == None: + return "$#" + + return ("$" + str(root.val) + self.serialize(root.left) + self.serialize(root.right)) def z_function(self, s: str) -> list: z = [0] * len(s) @@ -341,10 +382,10 @@ class Solution: serialized_root = self.serialize(root) serialized_subRoot = self.serialize(subRoot) combined = serialized_subRoot + "|" + serialized_root - + z_values = self.z_function(combined) sub_len = len(serialized_subRoot) - + for i in range(sub_len + 1, len(combined)): if z_values[i] == sub_len: return True @@ -492,8 +533,7 @@ class Solution { if (root === null) { return "$#"; } - return "$" + root.val + - this.serialize(root.left) + this.serialize(root.right); + return "$" + root.val + this.serialize(root.left) + this.serialize(root.right); } /** @@ -714,6 +754,69 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func serialize(_ root: TreeNode?) -> String { + guard let root = root else { + return "$#" + } + return "$\(root.val)" + serialize(root.left) + serialize(root.right) + } + + func zFunction(_ s: String) -> [Int] { + let n = s.count + var z = [Int](repeating: 0, count: n) + var l = 0, r = 0 + let chars = Array(s) + + for i in 1.. r { + l = i + r = i + z[i] - 1 + } + } + return z + } + + func isSubtree(_ root: TreeNode?, _ subRoot: TreeNode?) -> Bool { + let serializedRoot = serialize(root) + let serializedSubRoot = serialize(subRoot) + let combined = serializedSubRoot + "|" + serializedRoot + + let zValues = zFunction(combined) + let subLen = serializedSubRoot.count + + for i in (subLen + 1).. Int { + return a + b + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -250,6 +258,32 @@ class Solution { } ``` +```swift +class Solution { + func getSum(_ a: Int, _ b: Int) -> Int { + var carry = 0 + var res = 0 + let mask = 0xFFFFFFFF + + for i in 0..<32 { + let aBit = (a >> i) & 1 + let bBit = (b >> i) & 1 + let curBit = aBit ^ bBit ^ carry + carry = (aBit + bBit + carry) >= 2 ? 1 : 0 + if curBit == 1 { + res |= (1 << i) + } + } + + if res > 0x7FFFFFFF { + res = ~(res ^ mask) + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -379,6 +413,25 @@ class Solution { } ``` +```swift +class Solution { + func getSum(_ a: Int, _ b: Int) -> Int { + let mask = 0xFFFFFFFF + let maxInt = 0x7FFFFFFF + var a = a + var b = b + + while b != 0 { + let carry = (a & b) << 1 + a = (a ^ b) & mask + b = carry & mask + } + + return a <= maxInt ? a : ~(a ^ mask) + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/surrounded-regions.md b/articles/surrounded-regions.md index f1009a0bc..1c0c5445c 100644 --- a/articles/surrounded-regions.md +++ b/articles/surrounded-regions.md @@ -330,6 +330,54 @@ class Solution { } ``` +```swift +class Solution { + func solve(_ board: inout [[Character]]) { + let ROWS = board.count + let COLS = board[0].count + + func capture(_ r: Int, _ c: Int) { + if r < 0 || c < 0 || r == ROWS || c == COLS || board[r][c] != "O" { + return + } + board[r][c] = "T" + capture(r + 1, c) + capture(r - 1, c) + capture(r, c + 1) + capture(r, c - 1) + } + + for r in 0.. { - let q = []; + let q = new Queue(); for (let r = 0; r < ROWS; r++) { for (let c = 0; c < COLS; c++) { if (r === 0 || r === ROWS - 1 || @@ -506,8 +554,8 @@ class Solution { } } } - while (q.length) { - let [r, c] = q.shift(); + while (!q.isEmpty()) { + let [r, c] = q.pop(); if (board[r][c] === 'O') { board[r][c] = 'T'; for (let [dr, dc] of directions) { @@ -684,6 +732,53 @@ class Solution { } ``` +```swift +class Solution { + func solve(_ board: inout [[Character]]) { + let ROWS = board.count + let COLS = board[0].count + let directions = [(1, 0), (-1, 0), (0, 1), (0, -1)] + + func capture() { + var queue = Deque<(Int, Int)>() + for r in 0..= 0, nr < ROWS, nc >= 0, nc < COLS { + queue.append((nr, nc)) + } + } + } + } + } + + capture() + + for r in 0.. Int { + if parent[node] != node { + parent[node] = find(parent[node]) + } + return parent[node] + } + + func union(_ u: Int, _ v: Int) { + let pu = find(u) + let pv = find(v) + if pu == pv { return } + if size[pu] >= size[pv] { + size[pu] += size[pv] + parent[pv] = pu + } else { + size[pv] += size[pu] + parent[pu] = pv + } + } + + func connected(_ u: Int, _ v: Int) -> Bool { + return find(u) == find(v) + } +} + +class Solution { + func solve(_ board: inout [[Character]]) { + let ROWS = board.count + let COLS = board[0].count + let directions = [(1, 0), (-1, 0), (0, 1), (0, -1)] + let dsu = DSU(ROWS * COLS + 1) + let N = ROWS * COLS + + for r in 0..= 0, nr < ROWS, nc >= 0, nc < COLS, board[nr][nc] == "O" { + dsu.union(r * COLS + c, nr * COLS + nc) + } + } + } + } + } + + for r in 0.. Int { + let n = grid.count + var visit = Array(repeating: Array(repeating: false, count: n), count: n) + + func dfs(_ node: (Int, Int), _ t: Int) -> Int { + let (r, c) = node + if r < 0 || c < 0 || r >= n || c >= n || visit[r][c] { + return 1000000 + } + if r == n - 1 && c == n - 1 { + return max(t, grid[r][c]) + } + visit[r][c] = true + let t = max(t, grid[r][c]) + let res = min(dfs((r + 1, c), t), + dfs((r - 1, c), t), + dfs((r, c + 1), t), + dfs((r, c - 1), t)) + visit[r][c] = false + return res + } + + return dfs((0, 0), 0) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -544,6 +573,51 @@ class Solution { } ``` +```swift +class Solution { + func swimInWater(_ grid: [[Int]]) -> Int { + let n = grid.count + var visit = Array(repeating: Array(repeating: false, count: n), count: n) + var minH = grid[0][0], maxH = grid[0][0] + + for row in 0.. Bool { + let (r, c) = node + if r < 0 || c < 0 || r >= n || c >= n || visit[r][c] || grid[r][c] > t { + return false + } + if r == n - 1 && c == n - 1 { + return true + } + visit[r][c] = true + return dfs((r + 1, c), t) || + dfs((r - 1, c), t) || + dfs((r, c + 1), t) || + dfs((r, c - 1), t) + } + + for t in minH...maxH { + if dfs((0, 0), t) { + return t + } + for r in 0.. Int { + let n = grid.count + var visit = Array(repeating: Array(repeating: false, count: n), count: n) + var minH = grid[0][0], maxH = grid[0][0] + + for row in 0.. Bool { + let (r, c) = node + if r < 0 || c < 0 || r >= n || c >= n || visit[r][c] || grid[r][c] > t { + return false + } + if r == n - 1 && c == n - 1 { + return true + } + visit[r][c] = true + return dfs((r + 1, c), t) || + dfs((r - 1, c), t) || + dfs((r, c + 1), t) || + dfs((r, c - 1), t) + } + + var l = minH, r = maxH + while l < r { + let m = (l + r) >> 1 + if dfs((0, 0), m) { + r = m + } else { + l = m + 1 + } + for row in 0.. Bool { + return lhs.time < rhs.time + } +} + +class Solution { + func swimInWater(_ grid: [[Int]]) -> Int { + let N = grid.count + var visit = Set<[Int]>() + var minHeap = Heap() + + let directions = [(0, 1), (0, -1), (1, 0), (-1, 0)] + + minHeap.insert(Item(time: grid[0][0], row: 0, col: 0)) + visit.insert([0, 0]) + + while !minHeap.isEmpty { + let item = minHeap.removeMin() + let t = item.time, r = item.row, c = item.col + + if r == N - 1 && c == N - 1 { + return t + } + + for (dr, dc) in directions { + let neiR = r + dr, neiC = c + dc + if neiR < 0 || neiC < 0 || neiR == N || neiC == N || visit.contains([neiR, neiC]) { + continue + } + visit.insert([neiR, neiC]) + minHeap.insert(Item(time: max(t, grid[neiR][neiC]), row: neiR, col: neiC)) + } + } + + return -1 + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -1230,7 +1398,7 @@ class Solution: ``` ```java -public class DSU { +class DSU { private int[] Parent; private int[] Size; @@ -1625,6 +1793,75 @@ class Solution { } ``` +```swift +class DSU { + private var parent: [Int] + private var size: [Int] + + init(_ n: Int) { + parent = Array(0...(n - 1)) + size = Array(repeating: 1, count: n) + } + + func find(_ node: Int) -> Int { + if parent[node] != node { + parent[node] = find(parent[node]) + } + return parent[node] + } + + func union(_ u: Int, _ v: Int) -> Bool { + let pu = find(u) + let pv = find(v) + if pu == pv { + return false + } + if size[pu] < size[pv] { + parent[pu] = pv + size[pv] += size[pu] + } else { + parent[pv] = pu + size[pu] += size[pv] + } + return true + } + + func connected(_ u: Int, _ v: Int) -> Bool { + return find(u) == find(v) + } +} + +class Solution { + func swimInWater(_ grid: [[Int]]) -> Int { + let N = grid.count + let dsu = DSU(N * N) + var positions = [(Int, Int, Int)]() + let directions = [(0, 1), (1, 0), (0, -1), (-1, 0)] + + for r in 0..= 0, nc >= 0, nr < N, nc < N, grid[nr][nc] <= t { + dsu.union(r * N + c, nr * N + nc) + } + } + if dsu.connected(0, N * N - 1) { + return t + } + } + return -1 + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/target-sum.md b/articles/target-sum.md index 819f11b56..71c10c0c2 100644 --- a/articles/target-sum.md +++ b/articles/target-sum.md @@ -120,6 +120,20 @@ class Solution { } ``` +```swift +class Solution { + func findTargetSumWays(_ nums: [Int], _ target: Int) -> Int { + func backtrack(_ i: Int, _ total: Int) -> Int { + if i == nums.count { + return total == target ? 1 : 0 + } + return backtrack(i + 1, total + nums[i]) + backtrack(i + 1, total - nums[i]) + } + return backtrack(0, 0) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -331,6 +345,29 @@ class Solution { } ``` +```swift +class Solution { + func findTargetSumWays(_ nums: [Int], _ target: Int) -> Int { + let totalSum = nums.reduce(0, +) + var dp = Array(repeating: Array(repeating: Int.min, count: 2 * totalSum + 1), count: nums.count) + + func backtrack(_ i: Int, _ total: Int) -> Int { + if i == nums.count { + return total == target ? 1 : 0 + } + if dp[i][total + totalSum] != Int.min { + return dp[i][total + totalSum] + } + dp[i][total + totalSum] = backtrack(i + 1, total + nums[i]) + + backtrack(i + 1, total - nums[i]) + return dp[i][total + totalSum] + } + + return backtrack(0, 0) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -502,6 +539,24 @@ class Solution { } ``` +```swift +class Solution { + func findTargetSumWays(_ nums: [Int], _ target: Int) -> Int { + let n = nums.count + var dp = Array(repeating: [Int: Int](), count: n + 1) + dp[0][0] = 1 + + for i in 0.. Int { + var dp = [0: 1] + + for num in nums { + var nextDp = [Int: Int]() + for (total, count) in dp { + nextDp[total + num, default: 0] += count + nextDp[total - num, default: 0] += count + } + dp = nextDp + } + return dp[target, default: 0] + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/task-scheduling.md b/articles/task-scheduling.md index d6718ba3f..03e752212 100644 --- a/articles/task-scheduling.md +++ b/articles/task-scheduling.md @@ -330,6 +330,50 @@ class Solution { } ``` +```swift +class Solution { + func leastInterval(_ tasks: [Character], _ n: Int) -> Int { + var count = [Int](repeating: 0, count: 26) + for task in tasks { + count[Int(task.asciiValue! - Character("A").asciiValue!)] += 1 + } + + var arr = [(Int, Int)]() + for i in 0..<26 { + if count[i] > 0 { + arr.append((count[i], i)) + } + } + + var time = 0 + var processed = [Int]() + + while !arr.isEmpty { + var maxi = -1 + for i in 0.. Int { + var count = [Character: Int]() + for task in tasks { + count[task, default: 0] += 1 + } + + var maxHeap = Heap(Array(count.values)) + var time = 0 + var queue = Deque<(Int, Int)>() + + while !maxHeap.isEmpty || !queue.isEmpty { + time += 1 + if maxHeap.isEmpty { + time = queue.first!.1 + } else { + let cnt = maxHeap.popMax()! - 1 + if cnt > 0 { + queue.append((cnt, time + n)) + } + } + if let front = queue.first, front.1 == time { + maxHeap.insert(front.0) + queue.removeFirst() + } + } + + return time + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -775,6 +852,27 @@ class Solution { } ``` +```swift +class Solution { + func leastInterval(_ tasks: [Character], _ n: Int) -> Int { + var count = [Int](repeating: 0, count: 26) + for task in tasks { + count[Int(task.asciiValue! - Character("A").asciiValue!)] += 1 + } + + count.sort() + let maxf = count[25] + var idle = (maxf - 1) * n + + for i in stride(from: 24, through: 0, by: -1) { + idle -= min(maxf - 1, count[i]) + } + + return max(0, idle) + tasks.count + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -951,6 +1049,28 @@ class Solution { } ``` +```swift +class Solution { + func leastInterval(_ tasks: [Character], _ n: Int) -> Int { + var count = [Int](repeating: 0, count: 26) + for task in tasks { + count[Int(task.asciiValue! - Character("A").asciiValue!)] += 1 + } + + let maxf = count.max()! + var maxCount = 0 + for i in count { + if i == maxf { + maxCount += 1 + } + } + + let time = (maxf - 1) * (n + 1) + maxCount + return max(tasks.count, time) + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/three-integer-sum.md b/articles/three-integer-sum.md index 74afca85c..18b4b76b7 100644 --- a/articles/three-integer-sum.md +++ b/articles/three-integer-sum.md @@ -145,6 +145,27 @@ class Solution { } ``` +```swift +class Solution { + func threeSum(_ nums: [Int]) -> [[Int]] { + var res = Set<[Int]>() + let nums = nums.sorted() + + for i in 0.. [[Int]] { + var nums = nums.sorted() + var count = [Int: Int]() + for num in nums { + count[num, default: 0] += 1 + } + + var res = [[Int]]() + for i in 0.. 0 && nums[i] == nums[i - 1] { + continue + } + + for j in (i + 1).. i + 1 && nums[j] == nums[j - 1] { + continue + } + let target = -(nums[i] + nums[j]) + if let cnt = count[target], cnt > 0 { + res.append([nums[i], nums[j], target]) + } + } + + for j in (i + 1).. [[Int]] { + var res = [[Int]]() + var nums = nums.sorted() + + for i in 0.. 0 { + break + } + if i > 0 && a == nums[i - 1] { + continue + } + + var l = i + 1, r = nums.count - 1 + while l < r { + let threeSum = a + nums[l] + nums[r] + if threeSum > 0 { + r -= 1 + } else if threeSum < 0 { + l += 1 + } else { + res.append([a, nums[l], nums[r]]) + l += 1 + r -= 1 + while l < r && nums[l] == nums[l - 1] { + l += 1 + } + } + } + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity * Time complexity: $O(n ^ 2)$ -* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. \ No newline at end of file +* Space complexity: + * $O(1)$ or $O(n)$ extra space depending on the sorting algorithm. + * $O(m)$ space for the output list. + +> Where $m$ is the number of triplets and $n$ is the length of the given array. \ No newline at end of file diff --git a/articles/time-based-key-value-store.md b/articles/time-based-key-value-store.md index bfdc75b3e..8fc87e0e5 100644 --- a/articles/time-based-key-value-store.md +++ b/articles/time-based-key-value-store.md @@ -244,6 +244,40 @@ class TimeMap() { } ``` +```swift +class TimeMap { + private var keyStore: [String: [Int: [String]]] + + init() { + self.keyStore = [:] + } + + func set(_ key: String, _ value: String, _ timestamp: Int) { + if keyStore[key] == nil { + keyStore[key] = [:] + } + if keyStore[key]![timestamp] == nil { + keyStore[key]![timestamp] = [] + } + keyStore[key]![timestamp]!.append(value) + } + + func get(_ key: String, _ timestamp: Int) -> String { + guard let timeMap = keyStore[key] else { + return "" + } + + var seen = 0 + for time in timeMap.keys { + if time <= timestamp { + seen = max(seen, time) + } + } + return seen == 0 ? "" : timeMap[seen]!.last! + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -458,6 +492,44 @@ class TimeMap() { } ``` +```swift +class TimeMap { + private var m: [String: [(Int, String)]] + + init() { + self.m = [:] + } + + func set(_ key: String, _ value: String, _ timestamp: Int) { + if m[key] == nil { + m[key] = [] + } + m[key]!.append((timestamp, value)) + } + + func get(_ key: String, _ timestamp: Int) -> String { + guard let timestamps = m[key] else { + return "" + } + + var l = 0, r = timestamps.count - 1 + var res = "" + + while l <= r { + let mid = (l + r) / 2 + if timestamps[mid].0 <= timestamp { + res = timestamps[mid].1 + l = mid + 1 + } else { + r = mid - 1 + } + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -739,6 +811,44 @@ class TimeMap() { } ``` +```swift +class TimeMap { + private var keyStore: [String: [(String, Int)]] + + init() { + self.keyStore = [:] + } + + func set(_ key: String, _ value: String, _ timestamp: Int) { + if keyStore[key] == nil { + keyStore[key] = [] + } + keyStore[key]!.append((value, timestamp)) + } + + func get(_ key: String, _ timestamp: Int) -> String { + guard let values = keyStore[key] else { + return "" + } + + var res = "" + var l = 0, r = values.count - 1 + + while l <= r { + let m = (l + r) / 2 + if values[m].1 <= timestamp { + res = values[m].0 + l = m + 1 + } else { + r = m - 1 + } + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/top-k-elements-in-list.md b/articles/top-k-elements-in-list.md index ae16871e1..7bca2df74 100644 --- a/articles/top-k-elements-in-list.md +++ b/articles/top-k-elements-in-list.md @@ -156,6 +156,30 @@ class Solution { } ``` +```swift +class Solution { + func topKFrequent(_ nums: [Int], _ k: Int) -> [Int] { + var count = [Int: Int]() + for num in nums { + count[num, default: 0] += 1 + } + + var arr = [(Int, Int)]() + for (num, cnt) in count { + arr.append((cnt, num)) + } + arr.sort { $0.0 < $1.0 } + + var res = [Int]() + while res.count < k { + res.append(arr.removeLast().1) + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -165,7 +189,7 @@ class Solution { --- -## 2. Heap +## 2. Min-Heap ::tabs-start @@ -352,6 +376,41 @@ class Solution { } ``` +```swift +struct NumFreq: Comparable { + let num: Int + let freq: Int + + static func < (lhs: NumFreq, rhs: NumFreq) -> Bool { + return lhs.freq < rhs.freq + } +} + +class Solution { + func topKFrequent(_ nums: [Int], _ k: Int) -> [Int] { + var count = [Int: Int]() + for num in nums { + count[num, default: 0] += 1 + } + + var heap: Heap = [] + for (num, freq) in count { + heap.insert(NumFreq(num: num, freq: freq)) + if heap.count > k { + heap.removeMin() + } + } + + var res = [Int]() + while !heap.isEmpty { + res.append(heap.removeMin().num) + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -564,6 +623,35 @@ class Solution { } ``` +```swift +class Solution { + func topKFrequent(_ nums: [Int], _ k: Int) -> [Int] { + var count = [Int: Int]() + var freq = [[Int]](repeating: [], count: nums.count + 1) + + for num in nums { + count[num, default: 0] += 1 + } + + for (num, cnt) in count { + freq[cnt].append(num) + } + + var res = [Int]() + for i in stride(from: freq.count - 1, through: 1, by: -1) { + for num in freq[i] { + res.append(num) + if res.count == k { + return res + } + } + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/trapping-rain-water.md b/articles/trapping-rain-water.md index 73635a85d..4e8f600b8 100644 --- a/articles/trapping-rain-water.md +++ b/articles/trapping-rain-water.md @@ -197,6 +197,33 @@ class Solution { } ``` +```swift +class Solution { + func trap(_ height: [Int]) -> Int { + if height.isEmpty { + return 0 + } + let n = height.count + var res = 0 + + for i in 0.. Int { + let n = height.count + if n == 0 { + return 0 + } + + var leftMax = [Int](repeating: 0, count: n) + var rightMax = [Int](repeating: 0, count: n) + + leftMax[0] = height[0] + for i in 1.. Int { + if height.isEmpty { + return 0 + } + var stack = [Int]() + var res = 0 + + for i in 0..= height[stack.last!] { + let mid = height[stack.removeLast()] + if !stack.isEmpty { + let right = height[i] + let left = height[stack.last!] + let h = min(right, left) - mid + let w = i - stack.last! - 1 + res += h * w + } + } + stack.append(i) + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -852,6 +936,33 @@ class Solution { } ``` +```swift +class Solution { + func trap(_ height: [Int]) -> Int { + if height.isEmpty { + return 0 + } + + var l = 0, r = height.count - 1 + var leftMax = height[l], rightMax = height[r] + var res = 0 + + while l < r { + if leftMax < rightMax { + l += 1 + leftMax = max(leftMax, height[l]) + res += leftMax - height[l] + } else { + r -= 1 + rightMax = max(rightMax, height[r]) + res += rightMax - height[r] + } + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/two-integer-sum-ii.md b/articles/two-integer-sum-ii.md index 8aea74e9d..f63e71a60 100644 --- a/articles/two-integer-sum-ii.md +++ b/articles/two-integer-sum-ii.md @@ -106,6 +106,21 @@ class Solution { } ``` +```swift +class Solution { + func twoSum(_ numbers: [Int], _ target: Int) -> [Int] { + for i in 0.. [Int] { + for i in 0.. [Int] { + var mp = [Int: Int]() + + for i in 0.. [Int] { + var l = 0, r = numbers.count - 1 + + while l < r { + let curSum = numbers[l] + numbers[r] + + if curSum > target { + r -= 1 + } else if curSum < target { + l += 1 + } else { + return [l + 1, r + 1] + } + } + return [] + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/two-integer-sum.md b/articles/two-integer-sum.md index 5b08e079d..9fba0afdc 100644 --- a/articles/two-integer-sum.md +++ b/articles/two-integer-sum.md @@ -106,6 +106,21 @@ class Solution { } ``` +```swift +class Solution { + func twoSum(_ nums: [Int], _ target: Int) -> [Int] { + for i in 0.. [Int] { + var A = [(Int, Int)]() + for (i, num) in nums.enumerated() { + A.append((num, i)) + } + + A.sort { $0.0 < $1.0 } + var i = 0 + var j = nums.count - 1 + + while i < j { + let cur = A[i].0 + A[j].0 + if cur == target { + return [min(A[i].1, A[j].1), + max(A[i].1, A[j].1)] + } else if cur < target { + i += 1 + } else { + j -= 1 + } + } + return [] + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -469,6 +512,27 @@ class Solution { } ``` +```swift +class Solution { + func twoSum(_ nums: [Int], _ target: Int) -> [Int] { + var indices = [Int: Int]() // val -> index + + for (i, n) in nums.enumerated() { + indices[n] = i + } + + for (i, n) in nums.enumerated() { + let diff = target - n + if let j = indices[diff], j != i { + return [i, j] + } + } + + return [] + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -607,6 +671,24 @@ class Solution { } ``` +```swift +class Solution { + func twoSum(_ nums: [Int], _ target: Int) -> [Int] { + var prevMap = [Int: Int]() // val -> index + + for (i, n) in nums.enumerated() { + let diff = target - n + if let index = prevMap[diff] { + return [index, i] + } + prevMap[n] = i + } + + return [] + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/valid-binary-search-tree.md b/articles/valid-binary-search-tree.md index fd885ddfc..3b076e3c7 100644 --- a/articles/valid-binary-search-tree.md +++ b/articles/valid-binary-search-tree.md @@ -316,6 +316,44 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func isValidBST(_ root: TreeNode?) -> Bool { + guard let root = root else { return true } + if !isValid(root.left, root.val, { $0 < $1 }) || + !isValid(root.right, root.val, { $0 > $1 }) { + return false + } + + return isValidBST(root.left) && isValidBST(root.right) + } + + private func isValid(_ root: TreeNode?, _ limit: Int, _ check: (Int, Int) -> Bool) -> Bool { + guard let root = root else { return true } + if !check(root.val, limit) { + return false + } + + return isValid(root.left, limit, check) && isValid(root.right, limit, check) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -550,6 +588,37 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func isValidBST(_ root: TreeNode?) -> Bool { + return valid(root, Int.min, Int.max) + } + + private func valid(_ node: TreeNode?, _ left: Int, _ right: Int) -> Bool { + guard let node = node else { return true } + if !(left < node.val && node.val < right) { + return false + } + return valid(node.left, left, node.val) && valid(node.right, node.val, right) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -858,6 +927,48 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func isValidBST(_ root: TreeNode?) -> Bool { + guard let root = root else { return true } + + var q = Deque<(TreeNode, Int, Int)>() + q.append((root, Int.min, Int.max)) + + while !q.isEmpty { + let (node, left, right) = q.popFirst()! + + if !(left < node.val && node.val < right) { + return false + } + + if let leftNode = node.left { + q.append((leftNode, left, node.val)) + } + if let rightNode = node.right { + q.append((rightNode, node.val, right)) + } + } + return true + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/valid-parenthesis-string.md b/articles/valid-parenthesis-string.md index 84c0422d8..c412ad605 100644 --- a/articles/valid-parenthesis-string.md +++ b/articles/valid-parenthesis-string.md @@ -148,7 +148,52 @@ func checkValidString(s string) bool { ``` ```kotlin +class Solution { + fun checkValidString(s: String): Boolean { + + fun dfs(i: Int, open: Int): Boolean { + if (open < 0) { + return false + } + if (i == s.length) { + return open == 0 + } + + return when (s[i]) { + '(' -> dfs(i + 1, open + 1) + ')' -> dfs(i + 1, open - 1) + else -> dfs(i + 1, open) || dfs(i + 1, open + 1) || dfs(i + 1, open - 1) + } + } + + return dfs(0, 0) + } +} +``` + +```swift +class Solution { + func checkValidString(_ s: String) -> Bool { + let chars = Array(s) + + func dfs(_ i: Int, _ open: Int) -> Bool { + if open < 0 { return false } + if i == chars.count { return open == 0 } + + if chars[i] == "(" { + return dfs(i + 1, open + 1) + } else if chars[i] == ")" { + return dfs(i + 1, open - 1) + } else { + return dfs(i + 1, open) || + dfs(i + 1, open + 1) || + dfs(i + 1, open - 1) + } + } + return dfs(0, 0) + } +} ``` ::tabs-end @@ -397,6 +442,47 @@ class Solution { } ``` +```swift +class Solution { + func checkValidString(_ s: String) -> Bool { + let n = s.count + let sArr = Array(s) + var memo = Array( + repeating: Array(repeating: nil, count: n + 1), + count: n + 1 + ) + + func dfs(_ i: Int, _ open: Int) -> Bool { + if open < 0 { + return false + } + if i == n { + return open == 0 + } + if let memoized = memo[i][open] { + return memoized + } + + let result: Bool + if sArr[i] == "(" { + result = dfs(i + 1, open + 1) + } else if sArr[i] == ")" { + result = dfs(i + 1, open - 1) + } else { + result = dfs(i + 1, open) || + dfs(i + 1, open + 1) || + dfs(i + 1, open - 1) + } + + memo[i][open] = result + return result + } + + return dfs(0, 0) + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -620,6 +706,40 @@ class Solution { } ``` +```swift +class Solution { + func checkValidString(_ s: String) -> Bool { + let n = s.count + var dp = Array(repeating: Array(repeating: false, count: n + 1), count: n + 1) + dp[n][0] = true + + let chars = Array(s) + + for i in stride(from: n - 1, through: 0, by: -1) { + for open in 0.. 0 { + res = res || dp[i + 1][open - 1] + } + res = res || dp[i + 1][open] + } else { + if chars[i] == "(" { + res = res || dp[i + 1][open + 1] + } else if open > 0 { + res = res || dp[i + 1][open - 1] + } + } + dp[i][open] = res + } + } + + return dp[0][0] + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -815,6 +935,34 @@ class Solution { } ``` +```swift +class Solution { + func checkValidString(_ s: String) -> Bool { + let n = s.count + var dp = Array(repeating: false, count: n + 1) + dp[0] = true + + let chars = Array(s) + + for i in stride(from: n - 1, through: 0, by: -1) { + var new_dp = Array(repeating: false, count: n + 1) + for open in 0.. 0 && dp[open - 1]) || dp[open] + } else if chars[i] == "(" { + new_dp[open] = dp[open + 1] + } else if open > 0 { + new_dp[open] = dp[open - 1] + } + } + dp = new_dp + } + + return dp[0] + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -1034,6 +1182,44 @@ class Solution { } ``` +```swift +class Solution { + func checkValidString(_ s: String) -> Bool { + var left = [Int]() + var star = [Int]() + + let chars = Array(s) + + for (i, ch) in chars.enumerated() { + if ch == "(" { + left.append(i) + } else if ch == "*" { + star.append(i) + } else { + if left.isEmpty && star.isEmpty { + return false + } + if !left.isEmpty { + left.popLast() + } else { + star.popLast() + } + } + } + + while !left.isEmpty && !star.isEmpty { + if left.last! > star.last! { + return false + } + left.popLast() + star.popLast() + } + + return left.isEmpty + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -1236,6 +1422,35 @@ class Solution { } ``` +```swift +class Solution { + func checkValidString(_ s: String) -> Bool { + var leftMin = 0 + var leftMax = 0 + + for c in s { + if c == "(" { + leftMin += 1 + leftMax += 1 + } else if c == ")" { + leftMin -= 1 + leftMax -= 1 + } else { + leftMin -= 1 + leftMax += 1 + } + if leftMax < 0 { + return false + } + if leftMin < 0 { + leftMin = 0 + } + } + return leftMin == 0 + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/valid-sudoku.md b/articles/valid-sudoku.md index 14c8dc735..74fb5deda 100644 --- a/articles/valid-sudoku.md +++ b/articles/valid-sudoku.md @@ -284,6 +284,45 @@ class Solution { } ``` +```swift +class Solution { + func isValidSudoku(_ board: [[Character]]) -> Bool { + for row in 0..<9 { + var seen = Set() + for i in 0..<9 { + if board[row][i] == "." { continue } + if seen.contains(board[row][i]) { return false } + seen.insert(board[row][i]) + } + } + + for col in 0..<9 { + var seen = Set() + for i in 0..<9 { + if board[i][col] == "." { continue } + if seen.contains(board[i][col]) { return false } + seen.insert(board[i][col]) + } + } + + for square in 0..<9 { + var seen = Set() + for i in 0..<3 { + for j in 0..<3 { + let row = (square / 3) * 3 + i + let col = (square % 3) * 3 + j + if board[row][col] == "." { continue } + if seen.contains(board[row][col]) { return false } + seen.insert(board[row][col]) + } + } + } + + return true + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -510,6 +549,36 @@ class Solution { } ``` +```swift +class Solution { + func isValidSudoku(_ board: [[Character]]) -> Bool { + var cols = [Int: Set]() + var rows = [Int: Set]() + var squares = [String: Set]() + + for r in 0..<9 { + for c in 0..<9 { + if board[r][c] == "." { continue } + + let squareKey = "\(r / 3),\(c / 3)" + + if rows[r]?.contains(board[r][c]) == true || + cols[c]?.contains(board[r][c]) == true || + squares[squareKey]?.contains(board[r][c]) == true { + return false + } + + rows[r, default: []].insert(board[r][c]) + cols[c, default: []].insert(board[r][c]) + squares[squareKey, default: []].insert(board[r][c]) + } + } + + return true + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -725,6 +794,35 @@ class Solution { } ``` +```swift +class Solution { + func isValidSudoku(_ board: [[Character]]) -> Bool { + var rows = [Int](repeating: 0, count: 9) + var cols = [Int](repeating: 0, count: 9) + var squares = [Int](repeating: 0, count: 9) + + for r in 0..<9 { + for c in 0..<9 { + if board[r][c] == "." { continue } + + let val = Int(board[r][c].asciiValue! - Character("0").asciiValue!) + let bitmask = 1 << (val - 1) + + if (rows[r] & bitmask) != 0 { return false } + if (cols[c] & bitmask) != 0 { return false } + if (squares[(r / 3) * 3 + (c / 3)] & bitmask) != 0 { return false } + + rows[r] |= bitmask + cols[c] |= bitmask + squares[(r / 3) * 3 + (c / 3)] |= bitmask + } + } + + return true + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/valid-tree.md b/articles/valid-tree.md index a343b676e..7266d9836 100644 --- a/articles/valid-tree.md +++ b/articles/valid-tree.md @@ -266,6 +266,44 @@ class Solution { } ``` +```swift +class Solution { + func validTree(_ n: Int, _ edges: [[Int]]) -> Bool { + if edges.count > (n - 1) { + return false + } + + var adj = Array(repeating: [Int](), count: n) + for edge in edges { + let u = edge[0] + let v = edge[1] + adj[u].append(v) + adj[v].append(u) + } + + var visited = Set() + + func dfs(_ node: Int, _ parent: Int) -> Bool { + if visited.contains(node) { + return false + } + visited.insert(node) + for nei in adj[node] { + if nei == parent { + continue + } + if !dfs(nei, node) { + return false + } + } + return true + } + + return dfs(0, -1) && visited.count == n + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -537,6 +575,45 @@ class Solution { } ``` +```swift +class Solution { + func validTree(_ n: Int, _ edges: [[Int]]) -> Bool { + if edges.count > n - 1 { + return false + } + + var adj = [[Int]](repeating: [], count: n) + for edge in edges { + let u = edge[0] + let v = edge[1] + adj[u].append(v) + adj[v].append(u) + } + + var visit = Set() + var q = Deque<(Int, Int)>() // (current node, parent node) + q.append((0, -1)) + visit.insert(0) + + while !q.isEmpty { + let (node, parent) = q.removeFirst() + for nei in adj[node] { + if nei == parent { + continue + } + if visit.contains(nei) { + return false + } + visit.insert(nei) + q.append((nei, node)) + } + } + + return visit.count == n + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -593,7 +670,7 @@ class Solution: ``` ```java -public class DSU { +class DSU { int[] Parent, Size; int comps; @@ -932,6 +1009,65 @@ class Solution { } ``` +```swift +class DSU { + var comps: Int + var parent: [Int] + var size: [Int] + + init(_ n: Int) { + comps = n + parent = Array(0.. Int { + if parent[node] != node { + parent[node] = find(parent[node]) + } + return parent[node] + } + + func union(_ u: Int, _ v: Int) -> Bool { + let pu = find(u) + let pv = find(v) + if pu == pv { + return false + } + comps -= 1 + if size[pu] < size[pv] { + parent[pu] = pv + size[pv] += size[pu] + } else { + parent[pv] = pu + size[pu] += size[pv] + } + return true + } + + func components() -> Int { + return comps + } +} + +class Solution { + func validTree(_ n: Int, _ edges: [[Int]]) -> Bool { + if edges.count > n - 1 { + return false + } + + let dsu = DSU(n) + for edge in edges { + let u = edge[0], v = edge[1] + if !dsu.union(u, v) { + return false + } + } + return dsu.components() == 1 + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/validate-parentheses.md b/articles/validate-parentheses.md index fc97eac24..a7e649a78 100644 --- a/articles/validate-parentheses.md +++ b/articles/validate-parentheses.md @@ -105,6 +105,20 @@ class Solution { } ``` +```swift +class Solution { + func isValid(_ s: String) -> Bool { + var str = s + while str.contains("()") || str.contains("{}") || str.contains("[]") { + str = str.replacingOccurrences(of: "()", with: "") + str = str.replacingOccurrences(of: "{}", with: "") + str = str.replacingOccurrences(of: "[]", with: "") + } + return str.isEmpty + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -291,6 +305,29 @@ class Solution { } ``` +```swift +class Solution { + func isValid(_ s: String) -> Bool { + var stack = [Character]() + let closeToOpen: [Character: Character] = [")": "(", "]": "[", "}": "{"] + + for c in s { + if let open = closeToOpen[c] { + if !stack.isEmpty && stack.last! == open { + stack.popLast() + } else { + return false + } + } else { + stack.append(c) + } + } + + return stack.isEmpty + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/word-break.md b/articles/word-break.md index 908708670..acc8366d3 100644 --- a/articles/word-break.md +++ b/articles/word-break.md @@ -176,6 +176,32 @@ class Solution { } ``` +```swift +class Solution { + func wordBreak(_ s: String, _ wordDict: [String]) -> Bool { + let chars = Array(s) + + func dfs(_ i: Int) -> Bool { + if i == chars.count { + return true + } + + for w in wordDict { + if i + w.count <= chars.count, + String(chars[i.. Bool { + let wordSet = Set(wordDict) + let chars = Array(s) + + func dfs(_ i: Int) -> Bool { + if i == chars.count { + return true + } + + for j in i.. Bool { + var memo = [Int: Bool]() + memo[s.count] = true + let chars = Array(s) + + func dfs(_ i: Int) -> Bool { + if let cached = memo[i] { + return cached + } + + for w in wordDict { + if i + w.count <= chars.count, + String(chars[i.. Bool { + let wordSet = Set(wordDict) + var maxLen = 0 + for w in wordDict { + maxLen = max(maxLen, w.count) + } + + var memo = [Int: Bool]() + let chars = Array(s) + + func dfs(_ i: Int) -> Bool { + if let cached = memo[i] { + return cached + } + if i == chars.count { + return true + } + for j in i.. Bool { + var dp = Array(repeating: false, count: s.count + 1) + dp[s.count] = true + let chars = Array(s) + + for i in stride(from: s.count - 1, through: 0, by: -1) { + for w in wordDict { + if i + w.count <= chars.count, String(chars[i.. children; boolean isWord; @@ -1096,7 +1237,7 @@ public class TrieNode { } } -public class Trie { +class Trie { TrieNode root; public Trie() { @@ -1497,6 +1638,70 @@ class Solution { } ``` +```swift +class TrieNode { + var children = [Character: TrieNode]() + var isWord = false +} + +class Trie { + private let root = TrieNode() + + func insert(_ word: String) { + var node = root + for char in word { + if node.children[char] == nil { + node.children[char] = TrieNode() + } + node = node.children[char]! + } + node.isWord = true + } + + func search(_ s: [Character], _ i: Int, _ j: Int) -> Bool { + var node = root + for idx in i...j { + if node.children[s[idx]] == nil { + return false + } + node = node.children[s[idx]]! + } + return node.isWord + } +} + +class Solution { + func wordBreak(_ s: String, _ wordDict: [String]) -> Bool { + let trie = Trie() + for word in wordDict { + trie.insert(word) + } + + var dp = Array(repeating: false, count: s.count + 1) + dp[s.count] = true + let chars = Array(s) + + var maxLen = 0 + for word in wordDict { + maxLen = max(maxLen, word.count) + } + + for i in stride(from: s.count, through: 0, by: -1) { + for j in i.. Int { + if !wordList.contains(endWord) || beginWord == endWord { + return 0 + } + + let n = wordList.count + let m = wordList[0].count + var adj = [[Int]](repeating: [], count: n) + var mp = [String: Int]() + + for i in 0..() + var res = 1 + var visit = Set() + let beginChars = Array(beginWord) + + for i in 0.. Int { + if !wordList.contains(endWord) || beginWord == endWord { + return 0 + } + + var words = Set(wordList) + var queue = Deque() + queue.append(beginWord) + var res = 0 + + while !queue.isEmpty { + res += 1 + for _ in 0.. Int { + if !wordList.contains(endWord) { + return 0 + } + + var nei = [String: [String]]() + var wordList = wordList + wordList.append(beginWord) + + for word in wordList { + let wordArray = Array(word) + for j in 0.. = [beginWord] + var queue = Deque() + queue.append(beginWord) + var res = 1 + + while !queue.isEmpty { + for _ in 0.. Int { + if !wordList.contains(endWord) || beginWord == endWord { + return 0 + } + + let m = wordList[0].count + var wordSet = Set(wordList) + var qb = Deque([beginWord]) + var qe = Deque([endWord]) + var fromBegin = [beginWord: 1] + var fromEnd = [endWord: 1] + + while !qb.isEmpty && !qe.isEmpty { + if qb.count > qe.count { + swap(&qb, &qe) + swap(&fromBegin, &fromEnd) + } + + for _ in 0.. Date: Tue, 15 Apr 2025 10:02:05 +0530 Subject: [PATCH 06/12] Sri Hari: Batch-6/Neetcode-All/Added-articles (#4042) * Batch-6/Neetcode-ALL/Added-articles * Batch-6/Neetcode-ALL/Added-articles * Batch-6/Neetcode-ALL/Added-articles * Batch-6/Neetcode-ALL/Added-articles * Batch-6/Neetcode-ALL/Added-articles * Batch-6/Neetcode-ALL/Added-articles * Batch-6/Neetcode-ALL/Added-articles * Batch-6/Neetcode-ALL/Added-articles * Batch-6/Neetcode-ALL/Added-articles --- ...haracters-to-string-to-make-subsequence.md | 210 +++ articles/average-waiting-time.md | 169 +++ .../binary-tree-vertical-order-traversal.md | 837 ++++++++++++ articles/buildings-with-an-ocean-view.md | 339 +++++ .../check-if-array-is-sorted-and-rotated.md | 306 +++++ articles/circular-sentence.md | 154 +++ articles/count-number-of-bad-pairs.md | 157 +++ .../count-the-number-of-consistent-strings.md | 415 ++++++ articles/count-vowel-strings-in-ranges.md | 336 +++++ articles/divide-array-into-equal-pairs.md | 290 +++++ articles/find-common-characters.md | 122 ++ articles/find-missing-and-repeated-values.md | 492 +++++++ articles/height-checker.md | 206 +++ articles/kth-distinct-string-in-an-array.md | 350 +++++ articles/longest-palindrome.md | 419 ++++++ ...reasing-or-strictly-decreasing-subarray.md | 454 +++++++ articles/make-sum-divisible-by-p.md | 235 ++++ articles/maximum-ascending-subarray-sum.md | 173 +++ articles/minimum-index-of-a-valid-split.md | 385 ++++++ ...perations-to-move-all-balls-to-each-box.md | 325 +++++ ...inimum-remove-to-make-valid-parentheses.md | 124 ++ articles/number-of-senior-citizens.md | 149 +++ articles/number-of-sub-arrays-with-odd-sum.md | 521 ++++++++ articles/number-of-ways-to-split-array.md | 320 +++++ articles/relative-sort-array.md | 551 ++++++++ .../remove-duplicates-from-sorted-list.md | 2 +- articles/score-of-a-string.md | 60 + articles/shifting-letters-ii.md | 481 +++++++ .../sort-array-by-increasing-frequency.md | 79 ++ articles/sort-the-jumbled-numbers.md | 244 ++++ articles/sort-the-people.md | 256 ++++ articles/special-array-i.md | 129 ++ articles/string-matching-in-an-array.md | 1157 +++++++++++++++++ articles/subarray-sums-divisible-by-k.md | 280 ++++ articles/uncommon-words-from-two-sentences.md | 183 +++ articles/valid-palindrome-ii.md | 81 ++ articles/valid-word-abbreviation.md | 163 +++ articles/word-subsets.md | 293 +++++ 38 files changed, 11446 insertions(+), 1 deletion(-) create mode 100644 articles/append-characters-to-string-to-make-subsequence.md create mode 100644 articles/average-waiting-time.md create mode 100644 articles/binary-tree-vertical-order-traversal.md create mode 100644 articles/buildings-with-an-ocean-view.md create mode 100644 articles/check-if-array-is-sorted-and-rotated.md create mode 100644 articles/circular-sentence.md create mode 100644 articles/count-number-of-bad-pairs.md create mode 100644 articles/count-the-number-of-consistent-strings.md create mode 100644 articles/count-vowel-strings-in-ranges.md create mode 100644 articles/divide-array-into-equal-pairs.md create mode 100644 articles/find-common-characters.md create mode 100644 articles/find-missing-and-repeated-values.md create mode 100644 articles/height-checker.md create mode 100644 articles/kth-distinct-string-in-an-array.md create mode 100644 articles/longest-palindrome.md create mode 100644 articles/longest-strictly-increasing-or-strictly-decreasing-subarray.md create mode 100644 articles/make-sum-divisible-by-p.md create mode 100644 articles/maximum-ascending-subarray-sum.md create mode 100644 articles/minimum-index-of-a-valid-split.md create mode 100644 articles/minimum-number-of-operations-to-move-all-balls-to-each-box.md create mode 100644 articles/number-of-senior-citizens.md create mode 100644 articles/number-of-sub-arrays-with-odd-sum.md create mode 100644 articles/number-of-ways-to-split-array.md create mode 100644 articles/relative-sort-array.md create mode 100644 articles/score-of-a-string.md create mode 100644 articles/shifting-letters-ii.md create mode 100644 articles/sort-array-by-increasing-frequency.md create mode 100644 articles/sort-the-jumbled-numbers.md create mode 100644 articles/sort-the-people.md create mode 100644 articles/special-array-i.md create mode 100644 articles/string-matching-in-an-array.md create mode 100644 articles/subarray-sums-divisible-by-k.md create mode 100644 articles/uncommon-words-from-two-sentences.md create mode 100644 articles/valid-word-abbreviation.md create mode 100644 articles/word-subsets.md diff --git a/articles/append-characters-to-string-to-make-subsequence.md b/articles/append-characters-to-string-to-make-subsequence.md new file mode 100644 index 000000000..de5f09613 --- /dev/null +++ b/articles/append-characters-to-string-to-make-subsequence.md @@ -0,0 +1,210 @@ +## 1. Two Pointers + +::tabs-start + +```python +class Solution: + def appendCharacters(self, s: str, t: str) -> int: + i, j = 0, 0 + + while i < len(s) and j < len(t): + if s[i] == t[j]: + i += 1 + j += 1 + else: + i += 1 + return len(t) - j +``` + +```java +public class Solution { + public int appendCharacters(String s, String t) { + int i = 0, j = 0; + + while (i < s.length() && j < t.length()) { + if (s.charAt(i) == t.charAt(j)) { + i++; + j++; + } else { + i++; + } + } + return t.length() - j; + } +} +``` + +```cpp +class Solution { +public: + int appendCharacters(string s, string t) { + int i = 0, j = 0; + + while (i < s.length() && j < t.length()) { + if (s[i] == t[j]) { + i++; + j++; + } else { + i++; + } + } + return t.length() - j; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @param {string} t + * @return {number} + */ + appendCharacters(s, t) { + let i = 0, j = 0; + + while (i < s.length && j < t.length) { + if (s[i] === t[j]) { + i++; + j++; + } else { + i++; + } + } + return t.length - j; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n + m)$ +* Space complexity: $O(1)$ + +> Where $n$ and $m$ are the lengths of the strings $s$ and $t$, respectively. + +--- + +## 2. Index Jumping + +::tabs-start + +```python +class Solution: + def appendCharacters(self, s: str, t: str) -> int: + n, m = len(s), len(t) + store = [[n + 1] * 26 for _ in range(n)] + store[n - 1][ord(s[n - 1]) - ord('a')] = n - 1 + + for i in range(n - 2, -1, -1): + store[i] = store[i + 1][:] + store[i][ord(s[i]) - ord('a')] = i + + i, j = 0, 0 + while i < n and j < m: + if store[i][ord(t[j]) - ord('a')] == n + 1: + break + + i = store[i][ord(t[j]) - ord('a')] + 1 + j += 1 + + return m - j +``` + +```java +public class Solution { + public int appendCharacters(String s, String t) { + int n = s.length(), m = t.length(); + int[][] store = new int[n][26]; + for (int[] row : store) { + Arrays.fill(row, n + 1); + } + store[n - 1][s.charAt(n - 1) - 'a'] = n - 1; + + for (int i = n - 2; i >= 0; i--) { + store[i] = store[i + 1].clone(); + store[i][s.charAt(i) - 'a'] = i; + } + + int i = 0, j = 0; + while (i < n && j < m) { + if (store[i][t.charAt(j) - 'a'] == n + 1) { + break; + } + i = store[i][t.charAt(j) - 'a'] + 1; + j++; + } + + return m - j; + } +} +``` + +```cpp +class Solution { +public: + int appendCharacters(string s, string t) { + int n = s.length(), m = t.length(); + vector> store(n, vector(26, n + 1)); + store[n - 1][s[n - 1] - 'a'] = n - 1; + + for (int i = n - 2; i >= 0; i--) { + store[i] = store[i + 1]; + store[i][s[i] - 'a'] = i; + } + + int i = 0, j = 0; + while (i < n && j < m) { + if (store[i][t[j] - 'a'] == n + 1) { + break; + } + i = store[i][t[j] - 'a'] + 1; + j++; + } + + return m - j; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @param {string} t + * @return {number} + */ + appendCharacters(s, t) { + const n = s.length, m = t.length; + const store = Array.from({ length: n }, () => Array(26).fill(n + 1)); + store[n - 1][s.charCodeAt(n - 1) - 97] = n - 1; + + for (let i = n - 2; i >= 0; i--) { + store[i] = store[i + 1].slice(); + store[i][s.charCodeAt(i) - 97] = i; + } + + let i = 0, j = 0; + while (i < n && j < m) { + if (store[i][t.charCodeAt(j) - 97] === n + 1) { + break; + } + i = store[i][t.charCodeAt(j) - 97] + 1; + j++; + } + + return m - j; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n + m)$ +* Space complexity: $O(n)$ + +> Where $n$ and $m$ are the lengths of the strings $s$ and $t$, respectively. \ No newline at end of file diff --git a/articles/average-waiting-time.md b/articles/average-waiting-time.md new file mode 100644 index 000000000..0d6c7c818 --- /dev/null +++ b/articles/average-waiting-time.md @@ -0,0 +1,169 @@ +## 1. Simulation - I + +::tabs-start + +```python +class Solution: + def averageWaitingTime(self, customers: List[List[int]]) -> float: + t = 0 + total = 0 + + for arrival, order in customers: + if t > arrival: + total += t - arrival + else: + t = arrival + total += order + t += order + + return total / len(customers) +``` + +```java +public class Solution { + public double averageWaitingTime(int[][] customers) { + long t = 0, total = 0; + + for (int[] c : customers) { + int arrival = c[0], order = c[1]; + if (t > arrival) { + total += t - arrival; + } else { + t = arrival; + } + total += order; + t += order; + } + + return (double) total / customers.length; + } +} +``` + +```cpp +class Solution { +public: + double averageWaitingTime(vector>& customers) { + long long t = 0, total = 0; + + for (auto& c : customers) { + int arrival = c[0], order = c[1]; + if (t > arrival) { + total += t - arrival; + } else { + t = arrival; + } + total += order; + t += order; + } + + return (double) total / customers.size(); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} customers + * @return {number} + */ + averageWaitingTime(customers) { + let t = 0, total = 0; + + for (let [arrival, order] of customers) { + if (t > arrival) { + total += t - arrival; + } else { + t = arrival; + } + total += order; + t += order; + } + + return total / customers.length; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ + +--- + +## 2. Simulation - II + +::tabs-start + +```python +class Solution: + def averageWaitingTime(self, customers: List[List[int]]) -> float: + t = total = 0 + for arrival, order in customers: + t = max(t, arrival) + order + total += t - arrival + return total / len(customers) +``` + +```java +public class Solution { + public double averageWaitingTime(int[][] customers) { + long t = 0, total = 0; + + for (int[] c : customers) { + int arrival = c[0], order = c[1]; + t = Math.max(t, arrival) + order; + total += t - arrival; + } + + return (double) total / customers.length; + } +} +``` + +```cpp +class Solution { +public: + double averageWaitingTime(vector>& customers) { + long long t = 0, total = 0; + + for (auto& c : customers) { + int arrival = c[0], order = c[1]; + t = max(t, (long long)arrival) + order; + total += t - arrival; + } + + return (double) total / customers.size(); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} customers + * @return {number} + */ + averageWaitingTime(customers) { + let t = 0, total = 0; + + for (let [arrival, order] of customers) { + t = Math.max(t, arrival) + order; + total += t - arrival; + } + + return total / customers.length; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ \ No newline at end of file diff --git a/articles/binary-tree-vertical-order-traversal.md b/articles/binary-tree-vertical-order-traversal.md new file mode 100644 index 000000000..506fdad2c --- /dev/null +++ b/articles/binary-tree-vertical-order-traversal.md @@ -0,0 +1,837 @@ +## 1. Breadth First Search + Sorting + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def verticalOrder(self, root: Optional[TreeNode]) -> List[List[int]]: + cols = defaultdict(list) + que = deque([(root, 0)]) + + while que: + node, pos = que.popleft() + if node: + cols[pos].append(node.val) + que.append((node.left, pos - 1)) + que.append((node.right, pos + 1)) + + return [cols[x] for x in sorted(cols)] +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public List> verticalOrder(TreeNode root) { + if (root == null) return new ArrayList<>(); + + Map> cols = new TreeMap<>(); + Queue> queue = new LinkedList<>(); + queue.offer(new Pair<>(root, 0)); + + while (!queue.isEmpty()) { + Pair p = queue.poll(); + TreeNode node = p.getKey(); + int pos = p.getValue(); + + cols.computeIfAbsent(pos, k -> new ArrayList<>()).add(node.val); + + if (node.left != null) queue.offer(new Pair<>(node.left, pos - 1)); + if (node.right != null) queue.offer(new Pair<>(node.right, pos + 1)); + } + + return new ArrayList<>(cols.values()); + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + vector> verticalOrder(TreeNode* root) { + if (!root) return {}; + map> cols; + queue> q; + q.push({root, 0}); + + while (!q.empty()) { + auto [node, pos] = q.front(); q.pop(); + cols[pos].push_back(node->val); + if (node->left) q.push({node->left, pos - 1}); + if (node->right) q.push({node->right, pos + 1}); + } + + vector> res; + for (auto& [_, vec] : cols) + res.push_back(vec); + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number[][]} + */ + verticalOrder(root) { + if (!root) return []; + + const cols = new Map(); + const queue = new Queue([[root, 0]]); + + while (!queue.isEmpty()) { + const [node, pos] = queue.pop(); + if (!cols.has(pos)) cols.set(pos, []); + cols.get(pos).push(node.val); + + if (node.left) queue.push([node.left, pos - 1]); + if (node.right) queue.push([node.right, pos + 1]); + } + + const sortedKeys = Array.from(cols.keys()).sort((a, b) => a - b); + return sortedKeys.map(k => cols.get(k)); + } +} +``` + +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public int val; + * public TreeNode left; + * public TreeNode right; + * public TreeNode(int val=0, TreeNode left=null, TreeNode right=null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public IList> VerticalOrder(TreeNode root) { + if (root == null) return new List>(); + + var cols = new SortedDictionary>(); + var queue = new Queue<(TreeNode node, int pos)>(); + queue.Enqueue((root, 0)); + + while (queue.Count > 0) { + var (node, pos) = queue.Dequeue(); + + if (!cols.ContainsKey(pos)) + cols[pos] = new List(); + cols[pos].Add(node.val); + + if (node.left != null) queue.Enqueue((node.left, pos - 1)); + if (node.right != null) queue.Enqueue((node.right, pos + 1)); + } + + return cols.Values.ToList>(); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(n)$ + +--- + +## 2. Depth First Search + Sorting + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def verticalOrder(self, root: Optional[TreeNode]) -> List[List[int]]: + cols = defaultdict(list) + + def dfs(node, row, col): + if not node: + return + cols[col].append((row, node.val)) + dfs(node.left, row + 1, col - 1) + dfs(node.right, row + 1, col + 1) + + dfs(root, 0, 0) + + res = [] + for col in sorted(cols): + col_vals = sorted(cols[col], key=lambda x: x[0]) + res.append([val for _, val in col_vals]) + return res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + private Map> cols = new TreeMap<>(); + + public List> verticalOrder(TreeNode root) { + dfs(root, 0, 0); + List> res = new ArrayList<>(); + + for (List list : cols.values()) { + list.sort(Comparator.comparingInt(a -> a[0])); + List colVals = new ArrayList<>(); + for (int[] p : list) colVals.add(p[1]); + res.add(colVals); + } + + return res; + } + + private void dfs(TreeNode node, int row, int col) { + if (node == null) return; + cols.computeIfAbsent(col, k -> new ArrayList<>()).add(new int[]{row, node.val}); + dfs(node.left, row + 1, col - 1); + dfs(node.right, row + 1, col + 1); + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { + map>> cols; + + void dfs(TreeNode* node, int row, int col) { + if (!node) return; + cols[col].push_back({row, node->val}); + dfs(node->left, row + 1, col - 1); + dfs(node->right, row + 1, col + 1); + } + +public: + vector> verticalOrder(TreeNode* root) { + dfs(root, 0, 0); + vector> res; + + for (auto& [col, vec] : cols) { + stable_sort(vec.begin(), vec.end(), + [](const pair& a, const pair& b) { + return a.first < b.first; // sort ONLY by row + }); + + vector colVals; + for (auto& [_, val] : vec) + colVals.push_back(val); + res.push_back(colVals); + } + + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number[][]} + */ + verticalOrder(root) { + const cols = new Map(); + + const dfs = (node, row, col) => { + if (!node) return; + if (!cols.has(col)) cols.set(col, []); + cols.get(col).push([row, node.val]); + dfs(node.left, row + 1, col - 1); + dfs(node.right, row + 1, col + 1); + }; + + dfs(root, 0, 0); + + const sortedCols = Array.from(cols.entries()).sort((a, b) => a[0] - b[0]); + return sortedCols.map(([_, vec]) => + vec.sort((a, b) => a[0] - b[0]).map(([_, val]) => val) + ); + } +} +``` + +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public int val; + * public TreeNode left; + * public TreeNode right; + * public TreeNode(int val=0, TreeNode left=null, TreeNode right=null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + private SortedDictionary> cols = new(); + + public IList> VerticalOrder(TreeNode root) { + DFS(root, 0, 0); + + List> res = new(); + foreach (var entry in cols) { + var list = entry.Value.OrderBy(x => x.Item1).Select(x => x.Item2).ToList(); + res.Add(list); + } + + return res; + } + + private void DFS(TreeNode node, int row, int col) { + if (node == null) return; + if (!cols.ContainsKey(col)) cols[col] = new List<(int, int)>(); + cols[col].Add((row, node.val)); + DFS(node.left, row + 1, col - 1); + DFS(node.right, row + 1, col + 1); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(n \log n)$ + +--- + +## 3. Breadth First Search (Optimal) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def verticalOrder(self, root: Optional[TreeNode]) -> List[List[int]]: + if not root: + return [] + + cols = defaultdict(list) + queue = deque([(root, 0)]) + minCol = maxCol = 0 + + while queue: + node, col = queue.popleft() + cols[col].append(node.val) + minCol = min(minCol, col) + maxCol = max(maxCol, col) + + if node.left: + queue.append((node.left, col - 1)) + if node.right: + queue.append((node.right, col + 1)) + + return [cols[c] for c in range(minCol, maxCol + 1)] +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public List> verticalOrder(TreeNode root) { + if (root == null) return new ArrayList<>(); + + Map> cols = new HashMap<>(); + Queue> queue = new LinkedList<>(); + queue.offer(new Pair<>(root, 0)); + int minCol = 0, maxCol = 0; + + while (!queue.isEmpty()) { + Pair p = queue.poll(); + TreeNode node = p.getKey(); + int col = p.getValue(); + + cols.computeIfAbsent(col, x -> new ArrayList<>()).add(node.val); + minCol = Math.min(minCol, col); + maxCol = Math.max(maxCol, col); + + if (node.left != null) queue.offer(new Pair<>(node.left, col - 1)); + if (node.right != null) queue.offer(new Pair<>(node.right, col + 1)); + } + + List> res = new ArrayList<>(); + for (int c = minCol; c <= maxCol; c++) { + res.add(cols.get(c)); + } + return res; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + vector> verticalOrder(TreeNode* root) { + if (!root) return {}; + + unordered_map> cols; + queue> q; + q.push({root, 0}); + int minCol = 0, maxCol = 0; + + while (!q.empty()) { + auto [node, col] = q.front(); q.pop(); + cols[col].push_back(node->val); + minCol = min(minCol, col); + maxCol = max(maxCol, col); + + if (node->left) q.push({node->left, col - 1}); + if (node->right) q.push({node->right, col + 1}); + } + + vector> res; + for (int c = minCol; c <= maxCol; ++c) + res.push_back(cols[c]); + + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number[][]} + */ + verticalOrder(root) { + if (!root) return []; + + const cols = new Map(); + const queue = new Queue([[root, 0]]); + let minCol = 0, maxCol = 0; + + while (!queue.isEmpty()) { + const [node, col] = queue.pop(); + if (!cols.has(col)) cols.set(col, []); + cols.get(col).push(node.val); + minCol = Math.min(minCol, col); + maxCol = Math.max(maxCol, col); + + if (node.left) queue.push([node.left, col - 1]); + if (node.right) queue.push([node.right, col + 1]); + } + + const res = []; + for (let c = minCol; c <= maxCol; c++) { + res.push(cols.get(c)); + } + return res; + } +} +``` + +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public int val; + * public TreeNode left; + * public TreeNode right; + * public TreeNode(int val=0, TreeNode left=null, TreeNode right=null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public IList> VerticalOrder(TreeNode root) { + if (root == null) return new List>(); + + Dictionary> cols = new(); + Queue<(TreeNode node, int col)> queue = new(); + queue.Enqueue((root, 0)); + int minCol = 0, maxCol = 0; + + while (queue.Count > 0) { + var (node, col) = queue.Dequeue(); + if (!cols.ContainsKey(col)) + cols[col] = new List(); + cols[col].Add(node.val); + minCol = Math.Min(minCol, col); + maxCol = Math.Max(maxCol, col); + + if (node.left != null) queue.Enqueue((node.left, col - 1)); + if (node.right != null) queue.Enqueue((node.right, col + 1)); + } + + var res = new List>(); + for (int c = minCol; c <= maxCol; c++) { + res.Add(cols[c]); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 4. Depth First Search (Optimal) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def verticalOrder(self, root: Optional[TreeNode]) -> List[List[int]]: + if not root: + return [] + + cols = defaultdict(list) + minCol = maxCol = 0 + + def dfs(node, row, col): + nonlocal minCol, maxCol + if not node: + return + cols[col].append((row, node.val)) + minCol = min(minCol, col) + maxCol = max(maxCol, col) + dfs(node.left, row + 1, col - 1) + dfs(node.right, row + 1, col + 1) + + dfs(root, 0, 0) + + res = [] + for c in range(minCol, maxCol + 1): + # sort by row only + col_vals = sorted(cols[c], key=lambda x: x[0]) + res.append([val for _, val in col_vals]) + return res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + private Map> cols = new HashMap<>(); + private int minCol = 0, maxCol = 0; + + public List> verticalOrder(TreeNode root) { + if (root == null) return new ArrayList<>(); + dfs(root, 0, 0); + + List> res = new ArrayList<>(); + for (int c = minCol; c <= maxCol; c++) { + List list = cols.getOrDefault(c, new ArrayList<>()); + list.sort(Comparator.comparingInt(a -> a[0])); // sort by row + List colVals = new ArrayList<>(); + for (int[] p : list) colVals.add(p[1]); + res.add(colVals); + } + return res; + } + + private void dfs(TreeNode node, int row, int col) { + if (node == null) return; + cols.computeIfAbsent(col, k -> new ArrayList<>()).add(new int[]{row, node.val}); + minCol = Math.min(minCol, col); + maxCol = Math.max(maxCol, col); + dfs(node.left, row + 1, col - 1); + dfs(node.right, row + 1, col + 1); + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { + unordered_map>> cols; + int minCol = 0, maxCol = 0; + + void dfs(TreeNode* node, int row, int col) { + if (!node) return; + cols[col].emplace_back(row, node->val); + minCol = min(minCol, col); + maxCol = max(maxCol, col); + dfs(node->left, row + 1, col - 1); + dfs(node->right, row + 1, col + 1); + } + +public: + vector> verticalOrder(TreeNode* root) { + if (!root) return {}; + dfs(root, 0, 0); + vector> res; + + for (int c = minCol; c <= maxCol; ++c) { + auto& vec = cols[c]; + stable_sort(vec.begin(), vec.end(), + [](const pair& a, const pair& b) { + return a.first < b.first; // sort by row only + }); + vector colVals; + for (auto& [_, val] : vec) + colVals.push_back(val); + res.push_back(colVals); + } + + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number[][]} + */ + verticalOrder(root) { + if (!root) return []; + + const cols = new Map(); + let minCol = 0, maxCol = 0; + + const dfs = (node, row, col) => { + if (!node) return; + if (!cols.has(col)) cols.set(col, []); + cols.get(col).push([row, node.val]); + minCol = Math.min(minCol, col); + maxCol = Math.max(maxCol, col); + dfs(node.left, row + 1, col - 1); + dfs(node.right, row + 1, col + 1); + }; + + dfs(root, 0, 0); + + const res = []; + for (let c = minCol; c <= maxCol; c++) { + let entries = cols.get(c) || []; + entries.sort((a, b) => a[0] - b[0]); // sort by row only + res.push(entries.map(([_, val]) => val)); + } + + return res; + } +} +``` + +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public int val; + * public TreeNode left; + * public TreeNode right; + * public TreeNode(int val=0, TreeNode left=null, TreeNode right=null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + private Dictionary> cols = new(); + private int minCol = 0, maxCol = 0; + + public IList> VerticalOrder(TreeNode root) { + if (root == null) return new List>(); + DFS(root, 0, 0); + var res = new List>(); + + for (int c = minCol; c <= maxCol; c++) { + var list = cols.ContainsKey(c) ? cols[c] : new List<(int, int)>(); + list.Sort((a, b) => a.Item1.CompareTo(b.Item1)); // sort by row + res.Add(list.Select(p => p.Item2).ToList()); + } + + return res; + } + + private void DFS(TreeNode node, int row, int col) { + if (node == null) return; + if (!cols.ContainsKey(col)) cols[col] = new List<(int, int)>(); + cols[col].Add((row, node.val)); + minCol = Math.Min(minCol, col); + maxCol = Math.Max(maxCol, col); + DFS(node.left, row + 1, col - 1); + DFS(node.right, row + 1, col + 1); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(w * h \log h)$ +* Space complexity: $O(n)$ + +> Where $n$ is the number of nodes, $h$ is the height of the tree (i.e. maximum number of nodes in any vertical line of the tree), and $w$ is the width of the tree (i.e. maximum number of nodes in any of the levels of the tree). \ No newline at end of file diff --git a/articles/buildings-with-an-ocean-view.md b/articles/buildings-with-an-ocean-view.md new file mode 100644 index 000000000..9c418c11c --- /dev/null +++ b/articles/buildings-with-an-ocean-view.md @@ -0,0 +1,339 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def findBuildings(self, heights: List[int]) -> List[int]: + n = len(heights) + res = [] + + for i in range(n): + flag = True + for j in range(i + 1, n): + if heights[i] <= heights[j]: + flag = False + break + if flag: + res.append(i) + + return res +``` + +```java +public class Solution { + public int[] findBuildings(int[] heights) { + int n = heights.length; + List temp = new ArrayList<>(); + + for (int i = 0; i < n; i++) { + boolean flag = true; + for (int j = i + 1; j < n; j++) { + if (heights[i] <= heights[j]) { + flag = false; + break; + } + } + if (flag) temp.add(i); + } + + int[] res = new int[temp.size()]; + for (int i = 0; i < temp.size(); i++) { + res[i] = temp.get(i); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + vector findBuildings(vector& heights) { + int n = heights.size(); + vector res; + + for (int i = 0; i < n; i++) { + bool flag = true; + for (int j = i + 1; j < n; j++) { + if (heights[i] <= heights[j]) { + flag = false; + break; + } + } + if (flag) res.push_back(i); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} heights + * @return {number[]} + */ + findBuildings(heights) { + const n = heights.length; + const res = []; + + for (let i = 0; i < n; i++) { + let flag = true; + for (let j = i + 1; j < n; j++) { + if (heights[i] <= heights[j]) { + flag = false; + break; + } + } + if (flag) res.push(i); + } + + return res; + } +} +``` + +```csharp +public class Solution { + public int[] FindBuildings(int[] heights) { + int n = heights.Length; + List temp = new List(); + + for (int i = 0; i < n; i++) { + bool flag = true; + for (int j = i + 1; j < n; j++) { + if (heights[i] <= heights[j]) { + flag = false; + break; + } + } + if (flag) temp.Add(i); + } + + return temp.ToArray(); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n)$ for the output array. + +--- + +## 2. Monotonic Stack + +::tabs-start + +```python +class Solution: + def findBuildings(self, heights: List[int]) -> List[int]: + stack = [] + + for i, h in enumerate(heights): + while stack and heights[stack[-1]] <= h: + stack.pop() + stack.append(i) + + return stack +``` + +```java +public class Solution { + public int[] findBuildings(int[] heights) { + int n = heights.length; + Stack stack = new Stack<>(); + + for (int i = 0; i < n; i++) { + while (!stack.isEmpty() && heights[stack.peek()] <= heights[i]) { + stack.pop(); + } + stack.push(i); + } + + int[] res = new int[stack.size()]; + for (int i = stack.size() - 1; i >= 0; i--) { + res[i] = stack.get(i); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector findBuildings(vector& heights) { + vector stack; + + for (int i = 0; i < heights.size(); i++) { + while (!stack.empty() && heights[stack.back()] <= heights[i]) { + stack.pop_back(); + } + stack.push_back(i); + } + + return stack; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} heights + * @return {number[]} + */ + findBuildings(heights) { + const stack = []; + + for (let i = 0; i < heights.length; i++) { + while (stack.length && heights[stack[stack.length - 1]] <= heights[i]) { + stack.pop(); + } + stack.push(i); + } + + return stack; + } +} +``` + +```csharp +public class Solution { + public int[] FindBuildings(int[] heights) { + List stack = new List(); + + for (int i = 0; i < heights.Length; i++) { + while (stack.Count > 0 && heights[stack[stack.Count - 1]] <= heights[i]) { + stack.RemoveAt(stack.Count - 1); + } + stack.Add(i); + } + + return stack.ToArray(); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 3. Greedy + +::tabs-start + +```python +class Solution: + def findBuildings(self, heights: List[int]) -> List[int]: + res = [len(heights) - 1] + for i in range(len(heights) - 2, -1, -1): + if heights[i] > heights[res[-1]]: + res.append(i) + res.reverse() + return res +``` + +```java +public class Solution { + public int[] findBuildings(int[] heights) { + List res = new ArrayList<>(); + int n = heights.length; + res.add(n - 1); + + for (int i = n - 2; i >= 0; i--) { + if (heights[i] > heights[res.get(res.size() - 1)]) { + res.add(i); + } + } + + Collections.reverse(res); + int[] ans = new int[res.size()]; + for (int i = 0; i < res.size(); i++) { + ans[i] = res.get(i); + } + + return ans; + } +} +``` + +```cpp +class Solution { +public: + vector findBuildings(vector& heights) { + vector res; + int n = heights.size(); + res.push_back(n - 1); + + for (int i = n - 2; i >= 0; i--) { + if (heights[i] > heights[res.back()]) { + res.push_back(i); + } + } + + reverse(res.begin(), res.end()); + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} heights + * @return {number[]} + */ + findBuildings(heights) { + const n = heights.length; + const res = [n - 1]; + + for (let i = n - 2; i >= 0; i--) { + if (heights[i] > heights[res[res.length - 1]]) { + res.push(i); + } + } + + return res.reverse(); + } +} +``` + +```csharp +public class Solution { + public int[] FindBuildings(int[] heights) { + int n = heights.Length; + List res = new List { n - 1 }; + + for (int i = n - 2; i >= 0; i--) { + if (heights[i] > heights[res[res.Count - 1]]) { + res.Add(i); + } + } + + res.Reverse(); + return res.ToArray(); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: + * $O(1)$ extra space. + * $O(n)$ for the output array. \ No newline at end of file diff --git a/articles/check-if-array-is-sorted-and-rotated.md b/articles/check-if-array-is-sorted-and-rotated.md new file mode 100644 index 000000000..061da0d48 --- /dev/null +++ b/articles/check-if-array-is-sorted-and-rotated.md @@ -0,0 +1,306 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def check(self, nums: List[int]) -> bool: + sortedNums = sorted(nums) + arr = [] + + for i in range(len(nums)): + arr.insert(0, sortedNums.pop()) + if nums == arr + sortedNums: + return True + + return False +``` + +```java +public class Solution { + public boolean check(int[] nums) { + int n = nums.length; + int[] sortedNums = nums.clone(); + Arrays.sort(sortedNums); + + for (int i = 0; i < n; i++) { + boolean match = true; + int idx = 0; + for (int j = n - i; j < n && match; j++) { + if (nums[idx] != sortedNums[j]) { + match = false; + } + idx += 1; + } + + for (int j = 0; j < n - i && match; j++) { + if (nums[idx] != sortedNums[j]) { + match = false; + } + idx += 1; + } + + if (match) return true; + } + + return false; + } +} +``` + +```cpp +class Solution { +public: + bool check(vector& nums) { + int n = nums.size(); + vector sortedNums = nums; + sort(sortedNums.begin(), sortedNums.end()); + + for (int i = 0; i < n; i++) { + bool match = true; + int idx = 0; + for (int j = n - i; j < n && match; j++) { + if (nums[idx] != sortedNums[j]) { + match = false; + } + idx++; + } + + for (int j = 0; j < n - i && match; j++) { + if (nums[idx] != sortedNums[j]) { + match = false; + } + idx++; + } + + if (match) return true; + } + + return false; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {boolean} + */ + check(nums) { + const n = nums.length; + const sortedNums = [...nums].sort((a, b) => a - b); + + for (let i = 0; i < n; i++) { + let match = true; + let idx = 0; + + for (let j = n - i; j < n && match; j++) { + if (nums[idx] !== sortedNums[j]) { + match = false; + } + idx++; + } + + for (let j = 0; j < n - i && match; j++) { + if (nums[idx] !== sortedNums[j]) { + match = false; + } + idx++; + } + + if (match) return true; + } + + return false; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n)$ + +--- + +## 2. Sliding Window + +::tabs-start + +```python +class Solution: + def check(self, nums: List[int]) -> bool: + N = len(nums) + count = 1 + + for i in range(1, 2 * N): + if nums[(i - 1) % N] <= nums[i % N]: + count += 1 + else: + count = 1 + if count == N: + return True + + return N == 1 +``` + +```java +public class Solution { + public boolean check(int[] nums) { + int N = nums.length; + int count = 1; + + for (int i = 1; i < 2 * N; i++) { + if (nums[(i - 1) % N] <= nums[i % N]) { + count++; + } else { + count = 1; + } + if (count == N) { + return true; + } + } + + return N == 1; + } +} +``` + +```cpp +class Solution { +public: + bool check(vector& nums) { + int N = nums.size(); + int count = 1; + + for (int i = 1; i < 2 * N; i++) { + if (nums[(i - 1) % N] <= nums[i % N]) { + count++; + } else { + count = 1; + } + if (count == N) { + return true; + } + } + + return N == 1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {boolean} + */ + check(nums) { + const N = nums.length; + let count = 1; + + for (let i = 1; i < 2 * N; i++) { + if (nums[(i - 1) % N] <= nums[i % N]) { + count++; + } else { + count = 1; + } + if (count === N) { + return true; + } + } + + return N === 1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ + +--- + +## 3. Iteration + +::tabs-start + +```python +class Solution: + def check(self, nums: List[int]) -> bool: + count, N = 0, len(nums) + + for i in range(N): + if nums[i] > nums[(i + 1) % N]: + count += 1 + if count > 1: + return False + + return True +``` + +```java +public class Solution { + public boolean check(int[] nums) { + int count = 0, N = nums.length; + + for (int i = 0; i < N; i++) { + if (nums[i] > nums[(i + 1) % N] && ++count > 1) { + return false; + } + } + + return true; + } +} +``` + +```cpp +class Solution { +public: + bool check(vector& nums) { + int count = 0, N = nums.size(); + + for (int i = 0; i < N; i++) { + if (nums[i] > nums[(i + 1) % N] && ++count > 1) { + return false; + } + } + + return true; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {boolean} + */ + check(nums) { + let count = 0, N = nums.length; + + for (let i = 0; i < N; i++) { + if (nums[i] > nums[(i + 1) % N] && ++count > 1) { + return false; + } + } + + return true; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ \ No newline at end of file diff --git a/articles/circular-sentence.md b/articles/circular-sentence.md new file mode 100644 index 000000000..c4e969dc1 --- /dev/null +++ b/articles/circular-sentence.md @@ -0,0 +1,154 @@ +## 1. Splitting the String + +::tabs-start + +```python +class Solution: + def isCircularSentence(self, sentence: str) -> bool: + w = sentence.split(" ") + + for i in range(len(w)): + if w[i][0] != w[i - 1][-1]: + return False + + return True +``` + +```java +public class Solution { + public boolean isCircularSentence(String sentence) { + String[] w = sentence.split(" "); + int n = w.length; + + for (int i = 0; i < n; i++) { + char start = w[i].charAt(0); + char end = w[(i - 1 + n) % n].charAt(w[(i - 1 + n) % n].length() - 1); + if (start != end) { + return false; + } + } + + return true; + } +} +``` + +```cpp +class Solution { +public: + bool isCircularSentence(string sentence) { + vector w; + stringstream ss(sentence); + string word; + + while (ss >> word) { + w.push_back(word); + } + + for (int i = 0; i < w.size(); i++) { + char start = w[i][0]; + char end = w[(i - 1 + w.size()) % w.size()].back(); + if (start != end) { + return false; + } + } + + return true; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} sentence + * @return {boolean} + */ + isCircularSentence(sentence) { + const w = sentence.split(" "); + + for (let i = 0; i < w.length; i++) { + const start = w[i][0]; + const prevEnd = w[(i - 1 + w.length) % w.length].slice(-1); + if (start !== prevEnd) { + return false; + } + } + + return true; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 2. Iteration (Space Optimized) + +::tabs-start + +```python +class Solution: + def isCircularSentence(self, sentence: str) -> bool: + for i in range(len(sentence)): + if sentence[i] == " " and sentence[i - 1] != sentence[i + 1]: + return False + return sentence[0] == sentence[-1] +``` + +```java +public class Solution { + public boolean isCircularSentence(String sentence) { + for (int i = 0; i < sentence.length(); i++) { + if (sentence.charAt(i) == ' ' && sentence.charAt(i - 1) != sentence.charAt(i + 1)) { + return false; + } + } + return sentence.charAt(0) == sentence.charAt(sentence.length() - 1); + } +} +``` + +```cpp +class Solution { +public: + bool isCircularSentence(string sentence) { + for (int i = 0; i < sentence.size(); i++) { + if (sentence[i] == ' ' && sentence[i - 1] != sentence[i + 1]) { + return false; + } + } + return sentence.front() == sentence.back(); + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} sentence + * @return {boolean} + */ + isCircularSentence(sentence) { + for (let i = 0; i < sentence.length; i++) { + if (sentence[i] === ' ' && sentence[i - 1] !== sentence[i + 1]) { + return false; + } + } + return sentence[0] === sentence[sentence.length - 1]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ \ No newline at end of file diff --git a/articles/count-number-of-bad-pairs.md b/articles/count-number-of-bad-pairs.md new file mode 100644 index 000000000..936e3af7f --- /dev/null +++ b/articles/count-number-of-bad-pairs.md @@ -0,0 +1,157 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def countBadPairs(self, nums: List[int]) -> int: + n, res = len(nums), 0 + for i in range(n - 1): + for j in range(i + 1, n): + if j - i != nums[j] - nums[i]: + res += 1 + return res +``` + +```java +public class Solution { + public long countBadPairs(int[] nums) { + int n = nums.length; + long res = 0; + for (int i = 0; i < n - 1; i++) { + for (int j = i + 1; j < n; j++) { + if (j - i != nums[j] - nums[i]) { + res++; + } + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + long long countBadPairs(vector& nums) { + int n = nums.size(); + long long res = 0; + for (int i = 0; i < n - 1; i++) { + for (int j = i + 1; j < n; j++) { + if (j - i != nums[j] - nums[i]) { + res++; + } + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + countBadPairs(nums) { + let n = nums.length, res = 0; + for (let i = 0; i < n - 1; i++) { + for (let j = i + 1; j < n; j++) { + if (j - i !== nums[j] - nums[i]) { + res++; + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(1)$ + +--- + +## 2. Hash Map + +::tabs-start + +```python +class Solution: + def countBadPairs(self, nums: List[int]) -> int: + good_pairs = 0 + total_pairs = 0 + count = defaultdict(int) + + for i in range(len(nums)): + total_pairs += i + good_pairs += count[nums[i] - i] + count[nums[i] - i] += 1 + + return total_pairs - good_pairs +``` + +```java +public class Solution { + public long countBadPairs(int[] nums) { + Map count = new HashMap<>(); + long total = 0, good = 0; + for (int i = 0; i < nums.length; i++) { + int key = nums[i] - i; + good += count.getOrDefault(key, 0); + count.put(key, count.getOrDefault(key, 0) + 1); + total += i; + } + return total - good; + } +} +``` + +```cpp +class Solution { +public: + long long countBadPairs(vector& nums) { + unordered_map count; + long long total = 0, good = 0; + for (int i = 0; i < nums.size(); i++) { + int key = nums[i] - i; + good += count[key]; + count[key]++; + total += i; + } + return total - good; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + countBadPairs(nums) { + let count = new Map(); + let total = 0, good = 0; + for (let i = 0; i < nums.length; i++) { + let key = nums[i] - i; + good += count.get(key) || 0; + count.set(key, (count.get(key) || 0) + 1); + total += i; + } + return total - good; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ \ No newline at end of file diff --git a/articles/count-the-number-of-consistent-strings.md b/articles/count-the-number-of-consistent-strings.md new file mode 100644 index 000000000..600698357 --- /dev/null +++ b/articles/count-the-number-of-consistent-strings.md @@ -0,0 +1,415 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def countConsistentStrings(self, allowed: str, words: List[str]) -> int: + res = 0 + + for w in words: + flag = 1 + for c in w: + if c not in allowed: + flag = 0 + break + res += flag + + return res +``` + +```java +public class Solution { + public int countConsistentStrings(String allowed, String[] words) { + int res = 0; + + for (String w : words) { + boolean flag = true; + for (char c : w.toCharArray()) { + if (allowed.indexOf(c) == -1) { + flag = false; + break; + } + } + if (flag) res++; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int countConsistentStrings(string allowed, vector& words) { + int res = 0; + + for (string& w : words) { + bool flag = true; + for (char c : w) { + if (allowed.find(c) == string::npos) { + flag = false; + break; + } + } + res += flag; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} allowed + * @param {string[]} words + * @return {number} + */ + countConsistentStrings(allowed, words) { + let res = 0; + + for (let w of words) { + let flag = 1; + for (let c of w) { + if (!allowed.includes(c)) { + flag = 0; + break; + } + } + res += flag; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * m * l)$ +* Space complexity: $O(1)$ + +> Where $n$ is the number of words, $m$ is the length of the string $allowed$, and $l$ is the length of the longest word. + +--- + +## 2. Hash Set + +::tabs-start + +```python +class Solution: + def countConsistentStrings(self, allowed: str, words: List[str]) -> int: + allowed = set(allowed) + + res = len(words) + for w in words: + for c in w: + if c not in allowed: + res -= 1 + break + + return res +``` + +```java +public class Solution { + public int countConsistentStrings(String allowed, String[] words) { + Set allowedSet = new HashSet<>(); + for (char c : allowed.toCharArray()) { + allowedSet.add(c); + } + + int res = words.length; + for (String w : words) { + for (char c : w.toCharArray()) { + if (!allowedSet.contains(c)) { + res--; + break; + } + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int countConsistentStrings(string allowed, vector& words) { + unordered_set allowedSet(allowed.begin(), allowed.end()); + + int res = words.size(); + for (string& w : words) { + for (char c : w) { + if (allowedSet.find(c) == allowedSet.end()) { + res--; + break; + } + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} allowed + * @param {string[]} words + * @return {number} + */ + countConsistentStrings(allowed, words) { + const allowedSet = new Set(allowed); + let res = words.length; + + for (let w of words) { + for (let c of w) { + if (!allowedSet.has(c)) { + res--; + break; + } + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * l + m)$ +* Space complexity: $O(m)$ + +> Where $n$ is the number of words, $m$ is the length of the string $allowed$, and $l$ is the length of the longest word. + +--- + +## 3. Boolean Array + +::tabs-start + +```python +class Solution: + def countConsistentStrings(self, allowed: str, words: List[str]) -> int: + allowedArr = [False] * 26 + for c in allowed: + allowedArr[ord(c) - ord('a')] = True + + res = len(words) + for w in words: + for c in w: + if not allowedArr[ord(c) - ord('a')]: + res -= 1 + break + + return res +``` + +```java +public class Solution { + public int countConsistentStrings(String allowed, String[] words) { + Set allowedSet = new HashSet<>(); + for (char c : allowed.toCharArray()) { + allowedSet.add(c); + } + + int res = words.length; + for (String w : words) { + for (char c : w.toCharArray()) { + if (!allowedSet.contains(c)) { + res--; + break; + } + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int countConsistentStrings(string allowed, vector& words) { + bool allowedArr[26] = {}; + for (char c : allowed) { + allowedArr[c - 'a'] = true; + } + + int res = words.size(); + for (const string& w : words) { + for (char c : w) { + if (!allowedArr[c - 'a']) { + res--; + break; + } + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} allowed + * @param {string[]} words + * @return {number} + */ + countConsistentStrings(allowed, words) { + const allowedArr = new Array(26).fill(false); + for (let c of allowed) { + allowedArr[c.charCodeAt(0) - 97] = true; + } + + let res = words.length; + for (let w of words) { + for (let c of w) { + if (!allowedArr[c.charCodeAt(0) - 97]) { + res--; + break; + } + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * l + m)$ +* Space complexity: $O(m)$ + +> Where $n$ is the number of words, $m$ is the length of the string $allowed$, and $l$ is the length of the longest word. + +--- + +## 4. Bitmask + +::tabs-start + +```python +class Solution: + def countConsistentStrings(self, allowed: str, words: List[str]) -> int: + bit_mask = 0 + for c in allowed: + bit = 1 << (ord(c) - ord('a')) + bit_mask = bit_mask | bit + + res = len(words) + for w in words: + for c in w: + bit = 1 << (ord(c) - ord('a')) + if bit & bit_mask == 0: + res -= 1 + break + + return res +``` + +```java +public class Solution { + public int countConsistentStrings(String allowed, String[] words) { + int bitMask = 0; + for (char c : allowed.toCharArray()) { + bitMask |= 1 << (c - 'a'); + } + + int res = words.length; + for (String w : words) { + for (char c : w.toCharArray()) { + int bit = 1 << (c - 'a'); + if ((bit & bitMask) == 0) { + res--; + break; + } + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int countConsistentStrings(string allowed, vector& words) { + int bitMask = 0; + for (char c : allowed) { + bitMask |= (1 << (c - 'a')); + } + + int res = words.size(); + for (const string& w : words) { + for (char c : w) { + int bit = 1 << (c - 'a'); + if ((bit & bitMask) == 0) { + res--; + break; + } + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} allowed + * @param {string[]} words + * @return {number} + */ + countConsistentStrings(allowed, words) { + let bitMask = 0; + for (let c of allowed) { + bitMask |= 1 << (c.charCodeAt(0) - 97); + } + + let res = words.length; + for (let w of words) { + for (let c of w) { + const bit = 1 << (c.charCodeAt(0) - 97); + if ((bit & bitMask) === 0) { + res--; + break; + } + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * l + m)$ +* Space complexity: $O(1)$ + +> Where $n$ is the number of words, $m$ is the length of the string $allowed$, and $l$ is the length of the longest word. \ No newline at end of file diff --git a/articles/count-vowel-strings-in-ranges.md b/articles/count-vowel-strings-in-ranges.md new file mode 100644 index 000000000..22c92a839 --- /dev/null +++ b/articles/count-vowel-strings-in-ranges.md @@ -0,0 +1,336 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def vowelStrings(self, words: List[str], queries: List[List[int]]) -> List[int]: + vowels = set("aeiou") + res = [] + + for start, end in queries: + cnt = 0 + for i in range(start, end + 1): + if words[i][0] in vowels and words[i][-1] in vowels: + cnt += 1 + res.append(cnt) + + return res +``` + +```java +public class Solution { + public int[] vowelStrings(String[] words, int[][] queries) { + Set vowels = Set.of('a', 'e', 'i', 'o', 'u'); + int[] res = new int[queries.length]; + + for (int k = 0; k < queries.length; k++) { + int start = queries[k][0], end = queries[k][1], count = 0; + + for (int i = start; i <= end; i++) { + String word = words[i]; + if (vowels.contains(word.charAt(0)) && vowels.contains(word.charAt(word.length() - 1))) { + count++; + } + } + + res[k] = count; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector vowelStrings(vector& words, vector>& queries) { + unordered_set vowels = {'a', 'e', 'i', 'o', 'u'}; + vector res; + + for (auto& q : queries) { + int start = q[0], end = q[1], count = 0; + + for (int i = start; i <= end; i++) { + if (vowels.count(words[i][0]) && vowels.count(words[i].back())) { + count++; + } + } + + res.push_back(count); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} words + * @param {number[][]} queries + * @return {number[]} + */ + vowelStrings(words, queries) { + const vowels = new Set(['a', 'e', 'i', 'o', 'u']); + const res = []; + + for (let [start, end] of queries) { + let count = 0; + for (let i = start; i <= end; i++) { + const word = words[i]; + if (vowels.has(word[0]) && vowels.has(word[word.length - 1])) { + count++; + } + } + res.push(count); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * m)$ +* Space complexity: + * $O(1)$ extra space. + * $O(m)$ space for the output list. + +> Where $n$ is the number of words, and $m$ is the number of queries. + +--- + +## 2. Prefix Sum + Hash Set + +::tabs-start + +```python +class Solution: + def vowelStrings(self, words: List[str], queries: List[List[int]]) -> List[int]: + vowel_set = set("aeiou") + prefix_cnt = [0] * (len(words) + 1) + prev = 0 + + for i, w in enumerate(words): + if w[0] in vowel_set and w[-1] in vowel_set: + prev += 1 + prefix_cnt[i + 1] = prev + + res = [0] * len(queries) + for i, q in enumerate(queries): + l, r = q + res[i] = prefix_cnt[r + 1] - prefix_cnt[l] + + return res +``` + +```java +public class Solution { + public int[] vowelStrings(String[] words, int[][] queries) { + Set vowels = Set.of('a', 'e', 'i', 'o', 'u'); + int n = words.length; + int[] prefixCnt = new int[n + 1]; + + for (int i = 0; i < n; i++) { + String w = words[i]; + prefixCnt[i + 1] = prefixCnt[i]; + if (vowels.contains(w.charAt(0)) && vowels.contains(w.charAt(w.length() - 1))) { + prefixCnt[i + 1]++; + } + } + + int[] res = new int[queries.length]; + for (int i = 0; i < queries.length; i++) { + int l = queries[i][0], r = queries[i][1]; + res[i] = prefixCnt[r + 1] - prefixCnt[l]; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector vowelStrings(vector& words, vector>& queries) { + unordered_set vowels = {'a', 'e', 'i', 'o', 'u'}; + int n = words.size(); + vector prefixCnt(n + 1, 0); + + for (int i = 0; i < n; i++) { + prefixCnt[i + 1] = prefixCnt[i]; + if (vowels.count(words[i][0]) && vowels.count(words[i].back())) { + prefixCnt[i + 1]++; + } + } + + vector res; + for (auto& q : queries) { + int l = q[0], r = q[1]; + res.push_back(prefixCnt[r + 1] - prefixCnt[l]); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} words + * @param {number[][]} queries + * @return {number[]} + */ + vowelStrings(words, queries) { + const vowels = new Set(['a', 'e', 'i', 'o', 'u']); + const n = words.length; + const prefixCnt = new Array(n + 1).fill(0); + + for (let i = 0; i < n; i++) { + prefixCnt[i + 1] = prefixCnt[i]; + const w = words[i]; + if (vowels.has(w[0]) && vowels.has(w[w.length - 1])) { + prefixCnt[i + 1]++; + } + } + + const res = new Array(queries.length); + for (let i = 0; i < queries.length; i++) { + const [l, r] = queries[i]; + res[i] = prefixCnt[r + 1] - prefixCnt[l]; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n + m)$ +* Space complexity: + * $O(n)$ extra space. + * $O(m)$ space for the output list. + +> Where $n$ is the number of words, and $m$ is the number of queries. + +--- + +## 3. Prefix Sum + Bitmask + +::tabs-start + +```python +class Solution: + def vowelStrings(self, words: List[str], queries: List[List[int]]) -> List[int]: + vowels = sum(1 << (ord(c) - ord('a')) for c in "aeiou") + prefix = [0] + for w in words: + prefix.append(prefix[-1]) + if (1 << (ord(w[0]) - ord('a'))) & vowels and (1 << (ord(w[-1]) - ord('a'))) & vowels: + prefix[-1] += 1 + return [prefix[r + 1] - prefix[l] for l, r in queries] +``` + +```java +public class Solution { + public int[] vowelStrings(String[] words, int[][] queries) { + int vowels = 0; + for (char c : "aeiou".toCharArray()) { + vowels |= 1 << (c - 'a'); + } + + int[] prefix = new int[words.length + 1]; + for (int i = 0; i < words.length; i++) { + int f = words[i].charAt(0) - 'a'; + int l = words[i].charAt(words[i].length() - 1) - 'a'; + int isVowel = ((1 << f) & vowels) != 0 && ((1 << l) & vowels) != 0 ? 1 : 0; + prefix[i + 1] = prefix[i] + isVowel; + } + + int[] res = new int[queries.length]; + for (int i = 0; i < queries.length; i++) { + int l = queries[i][0], r = queries[i][1]; + res[i] = prefix[r + 1] - prefix[l]; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector vowelStrings(vector& words, vector>& queries) { + int vowels = 0; + for (char c : string("aeiou")) { + vowels |= (1 << (c - 'a')); + } + + int n = words.size(); + vector prefix(n + 1); + for (int i = 0; i < n; i++) { + int f = words[i][0] - 'a'; + int l = words[i].back() - 'a'; + int isVowel = ((1 << f) & vowels) && ((1 << l) & vowels); + prefix[i + 1] = prefix[i] + isVowel; + } + + vector res; + for (auto& q : queries) { + int l = q[0], r = q[1]; + res.push_back(prefix[r + 1] - prefix[l]); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} words + * @param {number[][]} queries + * @return {number[]} + */ + vowelStrings(words, queries) { + let vowels = 0; + for (let c of "aeiou") { + vowels |= 1 << (c.charCodeAt(0) - 97); + } + + const prefix = [0]; + for (let w of words) { + const f = w.charCodeAt(0) - 97; + const l = w.charCodeAt(w.length - 1) - 97; + const isVowel = ((1 << f) & vowels) && ((1 << l) & vowels) ? 1 : 0; + prefix.push(prefix[prefix.length - 1] + isVowel); + } + + return queries.map(([l, r]) => prefix[r + 1] - prefix[l]); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n + m)$ +* Space complexity: + * $O(n)$ extra space. + * $O(m)$ space for the output list. + +> Where $n$ is the number of words, and $m$ is the number of queries. \ No newline at end of file diff --git a/articles/divide-array-into-equal-pairs.md b/articles/divide-array-into-equal-pairs.md new file mode 100644 index 000000000..bc8a01fb1 --- /dev/null +++ b/articles/divide-array-into-equal-pairs.md @@ -0,0 +1,290 @@ +## 1. Sorting + +::tabs-start + +```python +class Solution: + def divideArray(self, nums: List[int]) -> bool: + N = len(nums) + nums.sort() + + i = 0 + while i < N: + j = i + while j < N and nums[i] == nums[j]: + j += 1 + + if (j - i) % 2 != 0: + return False + + i = j + + return True +``` + +```java +public class Solution { + public boolean divideArray(int[] nums) { + int N = nums.length; + Arrays.sort(nums); + + int i = 0; + while (i < N) { + int j = i; + while (j < N && nums[i] == nums[j]) { + j++; + } + + if ((j - i) % 2 != 0) { + return false; + } + + i = j; + } + + return true; + } +} +``` + +```cpp +class Solution { +public: + bool divideArray(vector& nums) { + int N = nums.size(); + sort(nums.begin(), nums.end()); + + int i = 0; + while (i < N) { + int j = i; + while (j < N && nums[i] == nums[j]) { + j++; + } + + if ((j - i) % 2 != 0) { + return false; + } + + i = j; + } + + return true; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {boolean} + */ + divideArray(nums) { + const N = nums.length; + nums.sort((a, b) => a - b); + + let i = 0; + while (i < N) { + let j = i; + while (j < N && nums[i] === nums[j]) { + j++; + } + + if ((j - i) % 2 !== 0) { + return false; + } + + i = j; + } + + return true; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. + +--- + +## 2. Hash Map + +::tabs-start + +```python +class Solution: + def divideArray(self, nums: List[int]) -> bool: + count = {} + for num in nums: + if num not in count: + count[num] = 0 + count[num] += 1 + + for cnt in count.values(): + if cnt % 2 == 1: + return False + + return True +``` + +```java +public class Solution { + public boolean divideArray(int[] nums) { + Map count = new HashMap<>(); + for (int num : nums) { + count.put(num, count.getOrDefault(num, 0) + 1); + } + + for (int cnt : count.values()) { + if (cnt % 2 == 1) { + return false; + } + } + + return true; + } +} +``` + +```cpp +class Solution { +public: + bool divideArray(vector& nums) { + unordered_map count; + for (int num : nums) { + count[num]++; + } + + for (auto& [key, cnt] : count) { + if (cnt % 2 == 1) { + return false; + } + } + + return true; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {boolean} + */ + divideArray(nums) { + const count = {}; + for (let num of nums) { + if (!(num in count)) { + count[num] = 0; + } + count[num]++; + } + + for (let key in count) { + if (count[key] % 2 === 1) { + return false; + } + } + + return true; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 3. Hash Set + +::tabs-start + +```python +class Solution: + def divideArray(self, nums: List[int]) -> bool: + odd_set = set() + + for num in nums: + if num not in odd_set: + odd_set.add(num) + else: + odd_set.remove(num) + + return not len(odd_set) +``` + +```java +public class Solution { + public boolean divideArray(int[] nums) { + Set oddSet = new HashSet<>(); + + for (int num : nums) { + if (!oddSet.contains(num)) { + oddSet.add(num); + } else { + oddSet.remove(num); + } + } + + return oddSet.isEmpty(); + } +} +``` + +```cpp +class Solution { +public: + bool divideArray(vector& nums) { + unordered_set oddSet; + + for (int num : nums) { + if (oddSet.count(num)) { + oddSet.erase(num); + } else { + oddSet.insert(num); + } + } + + return oddSet.empty(); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {boolean} + */ + divideArray(nums) { + const oddSet = new Set(); + + for (let num of nums) { + if (oddSet.has(num)) { + oddSet.delete(num); + } else { + oddSet.add(num); + } + } + + return oddSet.size === 0; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ \ No newline at end of file diff --git a/articles/find-common-characters.md b/articles/find-common-characters.md new file mode 100644 index 000000000..4a6cfe1e8 --- /dev/null +++ b/articles/find-common-characters.md @@ -0,0 +1,122 @@ +## 1. Frequency Count + +::tabs-start + +```python +class Solution: + def commonChars(self, words: List[str]) -> List[str]: + cnt = Counter(words[0]) + + for w in words: + cur_cnt = Counter(w) + for c in cnt: + cnt[c] = min(cnt[c], cur_cnt[c]) + + res = [] + for c in cnt: + for i in range(cnt[c]): + res.append(c) + + return res +``` + +```java +public class Solution { + public List commonChars(String[] words) { + int[] cnt = new int[26]; + Arrays.fill(cnt, Integer.MAX_VALUE); + + for (String word : words) { + int[] curCnt = new int[26]; + for (char c : word.toCharArray()) { + curCnt[c - 'a']++; + } + + for (int i = 0; i < 26; i++) { + cnt[i] = Math.min(cnt[i], curCnt[i]); + } + } + + List res = new ArrayList<>(); + for (int i = 0; i < 26; i++) { + for (int j = 0; j < cnt[i]; j++) { + res.add(String.valueOf((char) (i + 'a'))); + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector commonChars(vector& words) { + vector cnt(26, INT_MAX); + + for (string& word : words) { + vector curCnt(26, 0); + for (char c : word) { + curCnt[c - 'a']++; + } + + for (int i = 0; i < 26; i++) { + cnt[i] = min(cnt[i], curCnt[i]); + } + } + + vector res; + for (int i = 0; i < 26; i++) { + for (int j = 0; j < cnt[i]; j++) { + res.push_back(string(1, i + 'a')); + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} words + * @return {string[]} + */ + commonChars(words) { + const cnt = new Array(26).fill(Infinity); + + for (let word of words) { + const curCnt = new Array(26).fill(0); + for (let c of word) { + curCnt[c.charCodeAt(0) - 97]++; + } + + for (let i = 0; i < 26; i++) { + cnt[i] = Math.min(cnt[i], curCnt[i]); + } + } + + const res = []; + for (let i = 0; i < 26; i++) { + for (let j = 0; j < cnt[i]; j++) { + res.push(String.fromCharCode(i + 97)); + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * m)$ +* Space complexity: + * $O(1)$ extra space, since we have at most $26$ different characters. + * $O(n * m)$ space for the output list. + +> Where $n$ is the number of words and $m$ is the length of the longest word. \ No newline at end of file diff --git a/articles/find-missing-and-repeated-values.md b/articles/find-missing-and-repeated-values.md new file mode 100644 index 000000000..58753bb0f --- /dev/null +++ b/articles/find-missing-and-repeated-values.md @@ -0,0 +1,492 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def findMissingAndRepeatedValues(self, grid: List[List[int]]) -> List[int]: + n = len(grid) + double = missing = 0 + + for num in range(1, n * n + 1): + cnt = 0 + for i in range(n): + for j in range(n): + if num == grid[i][j]: + cnt += 1 + + if cnt == 2: + double = num + elif cnt == 0: + missing = num + + return [double, missing] +``` + +```java +public class Solution { + public int[] findMissingAndRepeatedValues(int[][] grid) { + int n = grid.length; + int doubleVal = 0, missing = 0; + + for (int num = 1; num <= n * n; num++) { + int cnt = 0; + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + if (grid[i][j] == num) { + cnt++; + } + } + } + + if (cnt == 2) { + doubleVal = num; + } else if (cnt == 0) { + missing = num; + } + } + + return new int[]{doubleVal, missing}; + } +} +``` + +```cpp +class Solution { +public: + vector findMissingAndRepeatedValues(vector>& grid) { + int n = grid.size(); + int doubleVal = 0, missing = 0; + + for (int num = 1; num <= n * n; num++) { + int cnt = 0; + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + if (grid[i][j] == num) { + cnt++; + } + } + } + + if (cnt == 2) { + doubleVal = num; + } else if (cnt == 0) { + missing = num; + } + } + + return {doubleVal, missing}; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number[]} + */ + findMissingAndRepeatedValues(grid) { + const n = grid.length; + let doubleVal = 0, missing = 0; + + for (let num = 1; num <= n * n; num++) { + let cnt = 0; + for (let i = 0; i < n; i++) { + for (let j = 0; j < n; j++) { + if (grid[i][j] === num) { + cnt++; + } + } + } + + if (cnt === 2) { + doubleVal = num; + } else if (cnt === 0) { + missing = num; + } + } + + return [doubleVal, missing]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 4)$ +* Space complexity: $O(1)$ + +--- + +## 2. Hash Map + +::tabs-start + +```python +class Solution: + def findMissingAndRepeatedValues(self, grid: List[List[int]]) -> List[int]: + N = len(grid) + count = defaultdict(int) + + for i in range(N): + for j in range(N): + count[grid[i][j]] += 1 + + double = missing = 0 + + for num in range(1, N * N + 1): + if count[num] == 0: + missing = num + if count[num] == 2: + double = num + + return [double, missing] +``` + +```java +public class Solution { + public int[] findMissingAndRepeatedValues(int[][] grid) { + int N = grid.length; + Map count = new HashMap<>(); + + for (int i = 0; i < N; i++) { + for (int j = 0; j < N; j++) { + count.put(grid[i][j], count.getOrDefault(grid[i][j], 0) + 1); + } + } + + int doubleVal = 0, missing = 0; + + for (int num = 1; num <= N * N; num++) { + int freq = count.getOrDefault(num, 0); + if (freq == 0) missing = num; + if (freq == 2) doubleVal = num; + } + + return new int[]{doubleVal, missing}; + } +} +``` + +```cpp +class Solution { +public: + vector findMissingAndRepeatedValues(vector>& grid) { + int N = grid.size(); + unordered_map count; + + for (int i = 0; i < N; i++) { + for (int j = 0; j < N; j++) { + count[grid[i][j]]++; + } + } + + int doubleVal = 0, missing = 0; + + for (int num = 1; num <= N * N; num++) { + int freq = count[num]; + if (freq == 0) missing = num; + if (freq == 2) doubleVal = num; + } + + return {doubleVal, missing}; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number[]} + */ + findMissingAndRepeatedValues(grid) { + const N = grid.length; + const count = {}; + + for (let i = 0; i < N; i++) { + for (let j = 0; j < N; j++) { + let val = grid[i][j]; + count[val] = (count[val] || 0) + 1; + } + } + + let doubleVal = 0, missing = 0; + + for (let num = 1; num <= N * N; num++) { + let freq = count[num] || 0; + if (freq === 0) missing = num; + if (freq === 2) doubleVal = num; + } + + return [doubleVal, missing]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n ^ 2)$ + +--- + +## 3. Hash Set + +::tabs-start + +```python +class Solution: + def findMissingAndRepeatedValues(self, grid: List[List[int]]) -> List[int]: + N = len(grid) + seen = set() + double = missing = 0 + + for i in range(N): + for j in range(N): + if grid[i][j] in seen: + double = grid[i][j] + seen.add(grid[i][j]) + + for num in range(1, N * N + 1): + if num not in seen: + missing = num + break + + return [double, missing] +``` + +```java +public class Solution { + public int[] findMissingAndRepeatedValues(int[][] grid) { + int N = grid.length; + Set seen = new HashSet<>(); + int doubleVal = 0, missing = 0; + + for (int i = 0; i < N; i++) { + for (int j = 0; j < N; j++) { + if (seen.contains(grid[i][j])) { + doubleVal = grid[i][j]; + } + seen.add(grid[i][j]); + } + } + + for (int num = 1; num <= N * N; num++) { + if (!seen.contains(num)) { + missing = num; + break; + } + } + + return new int[]{doubleVal, missing}; + } +} +``` + +```cpp +class Solution { +public: + vector findMissingAndRepeatedValues(vector>& grid) { + int N = grid.size(); + unordered_set seen; + int doubleVal = 0, missing = 0; + + for (int i = 0; i < N; i++) { + for (int j = 0; j < N; j++) { + if (seen.count(grid[i][j])) { + doubleVal = grid[i][j]; + } + seen.insert(grid[i][j]); + } + } + + for (int num = 1; num <= N * N; num++) { + if (!seen.count(num)) { + missing = num; + break; + } + } + + return {doubleVal, missing}; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number[]} + */ + findMissingAndRepeatedValues(grid) { + const N = grid.length; + const seen = new Set(); + let doubleVal = 0, missing = 0; + + for (let i = 0; i < N; i++) { + for (let j = 0; j < N; j++) { + const val = grid[i][j]; + if (seen.has(val)) { + doubleVal = val; + } + seen.add(val); + } + } + + for (let num = 1; num <= N * N; num++) { + if (!seen.has(num)) { + missing = num; + break; + } + } + + return [doubleVal, missing]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n ^ 2)$ + +--- + +## 4. Math + +::tabs-start + +```python +class Solution: + def findMissingAndRepeatedValues(self, grid: List[List[int]]) -> List[int]: + N = len(grid) + gridSum = 0 + gridSqSum = 0 + + for i in range(N): + for j in range(N): + gridSum += grid[i][j] + gridSqSum += grid[i][j] * grid[i][j] + + totSum = (N * N * (N * N + 1)) // 2 + diff = gridSum - totSum # a - b + + totSqSum = (N * N * (N * N + 1) * (2 * N * N + 1)) // 6 + sqDiff = gridSqSum - totSqSum # (a^2) - (b^2) + + sum = sqDiff // diff # a + b + + a = (sum + diff) // 2 + b = sum - a + return [a, b] +``` + +```java +public class Solution { + public int[] findMissingAndRepeatedValues(int[][] grid) { + int N = grid.length; + long gridSum = 0; + long gridSqSum = 0; + + for (int i = 0; i < N; i++) { + for (int j = 0; j < N; j++) { + gridSum += grid[i][j]; + gridSqSum += 1L * grid[i][j] * grid[i][j]; + } + } + + long totSum = (long) N * N * (N * N + 1) / 2; + long diff = gridSum - totSum; // a - b + + long totSqSum = (long) N * N * (N * N + 1) * (2L * N * N + 1) / 6; + long sqDiff = gridSqSum - totSqSum; // (a^2) - (b^2) + + long sum = sqDiff / diff; // a + b + + long a = (sum + diff) / 2; + long b = sum - a; + + return new int[]{(int) a, (int) b}; + } +} +``` + +```cpp +class Solution { +public: + vector findMissingAndRepeatedValues(vector>& grid) { + int N = grid.size(); + long long gridSum = 0; + long long gridSqSum = 0; + + for (int i = 0; i < N; i++) { + for (int j = 0; j < N; j++) { + gridSum += grid[i][j]; + gridSqSum += 1LL * grid[i][j] * grid[i][j]; + } + } + + long long totSum = 1LL * N * N * (N * N + 1) / 2; + long long diff = gridSum - totSum; // a - b + + long long totSqSum = 1LL * N * N * (N * N + 1) * (2 * N * N + 1) / 6; + long long sqDiff = gridSqSum - totSqSum; // (a^2) - (b^2) + + long long sum = sqDiff / diff; // a + b + + int a = (sum + diff) / 2; + int b = sum - a; + + return {a, b}; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number[]} + */ + findMissingAndRepeatedValues(grid) { + const N = grid.length; + let gridSum = 0; + let gridSqSum = 0; + + for (let i = 0; i < N; i++) { + for (let j = 0; j < N; j++) { + gridSum += grid[i][j]; + gridSqSum += grid[i][j] * grid[i][j]; + } + } + + let totSum = N * N * (N * N + 1) / 2; + let diff = gridSum - totSum; // a - b + + let totSqSum = N * N * (N * N + 1) * (2 * N * N + 1) / 6; + let sqDiff = gridSqSum - totSqSum; // (a^2) - (b^2) + + let sum = sqDiff / diff; // a + b + + let a = (sum + diff) / 2; + let b = sum - a; + + return [a, b]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(1)$ \ No newline at end of file diff --git a/articles/height-checker.md b/articles/height-checker.md new file mode 100644 index 000000000..1e0919676 --- /dev/null +++ b/articles/height-checker.md @@ -0,0 +1,206 @@ +## 1. Sorting + +::tabs-start + +```python +class Solution: + def heightChecker(self, heights: List[int]) -> int: + expected = sorted(heights) + + res = 0 + for i in range(len(heights)): + if heights[i] != expected[i]: + res += 1 + + return res +``` + +```java +public class Solution { + public int heightChecker(int[] heights) { + int[] expected = Arrays.copyOf(heights, heights.length); + Arrays.sort(expected); + + int res = 0; + for (int i = 0; i < heights.length; i++) { + if (heights[i] != expected[i]) { + res++; + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int heightChecker(vector& heights) { + vector expected = heights; + sort(expected.begin(), expected.end()); + + int res = 0; + for (int i = 0; i < heights.size(); i++) { + if (heights[i] != expected[i]) { + res++; + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} heights + * @return {number} + */ + heightChecker(heights) { + const expected = [...heights].sort((a, b) => a - b); + + let res = 0; + for (let i = 0; i < heights.length; i++) { + if (heights[i] !== expected[i]) { + res++; + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(n)$ + +--- + +## 2. Counting Sort + +::tabs-start + +```python +class Solution: + def heightChecker(self, heights: List[int]) -> int: + count = [0] * 101 + for h in heights: + count[h] += 1 + + expected = [] + for h in range(1, 101): + c = count[h] + for _ in range(c): + expected.append(h) + + res = 0 + for i in range(len(heights)): + if heights[i] != expected[i]: + res += 1 + + return res +``` + +```java +public class Solution { + public int heightChecker(int[] heights) { + int[] count = new int[101]; + for (int h : heights) { + count[h]++; + } + + List expected = new ArrayList<>(); + for (int h = 1; h <= 100; h++) { + int c = count[h]; + for (int i = 0; i < c; i++) { + expected.add(h); + } + } + + int res = 0; + for (int i = 0; i < heights.length; i++) { + if (heights[i] != expected.get(i)) { + res++; + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int heightChecker(vector& heights) { + int count[101] = {}; + for (int h : heights) { + count[h]++; + } + + vector expected; + for (int h = 1; h <= 100; h++) { + int c = count[h]; + for (int i = 0; i < c; i++) { + expected.push_back(h); + } + } + + int res = 0; + for (int i = 0; i < heights.size(); i++) { + if (heights[i] != expected[i]) { + res++; + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} heights + * @return {number} + */ + heightChecker(heights) { + const count = new Array(101).fill(0); + for (let h of heights) { + count[h]++; + } + + const expected = []; + for (let h = 1; h <= 100; h++) { + let c = count[h]; + for (let i = 0; i < c; i++) { + expected.push(h); + } + } + + let res = 0; + for (let i = 0; i < heights.length; i++) { + if (heights[i] !== expected[i]) { + res++; + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n + k)$ +* Space complexity: $O(n + k)$ + +> Where $n$ is the size of the input array, and $k$ is the range of numbers. \ No newline at end of file diff --git a/articles/kth-distinct-string-in-an-array.md b/articles/kth-distinct-string-in-an-array.md new file mode 100644 index 000000000..244281490 --- /dev/null +++ b/articles/kth-distinct-string-in-an-array.md @@ -0,0 +1,350 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def kthDistinct(self, arr: List[str], k: int) -> str: + for i in range(len(arr)): + flag = True + for j in range(len(arr)): + if i == j: + continue + + if arr[i] == arr[j]: + flag = False + break + + if flag: + k -= 1 + if k == 0: + return arr[i] + return "" +``` + +```java +public class Solution { + public String kthDistinct(String[] arr, int k) { + for (int i = 0; i < arr.length; i++) { + boolean flag = true; + for (int j = 0; j < arr.length; j++) { + if (i == j) continue; + + if (arr[i].equals(arr[j])) { + flag = false; + break; + } + } + + if (flag) { + k--; + if (k == 0) { + return arr[i]; + } + } + } + return ""; + } +} +``` + +```cpp +class Solution { +public: + string kthDistinct(vector& arr, int k) { + for (int i = 0; i < arr.size(); i++) { + bool flag = true; + for (int j = 0; j < arr.size(); j++) { + if (i == j) continue; + + if (arr[i] == arr[j]) { + flag = false; + break; + } + } + + if (flag) { + k--; + if (k == 0) { + return arr[i]; + } + } + } + return ""; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} arr + * @param {number} k + * @return {string} + */ + kthDistinct(arr, k) { + for (let i = 0; i < arr.length; i++) { + let flag = true; + for (let j = 0; j < arr.length; j++) { + if (i === j) continue; + + if (arr[i] === arr[j]) { + flag = false; + break; + } + } + + if (flag) { + k--; + if (k === 0) { + return arr[i]; + } + } + } + return ""; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(1)$ + +--- + +## 2. Hash Map + +::tabs-start + +```python +class Solution: + def kthDistinct(self, arr: List[str], k: int) -> str: + count = {} + + for s in arr: + if s not in count: + count[s] = 0 + count[s] += 1 + + for s in arr: + if count[s] == 1: + k -= 1 + if k == 0: + return s + + return "" +``` + +```java +public class Solution { + public String kthDistinct(String[] arr, int k) { + Map count = new HashMap<>(); + + for (String s : arr) { + count.put(s, count.getOrDefault(s, 0) + 1); + } + + for (String s : arr) { + if (count.get(s) == 1) { + k--; + if (k == 0) { + return s; + } + } + } + + return ""; + } +} +``` + +```cpp +class Solution { +public: + string kthDistinct(vector& arr, int k) { + unordered_map count; + + for (const string& s : arr) { + count[s]++; + } + + for (const string& s : arr) { + if (count[s] == 1) { + k--; + if (k == 0) { + return s; + } + } + } + + return ""; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} arr + * @param {number} k + * @return {string} + */ + kthDistinct(arr, k) { + const count = {}; + + for (let s of arr) { + if (!(s in count)) { + count[s] = 0; + } + count[s]++; + } + + for (let s of arr) { + if (count[s] === 1) { + k--; + if (k === 0) { + return s; + } + } + } + + return ""; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 3. Hash Set + +::tabs-start + +```python +class Solution: + def kthDistinct(self, arr: List[str], k: int) -> str: + distinct, seen = set(), set() + + for s in arr: + if s in distinct: + distinct.remove(s) + seen.add(s) + elif s not in seen: + distinct.add(s) + + for s in arr: + if s in distinct: + k -= 1 + if k == 0: + return s + + return "" +``` + +```java +public class Solution { + public String kthDistinct(String[] arr, int k) { + Set distinct = new HashSet<>(); + Set seen = new HashSet<>(); + + for (String s : arr) { + if (distinct.contains(s)) { + distinct.remove(s); + seen.add(s); + } else if (!seen.contains(s)) { + distinct.add(s); + } + } + + for (String s : arr) { + if (distinct.contains(s)) { + k--; + if (k == 0) { + return s; + } + } + } + + return ""; + } +} +``` + +```cpp +class Solution { +public: + string kthDistinct(vector& arr, int k) { + unordered_set distinct, seen; + + for (const string& s : arr) { + if (distinct.count(s)) { + distinct.erase(s); + seen.insert(s); + } else if (!seen.count(s)) { + distinct.insert(s); + } + } + + for (const string& s : arr) { + if (distinct.count(s)) { + k--; + if (k == 0) { + return s; + } + } + } + + return ""; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} arr + * @param {number} k + * @return {string} + */ + kthDistinct(arr, k) { + const distinct = new Set(); + const seen = new Set(); + + for (let s of arr) { + if (distinct.has(s)) { + distinct.delete(s); + seen.add(s); + } else if (!seen.has(s)) { + distinct.add(s); + } + } + + for (let s of arr) { + if (distinct.has(s)) { + k--; + if (k === 0) { + return s; + } + } + } + + return ""; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ \ No newline at end of file diff --git a/articles/longest-palindrome.md b/articles/longest-palindrome.md new file mode 100644 index 000000000..635b7a163 --- /dev/null +++ b/articles/longest-palindrome.md @@ -0,0 +1,419 @@ +## 1. Hash Map + +::tabs-start + +```python +class Solution: + def longestPalindrome(self, s: str) -> int: + count = defaultdict(int) + res = 0 + + for c in s: + count[c] += 1 + if count[c] % 2 == 0: + res += 2 + + for cnt in count.values(): + if cnt % 2: + res += 1 + break + + return res +``` + +```java +public class Solution { + public int longestPalindrome(String s) { + Map count = new HashMap<>(); + int res = 0; + + for (char c : s.toCharArray()) { + count.put(c, count.getOrDefault(c, 0) + 1); + if (count.get(c) % 2 == 0) { + res += 2; + } + } + + for (int cnt : count.values()) { + if (cnt % 2 == 1) { + res += 1; + break; + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int longestPalindrome(string s) { + unordered_map count; + int res = 0; + + for (char c : s) { + count[c]++; + if (count[c] % 2 == 0) { + res += 2; + } + } + + for (auto& [ch, cnt] : count) { + if (cnt % 2 == 1) { + res += 1; + break; + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {number} + */ + longestPalindrome(s) { + const count = {}; + let res = 0; + + for (let c of s) { + count[c] = (count[c] || 0) + 1; + if (count[c] % 2 === 0) { + res += 2; + } + } + + for (let key in count) { + if (count[key] % 2 === 1) { + res += 1; + break; + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(m)$ + +> Where $n$ is the length of the given string, and $m$ is the number of distinct characters in the string. + +--- + +## 2. Hash Map (Optimal) + +::tabs-start + +```python +class Solution: + def longestPalindrome(self, s: str) -> int: + count = defaultdict(int) + res = 0 + + for c in s: + count[c] += 1 + if count[c] % 2 == 0: + res += 2 + + return res + (res < len(s)) +``` + +```java +public class Solution { + public int longestPalindrome(String s) { + Map count = new HashMap<>(); + int res = 0; + + for (char c : s.toCharArray()) { + count.put(c, count.getOrDefault(c, 0) + 1); + if (count.get(c) % 2 == 0) { + res += 2; + } + } + + return res + (res < s.length() ? 1 : 0); + } +} +``` + +```cpp +class Solution { +public: + int longestPalindrome(string s) { + unordered_map count; + int res = 0; + + for (char c : s) { + count[c]++; + if (count[c] % 2 == 0) { + res += 2; + } + } + + return res + (res < s.size()); + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {number} + */ + longestPalindrome(s) { + const count = {}; + let res = 0; + + for (let c of s) { + count[c] = (count[c] || 0) + 1; + if (count[c] % 2 === 0) { + res += 2; + } + } + + return res + (res < s.length ? 1 : 0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(m)$ + +> Where $n$ is the length of the given string, and $m$ is the number of distinct characters in the string. + +--- + +## 3. Hash Set + +::tabs-start + +```python +class Solution: + def longestPalindrome(self, s: str) -> int: + seen = set() + res = 0 + + for c in s: + if c in seen: + seen.remove(c) + res += 2 + else: + seen.add(c) + + return res + 1 if seen else res +``` + +```java +public class Solution { + public int longestPalindrome(String s) { + Set seen = new HashSet<>(); + int res = 0; + + for (char c : s.toCharArray()) { + if (seen.contains(c)) { + seen.remove(c); + res += 2; + } else { + seen.add(c); + } + } + + return seen.isEmpty() ? res : res + 1; + } +} +``` + +```cpp +class Solution { +public: + int longestPalindrome(string s) { + unordered_set seen; + int res = 0; + + for (char c : s) { + if (seen.count(c)) { + seen.erase(c); + res += 2; + } else { + seen.insert(c); + } + } + + return seen.empty() ? res : res + 1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {number} + */ + longestPalindrome(s) { + const seen = new Set(); + let res = 0; + + for (let c of s) { + if (seen.has(c)) { + seen.delete(c); + res += 2; + } else { + seen.add(c); + } + } + + return seen.size === 0 ? res : res + 1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(m)$ + +> Where $n$ is the length of the given string, and $m$ is the number of distinct characters in the string. + +--- + +## 4. Bitmask + +::tabs-start + +```python +class Solution: + def longestPalindrome(self, s: str) -> int: + mask1 = 0 # [a - z] + mask2 = 0 # [A - Z] + res = 0 + + for c in s: + if 'a' <= c <= 'z': + bit = 1 << (ord(c) - ord('a')) + if mask1 & bit: + res += 2 + mask1 ^= bit + else: + bit = 1 << (ord(c) - ord('A')) + if mask2 & bit: + res += 2 + mask2 ^= bit + + return res + 1 if mask1 or mask2 else res +``` + +```java +public class Solution { + public int longestPalindrome(String s) { + int mask1 = 0; // [a - z] + int mask2 = 0; // [A - Z] + int res = 0; + + for (char c : s.toCharArray()) { + if (c >= 'a' && c <= 'z') { + int bit = 1 << (c - 'a'); + if ((mask1 & bit) != 0) { + res += 2; + } + mask1 ^= bit; + } else { + int bit = 1 << (c - 'A'); + if ((mask2 & bit) != 0) { + res += 2; + } + mask2 ^= bit; + } + } + + return (mask1 != 0 || mask2 != 0) ? res + 1 : res; + } +} +``` + +```cpp +class Solution { +public: + int longestPalindrome(string s) { + int mask1 = 0; // [a - z] + int mask2 = 0; // [A - Z] + int res = 0; + + for (char c : s) { + if ('a' <= c && c <= 'z') { + int bit = 1 << (c - 'a'); + if (mask1 & bit) { + res += 2; + } + mask1 ^= bit; + } else { + int bit = 1 << (c - 'A'); + if (mask2 & bit) { + res += 2; + } + mask2 ^= bit; + } + } + + return (mask1 || mask2) ? res + 1 : res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {number} + */ + longestPalindrome(s) { + let mask1 = 0; // [a - z] + let mask2 = 0; // [A - Z] + let res = 0; + + for (let c of s) { + if (c >= 'a' && c <= 'z') { + let bit = 1 << (c.charCodeAt(0) - 97); + if (mask1 & bit) { + res += 2; + } + mask1 ^= bit; + } else { + let bit = 1 << (c.charCodeAt(0) - 65); + if (mask2 & bit) { + res += 2; + } + mask2 ^= bit; + } + } + + return (mask1 || mask2) ? res + 1 : res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ \ No newline at end of file diff --git a/articles/longest-strictly-increasing-or-strictly-decreasing-subarray.md b/articles/longest-strictly-increasing-or-strictly-decreasing-subarray.md new file mode 100644 index 000000000..4c55b7a6b --- /dev/null +++ b/articles/longest-strictly-increasing-or-strictly-decreasing-subarray.md @@ -0,0 +1,454 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def longestMonotonicSubarray(self, nums: List[int]) -> int: + n = len(nums) + res = 1 + + for i in range(n - 1): + curLen = 1 + for j in range(i + 1, n): + if nums[j] == nums[j - 1] or ((nums[i] < nums[i + 1]) != (nums[j - 1] < nums[j])): + break + curLen += 1 + + res = max(res, curLen) + + return res +``` + +```java +public class Solution { + public int longestMonotonicSubarray(int[] nums) { + int n = nums.length; + int res = 1; + + for (int i = 0; i < n - 1; i++) { + int curLen = 1; + for (int j = i + 1; j < n; j++) { + if (nums[j] == nums[j - 1] || ((nums[i] < nums[i + 1]) != (nums[j - 1] < nums[j]))) { + break; + } + curLen++; + } + res = Math.max(res, curLen); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int longestMonotonicSubarray(vector& nums) { + int n = nums.size(); + int res = 1; + + for (int i = 0; i < n - 1; i++) { + int curLen = 1; + for (int j = i + 1; j < n; j++) { + if (nums[j] == nums[j - 1] || ((nums[i] < nums[i + 1]) != (nums[j - 1] < nums[j]))) { + break; + } + curLen++; + } + res = max(res, curLen); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + longestMonotonicSubarray(nums) { + let n = nums.length; + let res = 1; + + for (let i = 0; i < n - 1; i++) { + let curLen = 1; + for (let j = i + 1; j < n; j++) { + if (nums[j] === nums[j - 1] || ((nums[i] < nums[i + 1]) !== (nums[j - 1] < nums[j]))) { + break; + } + curLen++; + } + res = Math.max(res, curLen); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(1)$ + +--- + +## 2. Iteration - I + +::tabs-start + +```python +class Solution: + def longestMonotonicSubarray(self, nums: List[int]) -> int: + cur = 1 + res = 1 + increasing = 0 + + for i in range(1, len(nums)): + if nums[i - 1] < nums[i]: + if increasing > 0: + cur += 1 + else: + cur = 2 + increasing = 1 + elif nums[i - 1] > nums[i]: + if increasing < 0: + cur += 1 + else: + cur = 2 + increasing = -1 + else: + cur = 1 + increasing = 0 + res = max(res, cur) + + return res +``` + +```java +public class Solution { + public int longestMonotonicSubarray(int[] nums) { + int cur = 1; + int res = 1; + int increasing = 0; + + for (int i = 1; i < nums.length; i++) { + if (nums[i - 1] < nums[i]) { + if (increasing > 0) { + cur++; + } else { + cur = 2; + increasing = 1; + } + } else if (nums[i - 1] > nums[i]) { + if (increasing < 0) { + cur++; + } else { + cur = 2; + increasing = -1; + } + } else { + cur = 1; + increasing = 0; + } + res = Math.max(res, cur); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int longestMonotonicSubarray(vector& nums) { + int cur = 1; + int res = 1; + int increasing = 0; + + for (int i = 1; i < nums.size(); i++) { + if (nums[i - 1] < nums[i]) { + if (increasing > 0) { + cur++; + } else { + cur = 2; + increasing = 1; + } + } else if (nums[i - 1] > nums[i]) { + if (increasing < 0) { + cur++; + } else { + cur = 2; + increasing = -1; + } + } else { + cur = 1; + increasing = 0; + } + res = max(res, cur); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + longestMonotonicSubarray(nums) { + let cur = 1; + let res = 1; + let increasing = 0; + + for (let i = 1; i < nums.length; i++) { + if (nums[i - 1] < nums[i]) { + if (increasing > 0) { + cur++; + } else { + cur = 2; + increasing = 1; + } + } else if (nums[i - 1] > nums[i]) { + if (increasing < 0) { + cur++; + } else { + cur = 2; + increasing = -1; + } + } else { + cur = 1; + increasing = 0; + } + res = Math.max(res, cur); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ + +--- + +## 3. Iteration - II + +::tabs-start + +```python +class Solution: + def longestMonotonicSubarray(self, nums: List[int]) -> int: + inc = dec = 1 + res = 1 + + for i in range(1, len(nums)): + if nums[i] == nums[i - 1]: + inc = dec = 1 + elif nums[i] > nums[i - 1]: + inc, dec = inc + 1, 1 + else: + inc, dec = 1, dec + 1 + + res = max(res, inc, dec) + + return res +``` + +```java +public class Solution { + public int longestMonotonicSubarray(int[] nums) { + int inc = 1, dec = 1, res = 1; + + for (int i = 1; i < nums.length; i++) { + if (nums[i] == nums[i - 1]) { + inc = dec = 1; + } else if (nums[i] > nums[i - 1]) { + inc = inc + 1; + dec = 1; + } else { + inc = 1; + dec = dec + 1; + } + res = Math.max(res, Math.max(inc, dec)); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int longestMonotonicSubarray(vector& nums) { + int inc = 1, dec = 1, res = 1; + + for (int i = 1; i < nums.size(); i++) { + if (nums[i] == nums[i - 1]) { + inc = dec = 1; + } else if (nums[i] > nums[i - 1]) { + inc = inc + 1; + dec = 1; + } else { + inc = 1; + dec = dec + 1; + } + res = max(res, max(inc, dec)); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + longestMonotonicSubarray(nums) { + let inc = 1, dec = 1, res = 1; + + for (let i = 1; i < nums.length; i++) { + if (nums[i] === nums[i - 1]) { + inc = dec = 1; + } else if (nums[i] > nums[i - 1]) { + inc = inc + 1; + dec = 1; + } else { + inc = 1; + dec = dec + 1; + } + res = Math.max(res, inc, dec); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ + +--- + +## 4. Iteration - III + +::tabs-start + +```python +class Solution: + def longestMonotonicSubarray(self, nums: List[int]) -> int: + curLen = res = 1 + + for i in range(1, len(nums)): + if (nums[i] == nums[i - 1] or + ((nums[i - curLen] < nums[i - curLen + 1]) != (nums[i - 1] < nums[i])) + ): + curLen = 1 if (nums[i] == nums[i - 1]) else 2 + continue + + curLen += 1 + res = max(res, curLen) + + return res +``` + +```java +public class Solution { + public int longestMonotonicSubarray(int[] nums) { + int curLen = 1, res = 1; + + for (int i = 1; i < nums.length; i++) { + if (nums[i] == nums[i - 1] || + ((nums[i - curLen] < nums[i - curLen + 1]) != (nums[i - 1] < nums[i]))) { + curLen = (nums[i] == nums[i - 1]) ? 1 : 2; + continue; + } + + curLen++; + res = Math.max(res, curLen); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int longestMonotonicSubarray(vector& nums) { + int curLen = 1, res = 1; + + for (int i = 1; i < nums.size(); i++) { + if (nums[i] == nums[i - 1] || + ((nums[i - curLen] < nums[i - curLen + 1]) != (nums[i - 1] < nums[i]))) { + curLen = (nums[i] == nums[i - 1]) ? 1 : 2; + continue; + } + + curLen++; + res = max(res, curLen); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + longestMonotonicSubarray(nums) { + let curLen = 1, res = 1; + + for (let i = 1; i < nums.length; i++) { + if ( + nums[i] === nums[i - 1] || + ((nums[i - curLen] < nums[i - curLen + 1]) !== (nums[i - 1] < nums[i])) + ) { + curLen = nums[i] === nums[i - 1] ? 1 : 2; + continue; + } + + curLen++; + res = Math.max(res, curLen); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ \ No newline at end of file diff --git a/articles/make-sum-divisible-by-p.md b/articles/make-sum-divisible-by-p.md new file mode 100644 index 000000000..493f5732c --- /dev/null +++ b/articles/make-sum-divisible-by-p.md @@ -0,0 +1,235 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def minSubarray(self, nums: List[int], p: int) -> int: + n = len(nums) + totSum = sum(nums) + + if totSum % p == 0: + return 0 + + for l in range(1, n): + curSum = 0 + for i in range(n): + curSum += nums[i] + if i >= l: + curSum -= nums[i - l] + + remainSum = totSum - curSum + if remainSum % p == 0: + return l + + return -1 +``` + +```java +public class Solution { + public int minSubarray(int[] nums, int p) { + int n = nums.length; + long totSum = 0; + for (int num : nums) totSum += num; + + if (totSum % p == 0) return 0; + + for (int l = 1; l < n; l++) { + long curSum = 0; + for (int i = 0; i < n; i++) { + curSum += nums[i]; + if (i >= l) curSum -= nums[i - l]; + + long remainSum = totSum - curSum; + if (remainSum % p == 0) return l; + } + } + + return -1; + } +} +``` + +```cpp +class Solution { +public: + int minSubarray(vector& nums, int p) { + int n = nums.size(); + long long totSum = 0; + for (int num : nums) totSum += num; + + if (totSum % p == 0) return 0; + + for (int l = 1; l < n; l++) { + long long curSum = 0; + for (int i = 0; i < n; i++) { + curSum += nums[i]; + if (i >= l) curSum -= nums[i - l]; + + long long remainSum = totSum - curSum; + if (remainSum % p == 0) return l; + } + } + + return -1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} p + * @return {number} + */ + minSubarray(nums, p) { + const n = nums.length; + let totSum = nums.reduce((a, b) => a + b, 0); + + if (totSum % p === 0) return 0; + + for (let l = 1; l < n; l++) { + let curSum = 0; + for (let i = 0; i < n; i++) { + curSum += nums[i]; + if (i >= l) curSum -= nums[i - l]; + + const remainSum = totSum - curSum; + if (remainSum % p === 0) return l; + } + } + + return -1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(1)$ + +--- + +## 2. Prefix Sum + +::tabs-start + +```python +class Solution: + def minSubarray(self, nums: List[int], p: int) -> int: + total = sum(nums) + remain = total % p + if remain == 0: + return 0 + + res = len(nums) + cur_sum = 0 + remain_to_idx = {0: -1} + + for i, n in enumerate(nums): + cur_sum = (cur_sum + n) % p + prefix = (cur_sum - remain + p) % p + if prefix in remain_to_idx: + length = i - remain_to_idx[prefix] + res = min(res, length) + remain_to_idx[cur_sum] = i + + return -1 if res == len(nums) else res +``` + +```java +public class Solution { + public int minSubarray(int[] nums, int p) { + long total = 0; + for (int num : nums) total += num; + int remain = (int)(total % p); + if (remain == 0) return 0; + + int res = nums.length; + long curSum = 0; + Map map = new HashMap<>(); + map.put(0, -1); + + for (int i = 0; i < nums.length; i++) { + curSum = (curSum + nums[i]) % p; + int prefix = (int)((curSum - remain + p) % p); + if (map.containsKey(prefix)) { + res = Math.min(res, i - map.get(prefix)); + } + map.put((int)curSum, i); + } + + return res == nums.length ? -1 : res; + } +} +``` + +```cpp +class Solution { +public: + int minSubarray(vector& nums, int p) { + long total = 0; + for (int num : nums) total += num; + int remain = total % p; + if (remain == 0) return 0; + + int res = nums.size(); + long curSum = 0; + unordered_map map; + map[0] = -1; + + for (int i = 0; i < nums.size(); i++) { + curSum = (curSum + nums[i]) % p; + int prefix = (curSum - remain + p) % p; + if (map.count(prefix)) { + res = min(res, i - map[prefix]); + } + map[curSum] = i; + } + + return res == nums.size() ? -1 : res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} p + * @return {number} + */ + minSubarray(nums, p) { + let total = nums.reduce((a, b) => a + b, 0); + let remain = total % p; + if (remain === 0) return 0; + + let res = nums.length; + let curSum = 0; + const map = new Map(); + map.set(0, -1); + + for (let i = 0; i < nums.length; i++) { + curSum = (curSum + nums[i]) % p; + let prefix = (curSum - remain + p) % p; + if (map.has(prefix)) { + res = Math.min(res, i - map.get(prefix)); + } + map.set(curSum, i); + } + + return res === nums.length ? -1 : res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ \ No newline at end of file diff --git a/articles/maximum-ascending-subarray-sum.md b/articles/maximum-ascending-subarray-sum.md new file mode 100644 index 000000000..5d4e47a60 --- /dev/null +++ b/articles/maximum-ascending-subarray-sum.md @@ -0,0 +1,173 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def maxAscendingSum(self, nums: List[int]) -> int: + res = 0 + for i in range(len(nums)): + curSum = nums[i] + for j in range(i + 1, len(nums)): + if nums[j] <= nums[j - 1]: + break + curSum += nums[j] + res = max(res, curSum) + return res +``` + +```java +public class Solution { + public int maxAscendingSum(int[] nums) { + int res = 0; + for (int i = 0; i < nums.length; i++) { + int curSum = nums[i]; + for (int j = i + 1; j < nums.length; j++) { + if (nums[j] <= nums[j - 1]) { + break; + } + curSum += nums[j]; + } + res = Math.max(res, curSum); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int maxAscendingSum(vector& nums) { + int res = 0; + for (int i = 0; i < nums.size(); i++) { + int curSum = nums[i]; + for (int j = i + 1; j < nums.size(); j++) { + if (nums[j] <= nums[j - 1]) { + break; + } + curSum += nums[j]; + } + res = max(res, curSum); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + maxAscendingSum(nums) { + let res = 0; + for (let i = 0; i < nums.length; i++) { + let curSum = nums[i]; + for (let j = i + 1; j < nums.length; j++) { + if (nums[j] <= nums[j - 1]) { + break; + } + curSum += nums[j]; + } + res = Math.max(res, curSum); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(1)$ + +--- + +## 2. Iteration + +::tabs-start + +```python +class Solution: + def maxAscendingSum(self, nums: List[int]) -> int: + res = curSum= nums[0] + + for i in range(1, len(nums)): + if nums[i] <= nums[i - 1]: + curSum = 0 + + curSum += nums[i] + res = max(res, curSum) + + return res +``` + +```java +public class Solution { + public int maxAscendingSum(int[] nums) { + int res = nums[0], curSum = nums[0]; + + for (int i = 1; i < nums.length; i++) { + if (nums[i] <= nums[i - 1]) { + curSum = 0; + } + curSum += nums[i]; + res = Math.max(res, curSum); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int maxAscendingSum(vector& nums) { + int res = nums[0], curSum = nums[0]; + + for (int i = 1; i < nums.size(); i++) { + if (nums[i] <= nums[i - 1]) { + curSum = 0; + } + curSum += nums[i]; + res = max(res, curSum); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + maxAscendingSum(nums) { + let res = nums[0], curSum = nums[0]; + + for (let i = 1; i < nums.length; i++) { + if (nums[i] <= nums[i - 1]) { + curSum = 0; + } + curSum += nums[i]; + res = Math.max(res, curSum); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ \ No newline at end of file diff --git a/articles/minimum-index-of-a-valid-split.md b/articles/minimum-index-of-a-valid-split.md new file mode 100644 index 000000000..17548cd54 --- /dev/null +++ b/articles/minimum-index-of-a-valid-split.md @@ -0,0 +1,385 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def minimumIndex(self, nums: List[int]) -> int: + n = len(nums) + + for i in range(n - 1): + left_cnt = defaultdict(int) + for l in range(i + 1): + left_cnt[nums[l]] += 1 + + right_cnt = defaultdict(int) + for r in range(i + 1, n): + right_cnt[nums[r]] += 1 + + for num in left_cnt: + if left_cnt[num] > (i + 1) // 2 and right_cnt[num] > (n - i - 1) // 2: + return i + + return -1 +``` + +```java +public class Solution { + public int minimumIndex(List nums) { + int n = nums.size(); + + for (int i = 0; i < n - 1; i++) { + Map leftCnt = new HashMap<>(); + for (int l = 0; l <= i; l++) { + int val = nums.get(l); + leftCnt.put(val, leftCnt.getOrDefault(val, 0) + 1); + } + + Map rightCnt = new HashMap<>(); + for (int r = i + 1; r < n; r++) { + int val = nums.get(r); + rightCnt.put(val, rightCnt.getOrDefault(val, 0) + 1); + } + + for (int num : leftCnt.keySet()) { + if (leftCnt.get(num) > (i + 1) / 2 && rightCnt.getOrDefault(num, 0) > (n - i - 1) / 2) { + return i; + } + } + } + + return -1; + } +} +``` + +```cpp +class Solution { +public: + int minimumIndex(vector& nums) { + int n = nums.size(); + + for (int i = 0; i < n - 1; i++) { + unordered_map leftCnt, rightCnt; + for (int l = 0; l <= i; l++) { + leftCnt[nums[l]]++; + } + for (int r = i + 1; r < n; r++) { + rightCnt[nums[r]]++; + } + + for (auto& [num, cnt] : leftCnt) { + if (cnt > (i + 1) / 2 && rightCnt[num] > (n - i - 1) / 2) { + return i; + } + } + } + + return -1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + minimumIndex(nums) { + const n = nums.length; + + for (let i = 0; i < n - 1; i++) { + const leftCnt = {}; + for (let l = 0; l <= i; l++) { + leftCnt[nums[l]] = (leftCnt[nums[l]] || 0) + 1; + } + + const rightCnt = {}; + for (let r = i + 1; r < n; r++) { + rightCnt[nums[r]] = (rightCnt[nums[r]] || 0) + 1; + } + + for (const num in leftCnt) { + if (leftCnt[num] > Math.floor((i + 1) / 2) && + (rightCnt[num] || 0) > Math.floor((n - i - 1) / 2)) { + return i; + } + } + } + + return -1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n)$ + +--- + +## 2. Hash Map + +::tabs-start + +```python +class Solution: + def minimumIndex(self, nums: List[int]) -> int: + left = defaultdict(int) + right = Counter(nums) + + for i in range(len(nums)): + left[nums[i]] += 1 + right[nums[i]] -= 1 + + left_len = i + 1 + right_len = len(nums) - i - 1 + + if 2 * left[nums[i]] > left_len and 2 * right[nums[i]] > right_len: + return i + + return -1 +``` + +```java +public class Solution { + public int minimumIndex(List nums) { + Map left = new HashMap<>(); + Map right = new HashMap<>(); + int n = nums.size(); + + for (int num : nums) { + right.put(num, right.getOrDefault(num, 0) + 1); + } + + for (int i = 0; i < n; i++) { + int num = nums.get(i); + left.put(num, left.getOrDefault(num, 0) + 1); + right.put(num, right.get(num) - 1); + + int leftLen = i + 1; + int rightLen = n - i - 1; + + if (2 * left.get(num) > leftLen && 2 * right.get(num) > rightLen) { + return i; + } + } + + return -1; + } +} +``` + +```cpp +class Solution { +public: + int minimumIndex(vector& nums) { + unordered_map left, right; + int n = nums.size(); + + for (int num : nums) { + right[num]++; + } + + for (int i = 0; i < n; i++) { + int num = nums[i]; + left[num]++; + right[num]--; + + int leftLen = i + 1; + int rightLen = n - i - 1; + + if (2 * left[num] > leftLen && 2 * right[num] > rightLen) { + return i; + } + } + + return -1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + minimumIndex(nums) { + const left = {}; + const right = {}; + const n = nums.length; + + for (const num of nums) { + right[num] = (right[num] || 0) + 1; + } + + for (let i = 0; i < n; i++) { + const num = nums[i]; + left[num] = (left[num] || 0) + 1; + right[num] -= 1; + + const leftLen = i + 1; + const rightLen = n - i - 1; + + if (2 * left[num] > leftLen && 2 * right[num] > rightLen) { + return i; + } + } + + return -1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 3. Boyer-Moore Voting Algorithm + +::tabs-start + +```python +class Solution: + def minimumIndex(self, nums: List[int]) -> int: + majority = count = 0 + for num in nums: + if count == 0: + majority = num + count += (1 if majority == num else -1) + + left_cnt, right_cnt = 0, nums.count(majority) + + for i in range(len(nums)): + if nums[i] == majority: + left_cnt += 1 + right_cnt -= 1 + + left_len = i + 1 + right_len = len(nums) - i - 1 + + if 2 * left_cnt > left_len and 2 * right_cnt > right_len: + return i + + return -1 +``` + +```java +public class Solution { + public int minimumIndex(List nums) { + int majority = 0, count = 0; + for (int num : nums) { + if (count == 0) majority = num; + count += (majority == num) ? 1 : -1; + } + + int leftCnt = 0, rightCnt = 0; + for (int num : nums) { + if (num == majority) rightCnt++; + } + + int n = nums.size(); + for (int i = 0; i < n; i++) { + if (nums.get(i) == majority) { + leftCnt++; + rightCnt--; + } + + int leftLen = i + 1; + int rightLen = n - i - 1; + + if (2 * leftCnt > leftLen && 2 * rightCnt > rightLen) { + return i; + } + } + + return -1; + } +} +``` + +```cpp +class Solution { +public: + int minimumIndex(vector& nums) { + int majority = 0, count = 0; + for (int num : nums) { + if (count == 0) majority = num; + count += (num == majority ? 1 : -1); + } + + int leftCnt = 0, rightCnt = count_if(nums.begin(), nums.end(), + [&](int x) { return x == majority; }); + + int n = nums.size(); + for (int i = 0; i < n; i++) { + if (nums[i] == majority) { + leftCnt++; + rightCnt--; + } + + int leftLen = i + 1; + int rightLen = n - i - 1; + + if (2 * leftCnt > leftLen && 2 * rightCnt > rightLen) { + return i; + } + } + + return -1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + minimumIndex(nums) { + let majority = 0, count = 0; + for (let num of nums) { + if (count === 0) majority = num; + count += (num === majority ? 1 : -1); + } + + let leftCnt = 0; + let rightCnt = nums.filter(x => x === majority).length; + const n = nums.length; + + for (let i = 0; i < n; i++) { + if (nums[i] === majority) { + leftCnt++; + rightCnt--; + } + + let leftLen = i + 1; + let rightLen = n - i - 1; + + if (2 * leftCnt > leftLen && 2 * rightCnt > rightLen) { + return i; + } + } + + return -1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ \ No newline at end of file diff --git a/articles/minimum-number-of-operations-to-move-all-balls-to-each-box.md b/articles/minimum-number-of-operations-to-move-all-balls-to-each-box.md new file mode 100644 index 000000000..c00bbfdb0 --- /dev/null +++ b/articles/minimum-number-of-operations-to-move-all-balls-to-each-box.md @@ -0,0 +1,325 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def minOperations(self, boxes: str) -> List[int]: + n = len(boxes) + res = [0] * n + + for pos in range(n): + for i in range(n): + if boxes[i] == '1': + res[pos] += abs(pos - i) + + return res +``` + +```java +public class Solution { + public int[] minOperations(String boxes) { + int n = boxes.length(); + int[] res = new int[n]; + + for (int pos = 0; pos < n; pos++) { + for (int i = 0; i < n; i++) { + if (boxes.charAt(i) == '1') { + res[pos] += Math.abs(pos - i); + } + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector minOperations(string boxes) { + int n = boxes.size(); + vector res(n, 0); + + for (int pos = 0; pos < n; pos++) { + for (int i = 0; i < n; i++) { + if (boxes[i] == '1') { + res[pos] += abs(pos - i); + } + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} boxes + * @return {number[]} + */ + minOperations(boxes) { + const n = boxes.length; + const res = new Array(n).fill(0); + + for (let pos = 0; pos < n; pos++) { + for (let i = 0; i < n; i++) { + if (boxes[i] === '1') { + res[pos] += Math.abs(pos - i); + } + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: + * $O(1)$ extra space. + * $O(n)$ space for the output list. + +--- + +## 2. Prefix Sum + +::tabs-start + +```python +class Solution: + def minOperations(self, boxes: str) -> List[int]: + n = len(boxes) + res = [0] * n + + prefix_count = [0] * (n + 1) + index_sum = [0] * (n + 1) + for i in range(n): + prefix_count[i + 1] = prefix_count[i] + (boxes[i] == '1') + index_sum[i + 1] = index_sum[i] + (i if boxes[i] == '1' else 0) + + for i in range(n): + left = prefix_count[i] + left_sum = index_sum[i] + + right = prefix_count[n] - prefix_count[i + 1] + right_sum = index_sum[n] - index_sum[i + 1] + + res[i] = (i * left - left_sum) + (right_sum - i * right) + + return res +``` + +```java +public class Solution { + public int[] minOperations(String boxes) { + int n = boxes.length(); + int[] res = new int[n]; + int[] prefixCount = new int[n + 1]; + int[] indexSum = new int[n + 1]; + + for (int i = 0; i < n; i++) { + prefixCount[i + 1] = prefixCount[i] + (boxes.charAt(i) == '1' ? 1 : 0); + indexSum[i + 1] = indexSum[i] + (boxes.charAt(i) == '1' ? i : 0); + } + + for (int i = 0; i < n; i++) { + int left = prefixCount[i]; + int leftSum = indexSum[i]; + + int right = prefixCount[n] - prefixCount[i + 1]; + int rightSum = indexSum[n] - indexSum[i + 1]; + + res[i] = i * left - leftSum + (rightSum - i * right); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector minOperations(string boxes) { + int n = boxes.size(); + vector res(n), prefixCount(n + 1, 0), indexSum(n + 1, 0); + + for (int i = 0; i < n; i++) { + prefixCount[i + 1] = prefixCount[i] + (boxes[i] == '1' ? 1 : 0); + indexSum[i + 1] = indexSum[i] + (boxes[i] == '1' ? i : 0); + } + + for (int i = 0; i < n; i++) { + int left = prefixCount[i]; + int leftSum = indexSum[i]; + int right = prefixCount[n] - prefixCount[i + 1]; + int rightSum = indexSum[n] - indexSum[i + 1]; + res[i] = i * left - leftSum + (rightSum - i * right); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} boxes + * @return {number[]} + */ + minOperations(boxes) { + const n = boxes.length; + const res = new Array(n).fill(0); + const prefixCount = new Array(n + 1).fill(0); + const indexSum = new Array(n + 1).fill(0); + + for (let i = 0; i < n; i++) { + prefixCount[i + 1] = prefixCount[i] + (boxes[i] === '1' ? 1 : 0); + indexSum[i + 1] = indexSum[i] + (boxes[i] === '1' ? i : 0); + } + + for (let i = 0; i < n; i++) { + const left = prefixCount[i]; + const leftSum = indexSum[i]; + const right = prefixCount[n] - prefixCount[i + 1]; + const rightSum = indexSum[n] - indexSum[i + 1]; + + res[i] = i * left - leftSum + (rightSum - i * right); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 3. Prefix Sum (Optimal) + +::tabs-start + +```python +class Solution: + def minOperations(self, boxes: str) -> List[int]: + n = len(boxes) + res = [0] * n + + balls = moves = 0 + for i in range(n): + res[i] = balls + moves + moves += balls + balls += int(boxes[i]) + + balls = moves = 0 + for i in range(n - 1, -1, -1): + res[i] += balls + moves + moves += balls + balls += int(boxes[i]) + + return res +``` + +```java +public class Solution { + public int[] minOperations(String boxes) { + int n = boxes.length(); + int[] res = new int[n]; + + int balls = 0, moves = 0; + for (int i = 0; i < n; i++) { + res[i] = balls + moves; + moves += balls; + balls += boxes.charAt(i) - '0'; + } + + balls = moves = 0; + for (int i = n - 1; i >= 0; i--) { + res[i] += balls + moves; + moves += balls; + balls += boxes.charAt(i) - '0'; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector minOperations(string boxes) { + int n = boxes.size(); + vector res(n, 0); + + int balls = 0, moves = 0; + for (int i = 0; i < n; i++) { + res[i] = balls + moves; + moves += balls; + balls += boxes[i] - '0'; + } + + balls = moves = 0; + for (int i = n - 1; i >= 0; i--) { + res[i] += balls + moves; + moves += balls; + balls += boxes[i] - '0'; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} boxes + * @return {number[]} + */ + minOperations(boxes) { + const n = boxes.length; + const res = new Array(n).fill(0); + + let balls = 0, moves = 0; + for (let i = 0; i < n; i++) { + res[i] = balls + moves; + moves += balls; + balls += Number(boxes[i]); + } + + balls = moves = 0; + for (let i = n - 1; i >= 0; i--) { + res[i] += balls + moves; + moves += balls; + balls += Number(boxes[i]); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: + * $O(1)$ extra space. + * $O(n)$ space for the output list. \ No newline at end of file diff --git a/articles/minimum-remove-to-make-valid-parentheses.md b/articles/minimum-remove-to-make-valid-parentheses.md index 23627cf72..43c6d5981 100644 --- a/articles/minimum-remove-to-make-valid-parentheses.md +++ b/articles/minimum-remove-to-make-valid-parentheses.md @@ -128,6 +128,39 @@ class Solution { } ``` +```csharp +public class Solution { + public string MinRemoveToMakeValid(string s) { + List res = new List(); + int cnt = 0; + + foreach (char c in s) { + if (c == '(') { + res.Add(c); + cnt++; + } else if (c == ')' && cnt > 0) { + res.Add(c); + cnt--; + } else if (c != ')') { + res.Add(c); + } + } + + List filtered = new List(); + for (int i = res.Count - 1; i >= 0; i--) { + if (res[i] == '(' && cnt > 0) { + cnt--; + } else { + filtered.Add(res[i]); + } + } + + filtered.Reverse(); + return new string(filtered.ToArray()); + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -264,6 +297,37 @@ class Solution { } ``` +```csharp +public class Solution { + public string MinRemoveToMakeValid(string s) { + char[] arr = s.ToCharArray(); + int cnt = 0; + + for (int i = 0; i < s.Length; i++) { + if (s[i] == '(') { + cnt++; + } else if (s[i] == ')' && cnt > 0) { + cnt--; + } else if (s[i] == ')') { + arr[i] = '\0'; // mark invalid ')' + } + } + + List res = new List(); + for (int i = arr.Length - 1; i >= 0; i--) { + if (arr[i] == '(' && cnt > 0) { + cnt--; + } else if (arr[i] != '\0') { + res.Add(arr[i]); + } + } + + res.Reverse(); + return new string(res.ToArray()); + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -393,6 +457,40 @@ class Solution { } ``` +```csharp +public class Solution { + public string MinRemoveToMakeValid(string s) { + char[] arr = s.ToCharArray(); + Stack stack = new Stack(); + + for (int i = 0; i < arr.Length; i++) { + if (arr[i] == '(') { + stack.Push(i); + } else if (arr[i] == ')') { + if (stack.Count > 0) { + stack.Pop(); + } else { + arr[i] = '\0'; + } + } + } + + while (stack.Count > 0) { + arr[stack.Pop()] = '\0'; + } + + StringBuilder result = new StringBuilder(); + foreach (char c in arr) { + if (c != '\0') { + result.Append(c); + } + } + + return result.ToString(); + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -512,6 +610,32 @@ class Solution { } ``` +```csharp +public class Solution { + public string MinRemoveToMakeValid(string s) { + int openCnt = 0, closeCnt = 0; + foreach (char c in s) { + if (c == ')') closeCnt++; + } + + StringBuilder res = new StringBuilder(); + foreach (char c in s) { + if (c == '(') { + if (openCnt == closeCnt) continue; + openCnt++; + } else if (c == ')') { + closeCnt--; + if (openCnt == 0) continue; + openCnt--; + } + res.Append(c); + } + + return res.ToString(); + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/number-of-senior-citizens.md b/articles/number-of-senior-citizens.md new file mode 100644 index 000000000..11a6b0d29 --- /dev/null +++ b/articles/number-of-senior-citizens.md @@ -0,0 +1,149 @@ +## 1. String Parsing + +::tabs-start + +```python +class Solution: + def countSeniors(self, details: List[str]) -> int: + res = 0 + for d in details: + if int(d[11:13]) > 60: + res += 1 + return res +``` + +```java +public class Solution { + public int countSeniors(String[] details) { + int res = 0; + for (String d : details) { + if (Integer.parseInt(d.substring(11, 13)) > 60) { + res++; + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int countSeniors(vector& details) { + int res = 0; + for (const string& d : details) { + if (stoi(d.substr(11, 2)) > 60) { + res++; + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} details + * @return {number} + */ + countSeniors(details) { + let res = 0; + for (let d of details) { + if (parseInt(d.slice(11, 13)) > 60) { + res++; + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ + +--- + +## 2. Character-Based Extraction + +::tabs-start + +```python +class Solution: + def countSeniors(self, details: List[str]) -> int: + res = 0 + for d in details: + ten = ord(d[11]) - ord("0") + one = ord(d[12]) - ord("0") + age = one + 10 * ten + if age > 60: + res += 1 + return res +``` + +```java +public class Solution { + public int countSeniors(String[] details) { + int res = 0; + for (String d : details) { + int ten = d.charAt(11) - '0'; + int one = d.charAt(12) - '0'; + int age = one + 10 * ten; + if (age > 60) { + res++; + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int countSeniors(vector& details) { + int res = 0; + for (const string& d : details) { + int ten = d[11] - '0'; + int one = d[12] - '0'; + int age = one + 10 * ten; + if (age > 60) { + res++; + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} details + * @return {number} + */ + countSeniors(details) { + let res = 0; + for (let d of details) { + let ten = d.charCodeAt(11) - 48; + let one = d.charCodeAt(12) - 48; + let age = one + 10 * ten; + if (age > 60) { + res++; + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ \ No newline at end of file diff --git a/articles/number-of-sub-arrays-with-odd-sum.md b/articles/number-of-sub-arrays-with-odd-sum.md new file mode 100644 index 000000000..e13063014 --- /dev/null +++ b/articles/number-of-sub-arrays-with-odd-sum.md @@ -0,0 +1,521 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def numOfSubarrays(self, arr: List[int]) -> int: + n, res = len(arr), 0 + mod = int(1e9 + 7) + + for i in range(n): + curSum = 0 + for j in range(i, n): + curSum += arr[j] + if curSum % 2: + res = (res + 1) % mod + + return res +``` + +```java +public class Solution { + public int numOfSubarrays(int[] arr) { + int n = arr.length, res = 0; + int mod = (int)1e9 + 7; + + for (int i = 0; i < n; i++) { + int curSum = 0; + for (int j = i; j < n; j++) { + curSum += arr[j]; + if (curSum % 2 != 0) { + res = (res + 1) % mod; + } + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int numOfSubarrays(vector& arr) { + int n = arr.size(), res = 0; + int mod = 1e9 + 7; + + for (int i = 0; i < n; i++) { + int curSum = 0; + for (int j = i; j < n; j++) { + curSum += arr[j]; + if (curSum % 2 != 0) { + res = (res + 1) % mod; + } + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr + * @return {number} + */ + numOfSubarrays(arr) { + const n = arr.length; + let res = 0; + const mod = 1e9 + 7; + + for (let i = 0; i < n; i++) { + let curSum = 0; + for (let j = i; j < n; j++) { + curSum += arr[j]; + if (curSum % 2 !== 0) { + res = (res + 1) % mod; + } + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(1)$ + +--- + +## 2. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def numOfSubarrays(self, arr: List[int]) -> int: + mod = 10**9 + 7 + n = len(arr) + memo = {} + + def dp(i: int, parity: int) -> int: + if i == n: + return 0 + + if (i, parity) in memo: + return memo[(i, parity)] + + new_parity = (parity + arr[i]) % 2 + res = new_parity + dp(i + 1, new_parity) + memo[(i, parity)] = res % mod + return memo[(i, parity)] + + ans = 0 + for i in range(n): + ans = (ans + dp(i, 0)) % mod + + return ans +``` + +```java +public class Solution { + int[][] memo; + int[] arr; + int mod = (int)1e9 + 7; + + public int numOfSubarrays(int[] arr) { + int n = arr.length; + this.arr = arr; + memo = new int[n][2]; + for (int i = 0; i < n; i++) { + memo[i][0] = -1; + memo[i][1] = -1; + } + + int res = 0; + for (int i = 0; i < n; i++) { + res = (res + dp(i, 0)) % mod; + } + return res; + } + + private int dp(int i, int parity) { + if (i == arr.length) return 0; + if (memo[i][parity] != -1) return memo[i][parity]; + + int newParity = (parity + arr[i]) % 2; + int res = newParity + dp(i + 1, newParity); + return memo[i][parity] = res % mod; + } +} +``` + +```cpp +class Solution { +public: + int mod = 1e9 + 7; + vector> memo; + vector arr; + + int numOfSubarrays(vector& arr) { + this->arr = arr; + int n = arr.size(); + memo.assign(n, vector(2, -1)); + + int res = 0; + for (int i = 0; i < n; i++) { + res = (res + dp(i, 0)) % mod; + } + return res; + } + + int dp(int i, int parity) { + if (i == arr.size()) return 0; + if (memo[i][parity] != -1) return memo[i][parity]; + + int newParity = (parity + arr[i]) % 2; + int res = newParity + dp(i + 1, newParity); + return memo[i][parity] = res % mod; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr + * @return {number} + */ + numOfSubarrays(arr) { + const mod = 1e9 + 7; + const n = arr.length; + const memo = Array.from({ length: n }, () => Array(2).fill(-1)); + + const dp = (i, parity) => { + if (i === n) return 0; + if (memo[i][parity] !== -1) return memo[i][parity]; + + const newParity = (parity + arr[i]) % 2; + const res = newParity + dp(i + 1, newParity); + return memo[i][parity] = res % mod; + }; + + let res = 0; + for (let i = 0; i < n; i++) { + res = (res + dp(i, 0)) % mod; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 3. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def numOfSubarrays(self, arr: List[int]) -> int: + n = len(arr) + mod = 10**9 + 7 + dp = [[0] * 2 for _ in range(n + 1)] + + for i in range(n - 1, -1, -1): + for parity in range(2): + new_parity = (parity + arr[i]) % 2 + dp[i][parity] = (new_parity + dp[i + 1][new_parity]) % mod + + res = 0 + for i in range(n): + res = (res + dp[i][0]) % mod + return res +``` + +```java +public class Solution { + public int numOfSubarrays(int[] arr) { + int n = arr.length; + int mod = (int)1e9 + 7; + int[][] dp = new int[n + 1][2]; + + for (int i = n - 1; i >= 0; i--) { + for (int parity = 0; parity <= 1; parity++) { + int newParity = (parity + arr[i]) % 2; + dp[i][parity] = (newParity + dp[i + 1][newParity]) % mod; + } + } + + int res = 0; + for (int i = 0; i < n; i++) { + res = (res + dp[i][0]) % mod; + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int numOfSubarrays(vector& arr) { + int n = arr.size(), mod = 1e9 + 7; + vector> dp(n + 1, vector(2, 0)); + + for (int i = n - 1; i >= 0; i--) { + for (int parity = 0; parity <= 1; parity++) { + int newParity = (parity + arr[i]) % 2; + dp[i][parity] = (newParity + dp[i + 1][newParity]) % mod; + } + } + + int res = 0; + for (int i = 0; i < n; i++) { + res = (res + dp[i][0]) % mod; + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr + * @return {number} + */ + numOfSubarrays(arr) { + const n = arr.length; + const mod = 1e9 + 7; + const dp = Array.from({ length: n + 1 }, () => [0, 0]); + + for (let i = n - 1; i >= 0; i--) { + for (let parity = 0; parity <= 1; parity++) { + const newParity = (parity + arr[i]) % 2; + dp[i][parity] = (newParity + dp[i + 1][newParity]) % mod; + } + } + + let res = 0; + for (let i = 0; i < n; i++) { + res = (res + dp[i][0]) % mod; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 4. Prefix Sum - I + +::tabs-start + +```python +class Solution: + def numOfSubarrays(self, arr: List[int]) -> int: + cur_sum = odd_cnt = even_cnt = res = 0 + MOD = 10**9 + 7 + + for n in arr: + cur_sum += n + if cur_sum % 2: + res = (res + 1 + even_cnt) % MOD + odd_cnt += 1 + else: + res = (res + odd_cnt) % MOD + even_cnt += 1 + + return res +``` + +```java +public class Solution { + public int numOfSubarrays(int[] arr) { + int curSum = 0, oddCnt = 0, evenCnt = 0, res = 0; + int MOD = (int)1e9 + 7; + + for (int n : arr) { + curSum += n; + if (curSum % 2 != 0) { + res = (res + 1 + evenCnt) % MOD; + oddCnt++; + } else { + res = (res + oddCnt) % MOD; + evenCnt++; + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int numOfSubarrays(vector& arr) { + long long curSum = 0, oddCnt = 0, evenCnt = 0, res = 0; + const int MOD = 1e9 + 7; + + for (int n : arr) { + curSum += n; + if (curSum % 2 != 0) { + res = (res + 1 + evenCnt) % MOD; + oddCnt++; + } else { + res = (res + oddCnt) % MOD; + evenCnt++; + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr + * @return {number} + */ + numOfSubarrays(arr) { + let curSum = 0, oddCnt = 0, evenCnt = 0, res = 0; + const MOD = 1e9 + 7; + + for (let n of arr) { + curSum += n; + if (curSum % 2 !== 0) { + res = (res + 1 + evenCnt) % MOD; + oddCnt++; + } else { + res = (res + oddCnt) % MOD; + evenCnt++; + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ + +--- + +## 5. Prefix Sum - II + +::tabs-start + +```python +class Solution: + def numOfSubarrays(self, arr: List[int]) -> int: + count = [1, 0] + prefix = res = 0 + MOD = 10**9 + 7 + + for num in arr: + prefix = (prefix + num) % 2 + res = (res + count[1 - prefix]) % MOD + count[prefix] += 1 + + return res +``` + +```java +public class Solution { + public int numOfSubarrays(int[] arr) { + int[] count = {1, 0}; + int prefix = 0, res = 0; + int MOD = (int)1e9 + 7; + + for (int num : arr) { + prefix = (prefix + num) % 2; + res = (res + count[1 - prefix]) % MOD; + count[prefix]++; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int numOfSubarrays(vector& arr) { + int count[2] = {1, 0}; + int prefix = 0, res = 0; + const int MOD = 1e9 + 7; + + for (int num : arr) { + prefix = (prefix + num) % 2; + res = (res + count[1 - prefix]) % MOD; + count[prefix]++; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr + * @return {number} + */ + numOfSubarrays(arr) { + const count = [1, 0]; + let prefix = 0, res = 0; + const MOD = 1e9 + 7; + + for (const num of arr) { + prefix = (prefix + num) % 2; + res = (res + count[1 - prefix]) % MOD; + count[prefix]++; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ \ No newline at end of file diff --git a/articles/number-of-ways-to-split-array.md b/articles/number-of-ways-to-split-array.md new file mode 100644 index 000000000..ca66c41c0 --- /dev/null +++ b/articles/number-of-ways-to-split-array.md @@ -0,0 +1,320 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def waysToSplitArray(self, nums: List[int]) -> int: + n = len(nums) + res = 0 + + for i in range(n - 1): + leftSum = 0 + for j in range(i + 1): + leftSum += nums[j] + + rightSum = 0 + for j in range(i + 1, n): + rightSum += nums[j] + + res += (1 if leftSum >= rightSum else 0) + + return res +``` + +```java +public class Solution { + public int waysToSplitArray(int[] nums) { + int n = nums.length; + int res = 0; + + for (int i = 0; i < n - 1; i++) { + long leftSum = 0; + for (int j = 0; j <= i; j++) { + leftSum += nums[j]; + } + + long rightSum = 0; + for (int j = i + 1; j < n; j++) { + rightSum += nums[j]; + } + + if (leftSum >= rightSum) { + res++; + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int waysToSplitArray(vector& nums) { + int n = nums.size(); + int res = 0; + + for (int i = 0; i < n - 1; i++) { + long long leftSum = 0; + for (int j = 0; j <= i; j++) { + leftSum += nums[j]; + } + + long long rightSum = 0; + for (int j = i + 1; j < n; j++) { + rightSum += nums[j]; + } + + if (leftSum >= rightSum) { + res++; + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + waysToSplitArray(nums) { + let n = nums.length; + let res = 0; + + for (let i = 0; i < n - 1; i++) { + let leftSum = 0; + for (let j = 0; j <= i; j++) { + leftSum += nums[j]; + } + + let rightSum = 0; + for (let j = i + 1; j < n; j++) { + rightSum += nums[j]; + } + + if (leftSum >= rightSum) { + res++; + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(1)$ + +--- + +## 2. Prefix Sum + +::tabs-start + +```python +class Solution: + def waysToSplitArray(self, nums: List[int]) -> int: + n = len(nums) + prefix = [0] * (n + 1) + + for i in range(n): + prefix[i + 1] = prefix[i] + nums[i] + + res = 0 + for i in range(1, n): + left = prefix[i] + right = prefix[n] - prefix[i] + if left >= right: + res += 1 + + return res +``` + +```java +public class Solution { + public int waysToSplitArray(int[] nums) { + int n = nums.length; + long[] prefix = new long[n + 1]; + + for (int i = 0; i < n; i++) { + prefix[i + 1] = prefix[i] + nums[i]; + } + + int res = 0; + for (int i = 1; i < n; i++) { + long left = prefix[i]; + long right = prefix[n] - prefix[i]; + if (left >= right) { + res++; + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int waysToSplitArray(vector& nums) { + int n = nums.size(); + vector prefix(n + 1, 0); + + for (int i = 0; i < n; i++) { + prefix[i + 1] = prefix[i] + nums[i]; + } + + int res = 0; + for (int i = 1; i < n; i++) { + long long left = prefix[i]; + long long right = prefix[n] - prefix[i]; + if (left >= right) { + res++; + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + waysToSplitArray(nums) { + const n = nums.length; + const prefix = Array(n + 1).fill(0); + + for (let i = 0; i < n; i++) { + prefix[i + 1] = prefix[i] + nums[i]; + } + + let res = 0; + for (let i = 1; i < n; i++) { + const left = prefix[i]; + const right = prefix[n] - prefix[i]; + if (left >= right) { + res++; + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 3. Prefix Sum (Optimal) + +::tabs-start + +```python +class Solution: + def waysToSplitArray(self, nums: List[int]) -> int: + right = sum(nums) + left = res = 0 + + for i in range(len(nums) - 1): + left += nums[i] + right -= nums[i] + res += 1 if left >= right else 0 + + return res +``` + +```java +public class Solution { + public int waysToSplitArray(int[] nums) { + long right = 0, left = 0; + for (int num : nums) { + right += num; + } + + int res = 0; + for (int i = 0; i < nums.length - 1; i++) { + left += nums[i]; + right -= nums[i]; + if (left >= right) { + res++; + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int waysToSplitArray(vector& nums) { + long long right = 0, left = 0; + for (int num : nums) { + right += num; + } + + int res = 0; + for (int i = 0; i < nums.size() - 1; i++) { + left += nums[i]; + right -= nums[i]; + if (left >= right) { + res++; + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + waysToSplitArray(nums) { + let right = nums.reduce((a, b) => a + b, 0); + let left = 0, res = 0; + + for (let i = 0; i < nums.length - 1; i++) { + left += nums[i]; + right -= nums[i]; + if (left >= right) { + res++; + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ \ No newline at end of file diff --git a/articles/relative-sort-array.md b/articles/relative-sort-array.md new file mode 100644 index 000000000..8681e3fba --- /dev/null +++ b/articles/relative-sort-array.md @@ -0,0 +1,551 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def relativeSortArray(self, arr1: List[int], arr2: List[int]) -> List[int]: + res = [] + + for num2 in arr2: + for i, num1 in enumerate(arr1): + if num1 == num2: + res.append(num1) + arr1[i] = -1 + + arr1.sort() + for i in range(len(res), len(arr1)): + res.append(arr1[i]) + + return res +``` + +```java +public class Solution { + public int[] relativeSortArray(int[] arr1, int[] arr2) { + List res = new ArrayList<>(); + + for (int num2 : arr2) { + for (int i = 0; i < arr1.length; i++) { + if (arr1[i] == num2) { + res.add(arr1[i]); + arr1[i] = -1; + } + } + } + + Arrays.sort(arr1); + for (int i = res.size(); i < arr1.length; i++) { + res.add(arr1[i]); + } + + return res.stream().mapToInt(i -> i).toArray(); + } +} +``` + +```cpp +class Solution { +public: + vector relativeSortArray(vector& arr1, vector& arr2) { + vector res; + + for (int num2 : arr2) { + for (int i = 0; i < arr1.size(); i++) { + if (arr1[i] == num2) { + res.push_back(arr1[i]); + arr1[i] = -1; + } + } + } + + sort(arr1.begin(), arr1.end()); + for (int i = res.size(); i < arr1.size(); i++) { + res.push_back(arr1[i]); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr1 + * @param {number[]} arr2 + * @return {number[]} + */ + relativeSortArray(arr1, arr2) { + const res = []; + + for (let num2 of arr2) { + for (let i = 0; i < arr1.length; i++) { + if (arr1[i] === num2) { + res.push(arr1[i]); + arr1[i] = -1; + } + } + } + + arr1.sort((a, b) => a - b); + for (let i = res.length; i < arr1.length; i++) { + res.push(arr1[i]); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * n + n \log n)$ +* Space complexity: + * $O(1)$ or $O(n)$ depending on the sorting algorithm. + * $O(n)$ space for the output list. + +> Where $n$ is the size of the array $arr1$, and $m$ is the size of the array $arr2$. + +--- + +## 2. Hash Map + +::tabs-start + +```python +class Solution: + def relativeSortArray(self, arr1: List[int], arr2: List[int]) -> List[int]: + arr2_set = set(arr2) + arr1_count = defaultdict(int) + end = [] + + for num in arr1: + if num not in arr2_set: + end.append(num) + arr1_count[num] += 1 + end.sort() + + res = [] + for num in arr2: + for _ in range(arr1_count[num]): + res.append(num) + return res + end +``` + +```java +public class Solution { + public int[] relativeSortArray(int[] arr1, int[] arr2) { + Set arr2Set = new HashSet<>(); + for (int num : arr2) arr2Set.add(num); + + Map count = new HashMap<>(); + List end = new ArrayList<>(); + for (int num : arr1) { + if (!arr2Set.contains(num)) end.add(num); + count.put(num, count.getOrDefault(num, 0) + 1); + } + Collections.sort(end); + + List res = new ArrayList<>(); + for (int num : arr2) { + int freq = count.get(num); + for (int i = 0; i < freq; i++) res.add(num); + } + res.addAll(end); + + return res.stream().mapToInt(i -> i).toArray(); + } +} +``` + +```cpp +class Solution { +public: + vector relativeSortArray(vector& arr1, vector& arr2) { + unordered_set arr2Set(arr2.begin(), arr2.end()); + unordered_map count; + vector end; + + for (int num : arr1) { + if (!arr2Set.count(num)) end.push_back(num); + count[num]++; + } + + sort(end.begin(), end.end()); + vector res; + + for (int num : arr2) { + for (int i = 0; i < count[num]; i++) { + res.push_back(num); + } + } + + res.insert(res.end(), end.begin(), end.end()); + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr1 + * @param {number[]} arr2 + * @return {number[]} + */ + relativeSortArray(arr1, arr2) { + const arr2Set = new Set(arr2); + const count = {}; + const end = []; + + for (let num of arr1) { + if (!arr2Set.has(num)) end.push(num); + count[num] = (count[num] || 0) + 1; + } + + end.sort((a, b) => a - b); + const res = []; + + for (let num of arr2) { + for (let i = 0; i < count[num]; i++) { + res.push(num); + } + } + + return res.concat(end); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n + m + n \log n)$ +* Space complexity: $O(n)$ + +> Where $n$ is the size of the array $arr1$, and $m$ is the size of the array $arr2$. + +--- + +## 3. Hash Map (Optimal) + +::tabs-start + +```python +class Solution: + def relativeSortArray(self, arr1: List[int], arr2: List[int]) -> List[int]: + count = {} + for num in arr1: + count[num] = count.get(num, 0) + 1 + + res = [] + for num in arr2: + res += [num] * count.pop(num) + + for num in sorted(count): + res += [num] * count[num] + + return res +``` + +```java +public class Solution { + public int[] relativeSortArray(int[] arr1, int[] arr2) { + Map count = new HashMap<>(); + for (int num : arr1) { + count.put(num, count.getOrDefault(num, 0) + 1); + } + + List res = new ArrayList<>(); + for (int num : arr2) { + int freq = count.remove(num); + for (int i = 0; i < freq; i++) { + res.add(num); + } + } + + List remaining = new ArrayList<>(count.keySet()); + Collections.sort(remaining); + for (int num : remaining) { + int freq = count.get(num); + for (int i = 0; i < freq; i++) { + res.add(num); + } + } + + return res.stream().mapToInt(i -> i).toArray(); + } +} +``` + +```cpp +class Solution { +public: + vector relativeSortArray(vector& arr1, vector& arr2) { + unordered_map count; + for (int num : arr1) { + count[num]++; + } + + vector res; + for (int num : arr2) { + for (int i = 0; i < count[num]; i++) { + res.push_back(num); + } + count.erase(num); + } + + vector remaining; + for (auto& [num, freq] : count) { + for (int i = 0; i < freq; i++) { + remaining.push_back(num); + } + } + + sort(remaining.begin(), remaining.end()); + res.insert(res.end(), remaining.begin(), remaining.end()); + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr1 + * @param {number[]} arr2 + * @return {number[]} + */ + relativeSortArray(arr1, arr2) { + const count = {}; + for (let num of arr1) { + count[num] = (count[num] || 0) + 1; + } + + const res = []; + for (let num of arr2) { + for (let i = 0; i < count[num]; i++) { + res.push(num); + } + delete count[num]; + } + + const remaining = Object.keys(count).map(Number).sort((a, b) => a - b); + for (let num of remaining) { + for (let i = 0; i < count[num]; i++) { + res.push(num); + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n + m + n \log n)$ +* Space complexity: $O(n)$ + +> Where $n$ is the size of the array $arr1$, and $m$ is the size of the array $arr2$. + +--- + +## 4. Counting Sort + +::tabs-start + +```python +class Solution: + def relativeSortArray(self, arr1: List[int], arr2: List[int]) -> List[int]: + max_val = max(arr1) + count = [0] * (max_val + 1) + + for num in arr1: + count[num] += 1 + + res = [] + for num in arr2: + res += [num] * count[num] + count[num] = 0 + + for num in range(len(count)): + res += [num] * count[num] + + return res +``` + +```java +public class Solution { + public int[] relativeSortArray(int[] arr1, int[] arr2) { + int max = 0; + for (int num : arr1) max = Math.max(max, num); + + int[] count = new int[max + 1]; + for (int num : arr1) count[num]++; + + List res = new ArrayList<>(); + for (int num : arr2) { + while (count[num]-- > 0) res.add(num); + } + + for (int num = 0; num < count.length; num++) { + while (count[num]-- > 0) res.add(num); + } + + return res.stream().mapToInt(i -> i).toArray(); + } +} +``` + +```cpp +class Solution { +public: + vector relativeSortArray(vector& arr1, vector& arr2) { + int max_val = *max_element(arr1.begin(), arr1.end()); + vector count(max_val + 1, 0); + + for (int num : arr1) count[num]++; + + vector res; + for (int num : arr2) { + while (count[num]-- > 0) res.push_back(num); + } + + for (int num = 0; num <= max_val; num++) { + while (count[num]-- > 0) res.push_back(num); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr1 + * @param {number[]} arr2 + * @return {number[]} + */ + relativeSortArray(arr1, arr2) { + let max = Math.max(...arr1); + let count = new Array(max + 1).fill(0); + + for (let num of arr1) count[num]++; + + let res = []; + for (let num of arr2) { + while (count[num]-- > 0) res.push(num); + } + + for (let num = 0; num < count.length; num++) { + while (count[num]-- > 0) res.push(num); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n + m + M)$ +* Space complexity: + * $O(M)$ extra space. + * $O(n)$ space for the output list. + +> Where $n$ is the size of the array $arr1$, $m$ is the size of the array $arr2$, and $M$ is the maximum value in the array $arr1$. + +--- + +## 5. Custom Sort + +::tabs-start + +```python +class Solution: + def relativeSortArray(self, arr1: List[int], arr2: List[int]) -> List[int]: + index = {num: i for i, num in enumerate(arr2)} + return sorted(arr1, key=lambda x: (index.get(x, 1000 + x))) +``` + +```java +public class Solution { + public int[] relativeSortArray(int[] arr1, int[] arr2) { + Map index = new HashMap<>(); + for (int i = 0; i < arr2.length; i++) { + index.put(arr2[i], i); + } + + Integer[] boxed = Arrays.stream(arr1).boxed().toArray(Integer[]::new); + Arrays.sort(boxed, (a, b) -> { + int ia = index.getOrDefault(a, 1000 + a); + int ib = index.getOrDefault(b, 1000 + b); + return Integer.compare(ia, ib); + }); + + return Arrays.stream(boxed).mapToInt(i -> i).toArray(); + } +} +``` + +```cpp +class Solution { +public: + vector relativeSortArray(vector& arr1, vector& arr2) { + unordered_map index; + for (int i = 0; i < arr2.size(); i++) { + index[arr2[i]] = i; + } + + sort(arr1.begin(), arr1.end(), [&](int a, int b) { + int ia = index.count(a) ? index[a] : 1000 + a; + int ib = index.count(b) ? index[b] : 1000 + b; + return ia < ib; + }); + + return arr1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr1 + * @param {number[]} arr2 + * @return {number[]} + */ + relativeSortArray(arr1, arr2) { + const index = new Map(); + arr2.forEach((num, i) => index.set(num, i)); + + return arr1.sort((a, b) => { + const ia = index.has(a) ? index.get(a) : 1000 + a; + const ib = index.has(b) ? index.get(b) : 1000 + b; + return ia - ib; + }); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n + m + n \log n)$ +* Space complexity: + * $O(m)$ extra space. + * $O(n)$ space for the output list. + +> Where $n$ is the size of the array $arr1$, and $m$ is the size of the array $arr2$. \ No newline at end of file diff --git a/articles/remove-duplicates-from-sorted-list.md b/articles/remove-duplicates-from-sorted-list.md index b50bbbdcb..9184c3e9c 100644 --- a/articles/remove-duplicates-from-sorted-list.md +++ b/articles/remove-duplicates-from-sorted-list.md @@ -88,7 +88,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(2 ^ n)$ +* Time complexity: $O(n)$ * Space complexity: $O(n)$ for recursion stack. --- diff --git a/articles/score-of-a-string.md b/articles/score-of-a-string.md new file mode 100644 index 000000000..9a5bf9bdf --- /dev/null +++ b/articles/score-of-a-string.md @@ -0,0 +1,60 @@ +## 1. Iteration + +::tabs-start + +```python +class Solution: + def scoreOfString(self, s: str) -> int: + res = 0 + for i in range(len(s) - 1): + res += abs(ord(s[i]) - ord(s[i + 1])) + return res +``` + +```java +public class Solution { + public int scoreOfString(String s) { + int res = 0; + for (int i = 0; i < s.length() - 1; i++) { + res += Math.abs(s.charAt(i) - s.charAt(i + 1)); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int scoreOfString(string s) { + int res = 0; + for (int i = 0; i < s.length() - 1; i++) { + res += abs(s[i] - s[i + 1]); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {number} + */ + scoreOfString(s) { + let res = 0; + for (let i = 0; i < s.length - 1; i++) { + res += Math.abs(s.charCodeAt(i) - s.charCodeAt(i + 1)); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ \ No newline at end of file diff --git a/articles/shifting-letters-ii.md b/articles/shifting-letters-ii.md new file mode 100644 index 000000000..12d3e9499 --- /dev/null +++ b/articles/shifting-letters-ii.md @@ -0,0 +1,481 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def shiftingLetters(self, s: str, shifts: List[List[int]]) -> str: + s = [ord(c) - ord('a') for c in s] + + for l, r, d in shifts: + for i in range(l, r + 1): + s[i] += 1 if d else -1 + s[i] %= 26 + + s = [chr(ord('a') + c) for c in s] + return "".join(s) +``` + +```java +class Solution { + public String shiftingLetters(String s, int[][] shifts) { + char[] arr = s.toCharArray(); + int[] letters = new int[arr.length]; + + for (int i = 0; i < arr.length; i++) { + letters[i] = arr[i] - 'a'; + } + + for (int[] shift : shifts) { + int l = shift[0], r = shift[1], d = shift[2]; + for (int i = l; i <= r; i++) { + letters[i] = (letters[i] + (d == 1 ? 1 : -1) + 26) % 26; + } + } + + for (int i = 0; i < arr.length; i++) { + arr[i] = (char) (letters[i] + 'a'); + } + + return new String(arr); + } +} +``` + +```cpp +class Solution { +public: + string shiftingLetters(string s, vector>& shifts) { + vector letters(s.size()); + for (int i = 0; i < s.size(); i++) { + letters[i] = s[i] - 'a'; + } + + for (const auto& shift : shifts) { + int l = shift[0], r = shift[1], d = shift[2]; + for (int i = l; i <= r; i++) { + letters[i] = (letters[i] + (d == 1 ? 1 : -1) + 26) % 26; + } + } + + for (int i = 0; i < s.size(); i++) { + s[i] = letters[i] + 'a'; + } + + return s; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @param {number[][]} shifts + * @return {string} + */ + shiftingLetters(s, shifts) { + let arr = Array.from(s).map(c => c.charCodeAt(0) - 97); + + for (const [l, r, d] of shifts) { + for (let i = l; i <= r; i++) { + arr[i] = (arr[i] + (d === 1 ? 1 : -1) + 26) % 26; + } + } + + return arr.map(c => String.fromCharCode(c + 97)).join(''); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * m)$ +* Space complexity: $O(n)$ + +> Where $n$ is the length of the string $s$ and $m$ is the size of the array $shifts$. + +--- + +## 2. Sweep Line Algorithm + +::tabs-start + +```python +class Solution: + def shiftingLetters(self, s: str, shifts: List[List[int]]) -> str: + prefix_diff = [0] * (len(s) + 1) + + for left, right, d in shifts: + val = 1 if d == 1 else -1 + prefix_diff[left] += val + prefix_diff[right + 1] -= val + + diff = 0 + res = [ord(c) - ord("a") for c in s] + + for i in range(len(s)): + diff += prefix_diff[i] + res[i] = (diff + res[i] + 26) % 26 + + s = [chr(ord("a") + n) for n in res] + return "".join(s) +``` + +```java +class Solution { + public String shiftingLetters(String s, int[][] shifts) { + int n = s.length(); + int[] prefix_diff = new int[n + 1]; + + for (int[] shift : shifts) { + int left = shift[0], right = shift[1], d = shift[2]; + int val = d == 1 ? 1 : -1; + prefix_diff[left] += val; + prefix_diff[right + 1] -= val; + } + + int[] res = new int[n]; + for (int i = 0; i < n; i++) { + res[i] = s.charAt(i) - 'a'; + } + + int diff = 0; + for (int i = 0; i < n; i++) { + diff += prefix_diff[i]; + res[i] = (res[i] + diff % 26 + 26) % 26; + } + + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < n; i++) { + sb.append((char) ('a' + res[i])); + } + + return sb.toString(); + } +} +``` + +```cpp +class Solution { +public: + string shiftingLetters(string s, vector>& shifts) { + int n = s.size(); + vector prefix_diff(n + 1, 0); + + for (auto& shift : shifts) { + int left = shift[0], right = shift[1], d = shift[2]; + int val = d == 1 ? 1 : -1; + prefix_diff[left] += val; + prefix_diff[right + 1] -= val; + } + + int diff = 0; + vector res(n); + for (int i = 0; i < n; ++i) { + res[i] = s[i] - 'a'; + } + + for (int i = 0; i < n; ++i) { + diff += prefix_diff[i]; + res[i] = (diff % 26 + res[i] + 26) % 26; + } + + for (int i = 0; i < n; ++i) { + s[i] = 'a' + res[i]; + } + + return s; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @param {number[][]} shifts + * @return {string} + */ + shiftingLetters(s, shifts) { + const n = s.length; + const prefix_diff = Array(n + 1).fill(0); + + for (const [left, right, d] of shifts) { + const val = d === 1 ? 1 : -1; + prefix_diff[left] += val; + prefix_diff[right + 1] -= val; + } + + let diff = 0; + const res = Array.from(s).map(c => c.charCodeAt(0) - 'a'.charCodeAt(0)); + + for (let i = 0; i < n; i++) { + diff += prefix_diff[i]; + res[i] = (diff % 26 + res[i] + 26) % 26; + } + + return res.map(x => String.fromCharCode('a'.charCodeAt(0) + x)).join(''); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n + m)$ +* Space complexity: $O(n)$ + +> Where $n$ is the length of the string $s$ and $m$ is the size of the array $shifts$. + +--- + +## 3. Binary Indexed Tree (Fenwick Tree) + +::tabs-start + +```python +class BIT: + def __init__(self, size): + self.n = size + 2 + self.tree = [0] * self.n + + def update(self, index, delta): + index += 1 + while index < self.n: + self.tree[index] += delta + index += index & -index + + def prefix_sum(self, index): + index += 1 + total = 0 + while index > 0: + total += self.tree[index] + index -= index & -index + return total + + def range_update(self, left, right, delta): + self.update(left, delta) + self.update(right + 1, -delta) + + +class Solution: + def shiftingLetters(self, s: str, shifts: List[List[int]]) -> str: + n = len(s) + bit = BIT(n) + + for left, right, d in shifts: + delta = 1 if d == 1 else -1 + bit.range_update(left, right, delta) + + res = [] + for i in range(n): + shift = bit.prefix_sum(i) % 26 + code = (ord(s[i]) - ord('a') + shift + 26) % 26 + res.append(chr(ord('a') + code)) + + return ''.join(res) +``` + +```java +class BIT { + int[] tree; + int n; + + public BIT(int size) { + n = size + 2; + tree = new int[n]; + } + + public void update(int index, int delta) { + index++; + while (index < n) { + tree[index] += delta; + index += index & -index; + } + } + + public int prefixSum(int index) { + index++; + int sum = 0; + while (index > 0) { + sum += tree[index]; + index -= index & -index; + } + return sum; + } + + public void rangeUpdate(int left, int right, int delta) { + update(left, delta); + update(right + 1, -delta); + } +} + +public class Solution { + public String shiftingLetters(String s, int[][] shifts) { + int n = s.length(); + BIT bit = new BIT(n); + + for (int[] shift : shifts) { + int left = shift[0], right = shift[1], d = shift[2]; + int delta = d == 1 ? 1 : -1; + bit.rangeUpdate(left, right, delta); + } + + StringBuilder res = new StringBuilder(); + for (int i = 0; i < n; i++) { + int shift = bit.prefixSum(i) % 26; + int code = (s.charAt(i) - 'a' + shift + 26) % 26; + res.append((char) ('a' + code)); + } + + return res.toString(); + } +} +``` + +```cpp +class BIT { + vector tree; + int n; +public: + BIT(int size) { + n = size + 2; + tree.assign(n, 0); + } + + void update(int index, int delta) { + index++; + while (index < n) { + tree[index] += delta; + index += index & -index; + } + } + + int prefixSum(int index) { + index++; + int sum = 0; + while (index > 0) { + sum += tree[index]; + index -= index & -index; + } + return sum; + } + + void rangeUpdate(int left, int right, int delta) { + update(left, delta); + update(right + 1, -delta); + } +}; + +class Solution { +public: + string shiftingLetters(string s, vector>& shifts) { + int n = s.size(); + BIT bit(n); + + for (auto& shift : shifts) { + int left = shift[0], right = shift[1], d = shift[2]; + int delta = d == 1 ? 1 : -1; + bit.rangeUpdate(left, right, delta); + } + + string res; + for (int i = 0; i < n; i++) { + int shift = bit.prefixSum(i) % 26; + int code = (s[i] - 'a' + shift + 26) % 26; + res += char('a' + code); + } + + return res; + } +}; +``` + +```javascript +class BIT { + /** + * @constructor + * @param {number} size + */ + constructor(size) { + this.n = size + 2; + this.tree = new Array(this.n).fill(0); + } + + /** + * @param {number} index + * @param {number} delta + * @return {void} + */ + update(index, delta) { + index++; + while (index < this.n) { + this.tree[index] += delta; + index += index & -index; + } + } + + /** + * @param {number} index + * @return {number} + */ + prefixSum(index) { + index++; + let sum = 0; + while (index > 0) { + sum += this.tree[index]; + index -= index & -index; + } + return sum; + } + + /** + * @param {number} left + * @param {number} right + * @param {number} delta + * @return {void} + */ + rangeUpdate(left, right, delta) { + this.update(left, delta); + this.update(right + 1, -delta); + } +} + +class Solution { + /** + * @param {string} s + * @param {number[][]} shifts + * @return {string} + */ + shiftingLetters(s, shifts) { + const n = s.length; + const bit = new BIT(n); + for (const [left, right, d] of shifts) { + const delta = d === 1 ? 1 : -1; + bit.rangeUpdate(left, right, delta); + } + + let res = ""; + for (let i = 0; i < n; i++) { + const shift = bit.prefixSum(i) % 26; + const code = (s.charCodeAt(i) - 97 + shift + 26) % 26; + res += String.fromCharCode(97 + code); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O((m + n) * \log n)$ +* Space complexity: $O(n)$ + +> Where $n$ is the length of the string $s$ and $m$ is the size of the array $shifts$. \ No newline at end of file diff --git a/articles/sort-array-by-increasing-frequency.md b/articles/sort-array-by-increasing-frequency.md new file mode 100644 index 000000000..04a4e1c80 --- /dev/null +++ b/articles/sort-array-by-increasing-frequency.md @@ -0,0 +1,79 @@ +## 1. Custom Sort + +::tabs-start + +```python +class Solution: + def frequencySort(self, nums: List[int]) -> List[int]: + count = Counter(nums) + nums.sort(key=lambda n: (count[n], -n)) + return nums +``` + +```java +public class Solution { + public int[] frequencySort(int[] nums) { + Map count = new HashMap<>(); + for (int num : nums) { + count.put(num, count.getOrDefault(num, 0) + 1); + } + + Integer[] arr = Arrays.stream(nums).boxed().toArray(Integer[]::new); + Arrays.sort(arr, (a, b) -> { + int freqA = count.get(a), freqB = count.get(b); + if (freqA != freqB) return Integer.compare(freqA, freqB); + return Integer.compare(b, a); + }); + + return Arrays.stream(arr).mapToInt(i -> i).toArray(); + } +} +``` + +```cpp +class Solution { +public: + vector frequencySort(vector& nums) { + unordered_map count; + for (int num : nums) { + count[num]++; + } + + sort(nums.begin(), nums.end(), [&](int a, int b) { + if (count[a] != count[b]) return count[a] < count[b]; + return a > b; + }); + + return nums; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number[]} + */ + frequencySort(nums) { + const count = {}; + for (let num of nums) { + count[num] = (count[num] || 0) + 1; + } + + nums.sort((a, b) => { + if (count[a] !== count[b]) return count[a] - count[b]; + return b - a; + }); + + return nums; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(n)$ \ No newline at end of file diff --git a/articles/sort-the-jumbled-numbers.md b/articles/sort-the-jumbled-numbers.md new file mode 100644 index 000000000..b8c0cbf47 --- /dev/null +++ b/articles/sort-the-jumbled-numbers.md @@ -0,0 +1,244 @@ +## 1. Convert To Strings + Sorting + +::tabs-start + +```python +class Solution: + def sortJumbled(self, mapping: List[int], nums: List[int]) -> List[int]: + pairs = [] + + for i, n in enumerate(nums): + n = str(n) + mapped_n = 0 + for c in n: + mapped_n *= 10 + mapped_n += mapping[int(c)] + pairs.append((mapped_n, i)) + + pairs.sort() + return [nums[p[1]] for p in pairs] +``` + +```java +public class Solution { + public int[] sortJumbled(int[] mapping, int[] nums) { + int n = nums.length; + int[][] pairs = new int[n][2]; + + for (int i = 0; i < n; i++) { + String numStr = String.valueOf(nums[i]); + int mapped_n = 0; + for (char c : numStr.toCharArray()) { + mapped_n = mapped_n * 10 + mapping[c - '0']; + } + pairs[i][0] = mapped_n; + pairs[i][1] = i; + } + + Arrays.sort(pairs, (a, b) -> a[0] - b[0]); + + int[] res = new int[n]; + for (int i = 0; i < n; i++) { + res[i] = nums[pairs[i][1]]; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector sortJumbled(vector& mapping, vector& nums) { + vector> pairs; + + for (int i = 0; i < nums.size(); ++i) { + string numStr = to_string(nums[i]); + int mapped_n = 0; + for (char c : numStr) { + mapped_n = mapped_n * 10 + mapping[c - '0']; + } + pairs.push_back({mapped_n, i}); + } + + sort(pairs.begin(), pairs.end()); + + vector res; + for (auto& p : pairs) { + res.push_back(nums[p.second]); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} mapping + * @param {number[]} nums + * @return {number[]} + */ + sortJumbled(mapping, nums) { + let pairs = []; + + for (let i = 0; i < nums.length; i++) { + let numStr = nums[i].toString(); + let mapped_n = 0; + for (let c of numStr) { + mapped_n = mapped_n * 10 + mapping[parseInt(c)]; + } + pairs.push([mapped_n, i]); + } + + pairs.sort((a, b) => a[0] - b[0]); + + return pairs.map(p => nums[p[1]]); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(n)$ + +--- + +## 2. Iterate On Numbers + Sorting + +::tabs-start + +```python +class Solution: + def sortJumbled(self, mapping: List[int], nums: List[int]) -> List[int]: + pairs = [] + + for i, n in enumerate(nums): + mapped_n = 0 + base = 1 + + if n == 0: + mapped_n = mapping[0] + else: + while n > 0: + digit = n % 10 + n //= 10 + mapped_n += base * mapping[digit] + base *= 10 + + pairs.append((mapped_n, i)) + + pairs.sort() + return [nums[p[1]] for p in pairs] +``` + +```java +public class Solution { + public int[] sortJumbled(int[] mapping, int[] nums) { + int n = nums.length; + int[][] pairs = new int[n][2]; + + for (int i = 0; i < n; i++) { + int mapped_n = 0, base = 1; + int num = nums[i]; + + if (num == 0) { + mapped_n = mapping[0]; + } else { + while (num > 0) { + int digit = num % 10; + num /= 10; + mapped_n += base * mapping[digit]; + base *= 10; + } + } + + pairs[i][0] = mapped_n; + pairs[i][1] = i; + } + + Arrays.sort(pairs, (a, b) -> Integer.compare(a[0], b[0])); + + int[] res = new int[n]; + for (int i = 0; i < n; i++) { + res[i] = nums[pairs[i][1]]; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector sortJumbled(vector& mapping, vector& nums) { + vector> pairs; + + for (int i = 0; i < nums.size(); i++) { + int mapped_n = 0, base = 1; + int num = nums[i]; + + if (num == 0) { + mapped_n = mapping[0]; + } else { + while (num > 0) { + int digit = num % 10; + num /= 10; + mapped_n += base * mapping[digit]; + base *= 10; + } + } + + pairs.push_back({mapped_n, i}); + } + + sort(pairs.begin(), pairs.end()); + + vector res; + for (auto& p : pairs) { + res.push_back(nums[p.second]); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} mapping + * @param {number[]} nums + * @return {number[]} + */ + sortJumbled(mapping, nums) { + let pairs = []; + + for (let i = 0; i < nums.length; i++) { + let numStr = nums[i].toString(); + let mapped_n = 0; + for (let c of numStr) { + mapped_n = mapped_n * 10 + mapping[parseInt(c)]; + } + pairs.push([mapped_n, i]); + } + + pairs.sort((a, b) => a[0] - b[0]); + + return pairs.map(p => nums[p[1]]); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(n)$ \ No newline at end of file diff --git a/articles/sort-the-people.md b/articles/sort-the-people.md new file mode 100644 index 000000000..c5d8ca911 --- /dev/null +++ b/articles/sort-the-people.md @@ -0,0 +1,256 @@ +## 1. Hash Map + +::tabs-start + +```python +class Solution: + def sortPeople(self, names: List[str], heights: List[int]) -> List[str]: + height_to_name = {} + for h, n in zip(heights, names): + height_to_name[h] = n + + res = [] + for h in reversed(sorted(heights)): + res.append(height_to_name[h]) + + return res +``` + +```java +public class Solution { + public String[] sortPeople(String[] names, int[] heights) { + Map map = new HashMap<>(); + for (int i = 0; i < heights.length; i++) { + map.put(heights[i], names[i]); + } + + Arrays.sort(heights); + String[] res = new String[heights.length]; + for (int i = 0; i < heights.length; i++) { + res[i] = map.get(heights[heights.length - 1 - i]); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector sortPeople(vector& names, vector& heights) { + unordered_map map; + for (int i = 0; i < heights.size(); i++) { + map[heights[i]] = names[i]; + } + + sort(heights.begin(), heights.end()); + vector res; + for (int i = heights.size() - 1; i >= 0; i--) { + res.push_back(map[heights[i]]); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} names + * @param {number[]} heights + * @return {string[]} + */ + sortPeople(names, heights) { + const map = {}; + for (let i = 0; i < heights.length; i++) { + map[heights[i]] = names[i]; + } + + heights.sort((a, b) => a - b); + const res = []; + for (let i = heights.length - 1; i >= 0; i--) { + res.push(map[heights[i]]); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(n)$ + +--- + +## 2. Sorting the Pairs + +::tabs-start + +```python +class Solution: + def sortPeople(self, names: List[str], heights: List[int]) -> List[str]: + arr = list(zip(heights, names)) + arr.sort(reverse=True) + return [name for _, name in arr] +``` + +```java +public class Solution { + public String[] sortPeople(String[] names, int[] heights) { + int n = names.length; + Pair[] arr = new Pair[n]; + + for (int i = 0; i < n; i++) { + arr[i] = new Pair(heights[i], names[i]); + } + + Arrays.sort(arr, (a, b) -> Integer.compare(b.height, a.height)); + + String[] res = new String[n]; + for (int i = 0; i < n; i++) { + res[i] = arr[i].name; + } + + return res; + } + + static class Pair { + int height; + String name; + + Pair(int height, String name) { + this.height = height; + this.name = name; + } + } +} +``` + +```cpp +class Solution { +public: + vector sortPeople(vector& names, vector& heights) { + vector> arr; + for (int i = 0; i < names.size(); i++) { + arr.emplace_back(heights[i], names[i]); + } + + sort(arr.begin(), arr.end(), [](auto& a, auto& b) { + return a.first > b.first; + }); + + vector res; + for (auto& [_, name] : arr) { + res.push_back(name); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} names + * @param {number[]} heights + * @return {string[]} + */ + sortPeople(names, heights) { + const arr = names.map((name, i) => [heights[i], name]); + arr.sort((a, b) => b[0] - a[0]); + return arr.map(pair => pair[1]); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(n)$ + +--- + +## 3. Sorting the Indices + +::tabs-start + +```python +class Solution: + def sortPeople(self, names: List[str], heights: List[int]) -> List[str]: + indices = list(range(len(names))) + indices.sort(key=lambda i: -heights[i]) + return [names[i] for i in indices] +``` + +```java +public class Solution { + public String[] sortPeople(String[] names, int[] heights) { + Integer[] indices = new Integer[names.length]; + for (int i = 0; i < names.length; i++) { + indices[i] = i; + } + + Arrays.sort(indices, (i, j) -> Integer.compare(heights[j], heights[i])); + + String[] res = new String[names.length]; + for (int i = 0; i < names.length; i++) { + res[i] = names[indices[i]]; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector sortPeople(vector& names, vector& heights) { + int n = names.size(); + vector indices(n); + iota(indices.begin(), indices.end(), 0); + + sort(indices.begin(), indices.end(), [&](int a, int b) { + return heights[a] > heights[b]; + }); + + vector res; + for (int i : indices) { + res.push_back(names[i]); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} names + * @param {number[]} heights + * @return {string[]} + */ + sortPeople(names, heights) { + const indices = names.map((_, i) => i); + indices.sort((a, b) => heights[b] - heights[a]); + return indices.map(i => names[i]); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(n)$ \ No newline at end of file diff --git a/articles/special-array-i.md b/articles/special-array-i.md new file mode 100644 index 000000000..40ccd36c6 --- /dev/null +++ b/articles/special-array-i.md @@ -0,0 +1,129 @@ +## 1. Modulo Comparision + +::tabs-start + +```python +class Solution: + def isArraySpecial(self, nums: List[int]) -> bool: + for i in range(1, len(nums)): + if nums[i - 1] % 2 == nums[i] % 2: + return False + return True +``` + +```java +public class Solution { + public boolean isArraySpecial(int[] nums) { + for (int i = 1; i < nums.length; i++) { + if (nums[i - 1] % 2 == nums[i] % 2) { + return false; + } + } + return true; + } +} +``` + +```cpp +class Solution { +public: + bool isArraySpecial(vector& nums) { + for (int i = 1; i < nums.size(); i++) { + if (nums[i - 1] % 2 == nums[i] % 2) { + return false; + } + } + return true; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {boolean} + */ + isArraySpecial(nums) { + for (let i = 1; i < nums.length; i++) { + if (nums[i - 1] % 2 === nums[i] % 2) { + return false; + } + } + return true; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ + +--- + +## 2. Bitwise Comparision + +::tabs-start + +```python +class Solution: + def isArraySpecial(self, nums: List[int]) -> bool: + for i in range(1, len(nums)): + if nums[i - 1] & 1 == nums[i] & 1: + return False + return True +``` + +```java +public class Solution { + public boolean isArraySpecial(int[] nums) { + for (int i = 1; i < nums.length; i++) { + if ((nums[i - 1] & 1) == (nums[i] & 1)) { + return false; + } + } + return true; + } +} +``` + +```cpp +class Solution { +public: + bool isArraySpecial(vector& nums) { + for (int i = 1; i < nums.size(); i++) { + if ((nums[i - 1] & 1) == (nums[i] & 1)) { + return false; + } + } + return true; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {boolean} + */ + isArraySpecial(nums) { + for (let i = 1; i < nums.length; i++) { + if ((nums[i - 1] & 1) === (nums[i] & 1)) { + return false; + } + } + return true; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ \ No newline at end of file diff --git a/articles/string-matching-in-an-array.md b/articles/string-matching-in-an-array.md new file mode 100644 index 000000000..f369be41c --- /dev/null +++ b/articles/string-matching-in-an-array.md @@ -0,0 +1,1157 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def stringMatching(self, words: List[str]) -> List[str]: + res = [] + + for i in range(len(words)): + for j in range(len(words)): + if i == j: + continue + + if words[i] in words[j]: + res.append(words[i]) + break + + return res +``` + +```java +public class Solution { + public List stringMatching(String[] words) { + List res = new ArrayList<>(); + + for (int i = 0; i < words.length; i++) { + for (int j = 0; j < words.length; j++) { + if (i == j) { + continue; + } + + if (words[j].contains(words[i])) { + res.add(words[i]); + break; + } + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector stringMatching(vector& words) { + vector res; + + for (int i = 0; i < words.size(); i++) { + for (int j = 0; j < words.size(); j++) { + if (i == j) { + continue; + } + + if (words[j].find(words[i]) != string::npos) { + res.push_back(words[i]); + break; + } + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} words + * @return {string[]} + */ + stringMatching(words) { + let res = []; + + for (let i = 0; i < words.length; i++) { + for (let j = 0; j < words.length; j++) { + if (i === j) { + continue; + } + + if (words[j].includes(words[i])) { + res.push(words[i]); + break; + } + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2 * m ^ 2)$ +* Space complexity: + * $O(1)$ extra space. + * $O(n * m)$ space for the output list. + +> Where $n$ is the number of words, and $m$ is the length of the longest word. + +--- + +## 2. Sorting + +::tabs-start + +```python +class Solution: + def stringMatching(self, words: List[str]) -> List[str]: + res = [] + words.sort(key=len) + + for i in range(len(words)): + for j in range(i + 1, len(words)): + if words[i] in words[j]: + res.append(words[i]) + break + + return res +``` + +```java +public class Solution { + public List stringMatching(String[] words) { + List res = new ArrayList<>(); + Arrays.sort(words, Comparator.comparingInt(String::length)); + + for (int i = 0; i < words.length; i++) { + for (int j = i + 1; j < words.length; j++) { + if (words[j].contains(words[i])) { + res.add(words[i]); + break; + } + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector stringMatching(vector& words) { + vector res; + sort(words.begin(), words.end(), [](const string& a, const string& b) { + return a.length() < b.length(); + }); + + for (int i = 0; i < words.size(); i++) { + for (int j = i + 1; j < words.size(); j++) { + if (words[j].find(words[i]) != string::npos) { + res.push_back(words[i]); + break; + } + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} words + * @return {string[]} + */ + stringMatching(words) { + let res = []; + words.sort((a, b) => a.length - b.length); + + for (let i = 0; i < words.length; i++) { + for (let j = i + 1; j < words.length; j++) { + if (words[j].includes(words[i])) { + res.push(words[i]); + break; + } + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2 * m ^ 2)$ +* Space complexity: + * $O(1)$ or $O(n)$ depending on the sorting algorithm. + * $O(n * m)$ space for the output list. + +> Where $n$ is the number of words, and $m$ is the length of the longest word. + +--- + +## 3. Knuth-Morris-Pratt (KMP) Algorithm + +::tabs-start + +```python +class Solution: + def stringMatching(self, words: List[str]) -> List[str]: + def kmp(word1: str, word2: str) -> int: + lps = [0] * len(word2) + prevLPS, i = 0, 1 + + while i < len(word2): + if word2[i] == word2[prevLPS]: + lps[i] = prevLPS + 1 + prevLPS += 1 + i += 1 + elif prevLPS == 0: + lps[i] = 0 + i += 1 + else: + prevLPS = lps[prevLPS - 1] + + i = j = 0 + while i < len(word1): + if word1[i] == word2[j]: + i += 1 + j += 1 + else: + if j == 0: + i += 1 + else: + j = lps[j - 1] + + if j == len(word2): + return i - len(word2) + + return -1 + + res = [] + words.sort(key=len) + + for i in range(len(words)): + for j in range(i + 1, len(words)): + if kmp(words[j], words[i]) != -1: + res.append(words[i]) + break + + return res +``` + +```java +public class Solution { + public List stringMatching(String[] words) { + List res = new ArrayList<>(); + Arrays.sort(words, Comparator.comparingInt(String::length)); + + for (int i = 0; i < words.length; i++) { + for (int j = i + 1; j < words.length; j++) { + if (kmp(words[j], words[i]) != -1) { + res.add(words[i]); + break; + } + } + } + + return res; + } + + private int kmp(String word1, String word2) { + int[] lps = new int[word2.length()]; + int prevLPS = 0, i = 1; + + while (i < word2.length()) { + if (word2.charAt(i) == word2.charAt(prevLPS)) { + lps[i] = prevLPS + 1; + prevLPS++; + i++; + } else if (prevLPS == 0) { + lps[i] = 0; + i++; + } else { + prevLPS = lps[prevLPS - 1]; + } + } + + i = 0; + int j = 0; + while (i < word1.length()) { + if (word1.charAt(i) == word2.charAt(j)) { + i++; + j++; + } else { + if (j == 0) { + i++; + } else { + j = lps[j - 1]; + } + } + + if (j == word2.length()) { + return i - word2.length(); + } + } + + return -1; + } +} +``` + +```cpp +class Solution { +public: + vector stringMatching(vector& words) { + vector res; + sort(words.begin(), words.end(), [](const string& a, const string& b) { + return a.length() < b.length(); + }); + + for (int i = 0; i < words.size(); i++) { + for (int j = i + 1; j < words.size(); j++) { + if (kmp(words[j], words[i]) != -1) { + res.push_back(words[i]); + break; + } + } + } + + return res; + } + +private: + int kmp(const string& word1, const string& word2) { + vector lps(word2.size(), 0); + int prevLPS = 0, i = 1; + + while (i < word2.size()) { + if (word2[i] == word2[prevLPS]) { + lps[i++] = ++prevLPS; + } else if (prevLPS == 0) { + lps[i++] = 0; + } else { + prevLPS = lps[prevLPS - 1]; + } + } + + i = 0; + int j = 0; + while (i < word1.size()) { + if (word1[i] == word2[j]) { + i++; + j++; + } else { + if (j == 0) { + i++; + } else { + j = lps[j - 1]; + } + } + + if (j == word2.size()) { + return i - word2.size(); + } + } + + return -1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} words + * @return {string[]} + */ + stringMatching(words) { + const kmp = (word1, word2) => { + const lps = Array(word2.length).fill(0); + let prevLPS = 0, i = 1; + + while (i < word2.length) { + if (word2[i] === word2[prevLPS]) { + lps[i++] = ++prevLPS; + } else if (prevLPS === 0) { + lps[i++] = 0; + } else { + prevLPS = lps[prevLPS - 1]; + } + } + + i = 0; + let j = 0; + while (i < word1.length) { + if (word1[i] === word2[j]) { + i++; + j++; + } else { + if (j === 0) { + i++; + } else { + j = lps[j - 1]; + } + } + + if (j === word2.length) { + return i - word2.length; + } + } + + return -1; + }; + + let res = []; + words.sort((a, b) => a.length - b.length); + + for (let i = 0; i < words.length; i++) { + for (let j = i + 1; j < words.length; j++) { + if (kmp(words[j], words[i]) !== -1) { + res.push(words[i]); + break; + } + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2 * m)$ +* Space complexity: + * $O(m)$ extra space. + * $O(1)$ or $O(n)$ space depending on the sorting algorithm. + * $O(n * m)$ space for the output list. + +> Where $n$ is the number of words, and $m$ is the length of the longest word. + +--- + +## 4. Rabin-Karp Algorithm (Rolling Hash) + +::tabs-start + +```python +class Solution: + def stringMatching(self, words: List[str]) -> List[str]: + def rabinKarp(word1: str, word2: str) -> int: + base1, mod1 = 31, 768258391 + base2, mod2 = 37, 685683731 + n, m = len(word1), len(word2) + + power1, power2 = 1, 1 + for _ in range(m): + power1 = (power1 * base1) % mod1 + power2 = (power2 * base2) % mod2 + + word1_hash1 = word1_hash2 = 0 + word2_hash1 = word2_hash2 = 0 + + for i in range(m): + word1_hash1 = (word1_hash1 * base1 + ord(word2[i])) % mod1 + word1_hash2 = (word1_hash2 * base2 + ord(word2[i])) % mod2 + word2_hash1 = (word2_hash1 * base1 + ord(word1[i])) % mod1 + word2_hash2 = (word2_hash2 * base2 + ord(word1[i])) % mod2 + + for i in range(n - m + 1): + if word2_hash1 == word1_hash1 and word2_hash2 == word1_hash2: + return i + + if i + m < n: + word2_hash1 = (word2_hash1 * base1 - ord(word1[i]) * power1 + ord(word1[i + m])) % mod1 + word2_hash2 = (word2_hash2 * base2 - ord(word1[i]) * power2 + ord(word1[i + m])) % mod2 + + word2_hash1 = (word2_hash1 + mod1) % mod1 + word2_hash2 = (word2_hash2 + mod2) % mod2 + + return -1 + + res = [] + words.sort(key=len) + + for i in range(len(words)): + for j in range(i + 1, len(words)): + if rabinKarp(words[j], words[i]) != -1: + res.append(words[i]) + break + + return res +``` + +```java +public class Solution { + public List stringMatching(String[] words) { + List res = new ArrayList<>(); + Arrays.sort(words, Comparator.comparingInt(String::length)); + + for (int i = 0; i < words.length; i++) { + for (int j = i + 1; j < words.length; j++) { + if (rabinKarp(words[j], words[i]) != -1) { + res.add(words[i]); + break; + } + } + } + + return res; + } + + private int rabinKarp(String word1, String word2) { + int base1 = 31, mod1 = 768258391; + int base2 = 37, mod2 = 685683731; + int n = word1.length(), m = word2.length(); + + long power1 = 1, power2 = 1; + for (int k = 0; k < m; k++) { + power1 = (power1 * base1) % mod1; + power2 = (power2 * base2) % mod2; + } + + long word1Hash1 = 0, word1Hash2 = 0; + long word2Hash1 = 0, word2Hash2 = 0; + + for (int i = 0; i < m; i++) { + word1Hash1 = (word1Hash1 * base1 + word2.charAt(i)) % mod1; + word1Hash2 = (word1Hash2 * base2 + word2.charAt(i)) % mod2; + word2Hash1 = (word2Hash1 * base1 + word1.charAt(i)) % mod1; + word2Hash2 = (word2Hash2 * base2 + word1.charAt(i)) % mod2; + } + + for (int i = 0; i <= n - m; i++) { + if (word2Hash1 == word1Hash1 && word2Hash2 == word1Hash2) { + return i; + } + + if (i + m < n) { + word2Hash1 = (word2Hash1 * base1 - word1.charAt(i) * power1 + word1.charAt(i + m)) % mod1; + word2Hash2 = (word2Hash2 * base2 - word1.charAt(i) * power2 + word1.charAt(i + m)) % mod2; + + if (word2Hash1 < 0) word2Hash1 += mod1; + if (word2Hash2 < 0) word2Hash2 += mod2; + } + } + + return -1; + } +} +``` + +```cpp +class Solution { +public: + vector stringMatching(vector& words) { + vector res; + sort(words.begin(), words.end(), [](const string& a, const string& b) { + return a.length() < b.length(); + }); + + for (int i = 0; i < words.size(); i++) { + for (int j = i + 1; j < words.size(); j++) { + if (rabinKarp(words[j], words[i]) != -1) { + res.push_back(words[i]); + break; + } + } + } + + return res; + } + +private: + int rabinKarp(const string& word1, const string& word2) { + int base1 = 31, mod1 = 768258391; + int base2 = 37, mod2 = 685683731; + int n = word1.size(), m = word2.size(); + + long long power1 = 1, power2 = 1; + for (int i = 0; i < m; i++) { + power1 = (power1 * base1) % mod1; + power2 = (power2 * base2) % mod2; + } + + long long word1Hash1 = 0, word1Hash2 = 0; + long long word2Hash1 = 0, word2Hash2 = 0; + + for (int i = 0; i < m; i++) { + word1Hash1 = (word1Hash1 * base1 + word2[i]) % mod1; + word1Hash2 = (word1Hash2 * base2 + word2[i]) % mod2; + word2Hash1 = (word2Hash1 * base1 + word1[i]) % mod1; + word2Hash2 = (word2Hash2 * base2 + word1[i]) % mod2; + } + + for (int i = 0; i <= n - m; i++) { + if (word2Hash1 == word1Hash1 && word2Hash2 == word1Hash2) { + return i; + } + + if (i + m < n) { + word2Hash1 = (word2Hash1 * base1 - word1[i] * power1 + word1[i + m]) % mod1; + word2Hash2 = (word2Hash2 * base2 - word1[i] * power2 + word1[i + m]) % mod2; + + if (word2Hash1 < 0) word2Hash1 += mod1; + if (word2Hash2 < 0) word2Hash2 += mod2; + } + } + + return -1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} words + * @return {string[]} + */ + stringMatching(words) { + const rabinKarp = (word1, word2) => { + const base1 = 31, mod1 = 768258391; + const base2 = 37, mod2 = 685683731; + const n = word1.length, m = word2.length; + + let power1 = 1, power2 = 1; + for (let k = 0; k < m; k++) { + power1 = (power1 * base1) % mod1; + power2 = (power2 * base2) % mod2; + } + + let hash1 = 0, hash2 = 0; + let cur1 = 0, cur2 = 0; + + for (let i = 0; i < m; i++) { + hash1 = (hash1 * base1 + word2.charCodeAt(i)) % mod1; + hash2 = (hash2 * base2 + word2.charCodeAt(i)) % mod2; + cur1 = (cur1 * base1 + word1.charCodeAt(i)) % mod1; + cur2 = (cur2 * base2 + word1.charCodeAt(i)) % mod2; + } + + for (let i = 0; i <= n - m; i++) { + if (cur1 === hash1 && cur2 === hash2) { + return i; + } + + if (i + m < n) { + cur1 = (cur1 * base1 - word1.charCodeAt(i) * power1 + word1.charCodeAt(i + m)) % mod1; + cur2 = (cur2 * base2 - word1.charCodeAt(i) * power2 + word1.charCodeAt(i + m)) % mod2; + + cur1 = (cur1 + mod1) % mod1; + cur2 = (cur2 + mod2) % mod2; + } + } + + return -1; + }; + + words.sort((a, b) => a.length - b.length); + let res = []; + + for (let i = 0; i < words.length; i++) { + for (let j = i + 1; j < words.length; j++) { + if (rabinKarp(words[j], words[i]) !== -1) { + res.push(words[i]); + break; + } + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2 * m)$ +* Space complexity: + * $O(1)$ or $O(n)$ space depending on the sorting algorithm. + * $O(n * m)$ space for the output list. + +> Where $n$ is the number of words, and $m$ is the length of the longest word. + +--- + +## 5. Z-Algorithm + +::tabs-start + +```python +class Solution: + def stringMatching(self, words: List[str]) -> List[str]: + def zAlgorithm(word1: str, word2: str) -> int: + s = word2 + "$" + word1 + n = len(s) + z = [0] * n + l, r = 0, 0 + + for i in range(1, n): + if i <= r: + z[i] = min(r - i + 1, z[i - l]) + while i + z[i] < n and s[z[i]] == s[i + z[i]]: + z[i] += 1 + if i + z[i] - 1 > r: + l, r = i, i + z[i] - 1 + + for i in range(len(word2) + 1, n): + if z[i] == len(word2): + return i - len(word2) - 1 + + return -1 + + res = [] + words.sort(key=len) + + for i in range(len(words)): + for j in range(i + 1, len(words)): + if zAlgorithm(words[j], words[i]) != -1: + res.append(words[i]) + break + + return res +``` + +```java +public class Solution { + public List stringMatching(String[] words) { + List res = new ArrayList<>(); + Arrays.sort(words, Comparator.comparingInt(String::length)); + + for (int i = 0; i < words.length; i++) { + for (int j = i + 1; j < words.length; j++) { + if (zAlgorithm(words[j], words[i]) != -1) { + res.add(words[i]); + break; + } + } + } + + return res; + } + + private int zAlgorithm(String word1, String word2) { + String s = word2 + "$" + word1; + int n = s.length(); + int[] z = new int[n]; + int l = 0, r = 0; + + for (int i = 1; i < n; i++) { + if (i <= r) { + z[i] = Math.min(r - i + 1, z[i - l]); + } + while (i + z[i] < n && s.charAt(z[i]) == s.charAt(i + z[i])) { + z[i]++; + } + if (i + z[i] - 1 > r) { + l = i; + r = i + z[i] - 1; + } + } + + for (int i = word2.length() + 1; i < n; i++) { + if (z[i] == word2.length()) { + return i - word2.length() - 1; + } + } + + return -1; + } +} +``` + +```cpp +class Solution { +public: + vector stringMatching(vector& words) { + vector res; + sort(words.begin(), words.end(), [](const string& a, const string& b) { + return a.length() < b.length(); + }); + + for (int i = 0; i < words.size(); i++) { + for (int j = i + 1; j < words.size(); j++) { + if (zAlgorithm(words[j], words[i]) != -1) { + res.push_back(words[i]); + break; + } + } + } + + return res; + } + +private: + int zAlgorithm(const string& word1, const string& word2) { + string s = word2 + "$" + word1; + int n = s.size(); + vector z(n, 0); + int l = 0, r = 0; + + for (int i = 1; i < n; i++) { + if (i <= r) { + z[i] = min(r - i + 1, z[i - l]); + } + while (i + z[i] < n && s[z[i]] == s[i + z[i]]) { + z[i]++; + } + if (i + z[i] - 1 > r) { + l = i; + r = i + z[i] - 1; + } + } + + for (int i = word2.size() + 1; i < n; i++) { + if (z[i] == word2.size()) { + return i - word2.size() - 1; + } + } + + return -1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} words + * @return {string[]} + */ + stringMatching(words) { + const zAlgorithm = (word1, word2) => { + const s = word2 + "$" + word1; + const n = s.length; + const z = Array(n).fill(0); + let l = 0, r = 0; + + for (let i = 1; i < n; i++) { + if (i <= r) { + z[i] = Math.min(r - i + 1, z[i - l]); + } + while (i + z[i] < n && s[z[i]] === s[i + z[i]]) { + z[i]++; + } + if (i + z[i] - 1 > r) { + l = i; + r = i + z[i] - 1; + } + } + + for (let i = word2.length + 1; i < n; i++) { + if (z[i] === word2.length) { + return i - word2.length - 1; + } + } + + return -1; + }; + + words.sort((a, b) => a.length - b.length); + let res = []; + + for (let i = 0; i < words.length; i++) { + for (let j = i + 1; j < words.length; j++) { + if (zAlgorithm(words[j], words[i]) !== -1) { + res.push(words[i]); + break; + } + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2 * m)$ +* Space complexity: + * $O(m)$ extra space. + * $O(1)$ or $O(n)$ space depending on the sorting algorithm. + * $O(n * m)$ space for the output list. + +> Where $n$ is the number of words, and $m$ is the length of the longest word. + +--- + +## 6. Trie + +::tabs-start + +```python +class TrieNode: + def __init__(self): + self.children = [None] * 26 + self.cnt = 0 + +class Trie: + def __init__(self): + self.root = TrieNode() + + def insert_suffixes(self, word: str) -> None: + for i in range(len(word)): + node = self.root + for j in range(i, len(word)): + idx = ord(word[j]) - ord('a') + if not node.children[idx]: + node.children[idx] = TrieNode() + + node = node.children[idx] + node.cnt += 1 + + def search(self, word: str) -> bool: + node = self.root + for c in word: + idx = ord(c) - ord('a') + node = node.children[idx] + return node.cnt > 1 + +class Solution: + def stringMatching(self, words: List[str]) -> List[str]: + res = [] + trie = Trie() + + for word in words: + trie.insert_suffixes(word) + + for word in words: + if trie.search(word): + res.append(word) + + return res +``` + +```java +class TrieNode { + TrieNode[] children; + int cnt; + + TrieNode() { + children = new TrieNode[26]; + cnt = 0; + } +} + +class Trie { + TrieNode root; + + Trie() { + root = new TrieNode(); + } + + void insertSuffixes(String word) { + for (int i = 0; i < word.length(); i++) { + TrieNode node = root; + for (int j = i; j < word.length(); j++) { + int idx = word.charAt(j) - 'a'; + if (node.children[idx] == null) { + node.children[idx] = new TrieNode(); + } + + node = node.children[idx]; + node.cnt++; + } + } + } + + boolean search(String word) { + TrieNode node = root; + for (int i = 0; i < word.length(); i++) { + int idx = word.charAt(i) - 'a'; + node = node.children[idx]; + } + return node.cnt > 1; + } +} + +class Solution { + public List stringMatching(String[] words) { + List res = new ArrayList<>(); + Trie trie = new Trie(); + + for (String word : words) { + trie.insertSuffixes(word); + } + + for (String word : words) { + if (trie.search(word)) { + res.add(word); + } + } + + return res; + } +} +``` + +```cpp +class TrieNode { +public: + TrieNode* children[26]; + int cnt; + + TrieNode() { + for (int i = 0; i < 26; i++) children[i] = nullptr; + cnt = 0; + } +}; + +class Trie { +public: + TrieNode* root; + + Trie() { + root = new TrieNode(); + } + + void insertSuffixes(const string& word) { + for (int i = 0; i < word.size(); i++) { + TrieNode* node = root; + for (int j = i; j < word.size(); j++) { + int idx = word[j] - 'a'; + if (!node->children[idx]) { + node->children[idx] = new TrieNode(); + } + + node = node->children[idx]; + node->cnt++; + } + } + } + + bool search(const string& word) { + TrieNode* node = root; + for (char c : word) { + int idx = c - 'a'; + node = node->children[idx]; + } + return node->cnt > 1; + } +}; + +class Solution { +public: + vector stringMatching(vector& words) { + vector res; + Trie trie; + + for (const string& word : words) { + trie.insertSuffixes(word); + } + + for (const string& word : words) { + if (trie.search(word)) { + res.push_back(word); + } + } + + return res; + } +}; +``` + +```javascript +class TrieNode { + constructor() { + this.children = new Array(26).fill(null); + this.cnt = 0; + } +} + +class Trie { + constructor() { + this.root = new TrieNode(); + } + + /** + * @param {string} word + * @return {void} + */ + insertSuffixes(word) { + for (let i = 0; i < word.length; i++) { + let node = this.root; + for (let j = i; j < word.length; j++) { + let idx = word.charCodeAt(j) - 97; + if (!node.children[idx]) { + node.children[idx] = new TrieNode(); + } + + node = node.children[idx]; + node.cnt++; + } + } + } + + /** + * @param {string} word + * @return {boolean} + */ + search(word) { + let node = this.root; + for (let i = 0; i < word.length; i++) { + let idx = word.charCodeAt(i) - 97; + node = node.children[idx]; + } + return node.cnt > 1; + } +} + +class Solution { + /** + * @param {string[]} words + * @return {string[]} + */ + stringMatching(words) { + const res = []; + const trie = new Trie(); + + for (let word of words) { + trie.insertSuffixes(word); + } + + for (let word of words) { + if (trie.search(word)) { + res.push(word); + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * m ^ 2)$ +* Space complexity: + * $O(n * m ^ 2)$ extra space. + * $O(n * m)$ space for the output list. + +> Where $n$ is the number of words, and $m$ is the length of the longest word. \ No newline at end of file diff --git a/articles/subarray-sums-divisible-by-k.md b/articles/subarray-sums-divisible-by-k.md new file mode 100644 index 000000000..f1faeaf61 --- /dev/null +++ b/articles/subarray-sums-divisible-by-k.md @@ -0,0 +1,280 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def subarraysDivByK(self, nums: List[int], k: int) -> int: + n, res = len(nums), 0 + + for i in range(n): + curSum = 0 + for j in range(i, n): + curSum += nums[j] + if curSum % k == 0: + res += 1 + + return res +``` + +```java +public class Solution { + public int subarraysDivByK(int[] nums, int k) { + int n = nums.length, res = 0; + + for (int i = 0; i < n; i++) { + int curSum = 0; + for (int j = i; j < n; j++) { + curSum += nums[j]; + if (curSum % k == 0) { + res++; + } + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int subarraysDivByK(vector& nums, int k) { + int n = nums.size(), res = 0; + + for (int i = 0; i < n; i++) { + int curSum = 0; + for (int j = i; j < n; j++) { + curSum += nums[j]; + if (curSum % k == 0) { + res++; + } + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + subarraysDivByK(nums, k) { + const n = nums.length; + let res = 0; + + for (let i = 0; i < n; i++) { + let curSum = 0; + for (let j = i; j < n; j++) { + curSum += nums[j]; + if (curSum % k === 0) { + res++; + } + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(1)$ + +--- + +## 2. Prefix Sum + Hash Map + +::tabs-start + +```python +class Solution: + def subarraysDivByK(self, nums: List[int], k: int) -> int: + prefix_sum = 0 + res = 0 + prefix_cnt = defaultdict(int) + prefix_cnt[0] = 1 + + for n in nums: + prefix_sum += n + remain = prefix_sum % k + + res += prefix_cnt[remain] + prefix_cnt[remain] += 1 + + return res +``` + +```java +public class Solution { + public int subarraysDivByK(int[] nums, int k) { + int prefixSum = 0, res = 0; + Map prefixCnt = new HashMap<>(); + prefixCnt.put(0, 1); + + for (int n : nums) { + prefixSum += n; + int remain = prefixSum % k; + if (remain < 0) remain += k; + + res += prefixCnt.getOrDefault(remain, 0); + prefixCnt.put(remain, prefixCnt.getOrDefault(remain, 0) + 1); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int subarraysDivByK(vector& nums, int k) { + int prefixSum = 0, res = 0; + unordered_map prefixCnt; + prefixCnt[0] = 1; + + for (int n : nums) { + prefixSum += n; + int remain = prefixSum % k; + if (remain < 0) remain += k; + + res += prefixCnt[remain]; + prefixCnt[remain]++; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + subarraysDivByK(nums, k) { + let prefixSum = 0, res = 0; + const prefixCnt = new Map(); + prefixCnt.set(0, 1); + + for (let n of nums) { + prefixSum += n; + let remain = prefixSum % k; + if (remain < 0) remain += k; + + res += prefixCnt.get(remain) || 0; + prefixCnt.set(remain, (prefixCnt.get(remain) || 0) + 1); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(k)$ + +--- + +## 3. Prefix Sum + Array + +::tabs-start + +```python +class Solution: + def subarraysDivByK(self, nums: List[int], k: int) -> int: + count = [0] * k + count[0] = 1 + prefix = res = 0 + + for num in nums: + prefix = (prefix + num + k) % k + res += count[prefix] + count[prefix] += 1 + + return res +``` + +```java +public class Solution { + public int subarraysDivByK(int[] nums, int k) { + int[] count = new int[k]; + count[0] = 1; + int prefix = 0, res = 0; + + for (int num : nums) { + prefix = (prefix + num % k + k) % k; + res += count[prefix]; + count[prefix]++; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int subarraysDivByK(vector& nums, int k) { + vector count(k, 0); + count[0] = 1; + int prefix = 0, res = 0; + + for (int num : nums) { + prefix = (prefix + num % k + k) % k; + res += count[prefix]; + count[prefix]++; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + subarraysDivByK(nums, k) { + const count = Array(k).fill(0); + count[0] = 1; + let prefix = 0, res = 0; + + for (let num of nums) { + prefix = (prefix + num % k + k) % k; + res += count[prefix]; + count[prefix]++; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n + k)$ +* Space complexity: $O(k)$ \ No newline at end of file diff --git a/articles/uncommon-words-from-two-sentences.md b/articles/uncommon-words-from-two-sentences.md new file mode 100644 index 000000000..67be56a4b --- /dev/null +++ b/articles/uncommon-words-from-two-sentences.md @@ -0,0 +1,183 @@ +## 1. Hash Map - I + +::tabs-start + +```python +class Solution: + def uncommonFromSentences(self, s1: str, s2: str) -> List[str]: + count = defaultdict(int) + for w in s1.split(" ") + s2.split(" "): + count[w] += 1 + + res = [] + for w, cnt in count.items(): + if cnt == 1: + res.append(w) + return res +``` + +```java +public class Solution { + public String[] uncommonFromSentences(String s1, String s2) { + String[] words = (s1 + " " + s2).split(" "); + Map count = new HashMap<>(); + + for (String w : words) { + count.put(w, count.getOrDefault(w, 0) + 1); + } + + List res = new ArrayList<>(); + for (Map.Entry entry : count.entrySet()) { + if (entry.getValue() == 1) { + res.add(entry.getKey()); + } + } + + return res.toArray(new String[0]); + } +} +``` + +```cpp +class Solution { +public: + vector uncommonFromSentences(string s1, string s2) { + unordered_map count; + istringstream ss(s1 + " " + s2); + string w; + while (ss >> w) { + count[w]++; + } + + vector res; + for (auto& [word, freq] : count) { + if (freq == 1) { + res.push_back(word); + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s1 + * @param {string} s2 + * @return {string[]} + */ + uncommonFromSentences(s1, s2) { + const words = (s1 + " " + s2).split(" "); + const count = new Map(); + + for (const w of words) { + count.set(w, (count.get(w) || 0) + 1); + } + + const res = []; + for (const [w, c] of count.entries()) { + if (c === 1) { + res.push(w); + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n + m)$ +* Space complexity: $O(n + m)$ + +> Where $n$ and $m$ are the lengths of the strings $s1$ and $s2$, respectively. + +--- + +## 2. Hash Map - II + +::tabs-start + +```python +class Solution: + def uncommonFromSentences(self, s1: str, s2: str) -> List[str]: + return [w for w, cnt in Counter(s1.split(" ") + s2.split(" ")).items() if cnt == 1] +``` + +```java +public class Solution { + public String[] uncommonFromSentences(String s1, String s2) { + String[] words = (s1 + " " + s2).split(" "); + Map count = new HashMap<>(); + + for (String w : words) { + count.put(w, count.getOrDefault(w, 0) + 1); + } + + return count.entrySet() + .stream() + .filter(e -> e.getValue() == 1) + .map(Map.Entry::getKey) + .toArray(String[]::new); + } +} +``` + +```cpp +class Solution { +public: + vector uncommonFromSentences(string s1, string s2) { + unordered_map count; + istringstream ss(s1 + " " + s2); + string w; + while (ss >> w) { + count[w]++; + } + + vector res; + for (auto& [w, c] : count) { + if (c == 1) { + res.push_back(w); + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s1 + * @param {string} s2 + * @return {string[]} + */ + uncommonFromSentences(s1, s2) { + const words = (s1 + " " + s2).split(" "); + const count = new Map(); + + for (const w of words) { + count.set(w, (count.get(w) || 0) + 1); + } + + return [...count.entries()] + .filter(([_, c]) => c === 1) + .map(([w]) => w); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n + m)$ +* Space complexity: $O(n + m)$ + +> Where $n$ and $m$ are the lengths of the strings $s1$ and $s2$, respectively. \ No newline at end of file diff --git a/articles/valid-palindrome-ii.md b/articles/valid-palindrome-ii.md index 05367b687..6b1fbf303 100644 --- a/articles/valid-palindrome-ii.md +++ b/articles/valid-palindrome-ii.md @@ -119,6 +119,31 @@ class Solution { } ``` +```csharp +public class Solution { + public bool ValidPalindrome(string s) { + if (IsPalindrome(s)) return true; + + for (int i = 0; i < s.Length; i++) { + string newS = s.Substring(0, i) + s.Substring(i + 1); + if (IsPalindrome(newS)) return true; + } + + return false; + } + + private bool IsPalindrome(string str) { + int left = 0, right = str.Length - 1; + while (left < right) { + if (str[left] != str[right]) return false; + left++; + right--; + } + return true; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -250,6 +275,36 @@ class Solution { } ``` +```csharp +public class Solution { + public bool ValidPalindrome(string s) { + int l = 0, r = s.Length - 1; + + while (l < r) { + if (s[l] != s[r]) { + string skipL = s.Substring(l + 1, r - l); + string skipR = s.Substring(l, r - l); + return IsPalindrome(skipL) || IsPalindrome(skipR); + } + l++; + r--; + } + + return true; + } + + private bool IsPalindrome(string str) { + int left = 0, right = str.Length - 1; + while (left < right) { + if (str[left] != str[right]) return false; + left++; + right--; + } + return true; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -387,6 +442,32 @@ class Solution { } ``` +```csharp +public class Solution { + public bool ValidPalindrome(string s) { + bool IsPalindrome(int l, int r) { + while (l < r) { + if (s[l] != s[r]) return false; + l++; + r--; + } + return true; + } + + int left = 0, right = s.Length - 1; + while (left < right) { + if (s[left] != s[right]) { + return IsPalindrome(left + 1, right) || IsPalindrome(left, right - 1); + } + left++; + right--; + } + + return true; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/valid-word-abbreviation.md b/articles/valid-word-abbreviation.md new file mode 100644 index 000000000..79c44a2e7 --- /dev/null +++ b/articles/valid-word-abbreviation.md @@ -0,0 +1,163 @@ +## 1. Two Pointers + +::tabs-start + +```python +class Solution: + def validWordAbbreviation(self, word: str, abbr: str) -> bool: + n, m = len(word), len(abbr) + i = j = 0 + + while i < n and j < m: + if abbr[j] == '0': + return False + + if word[i] == abbr[j]: + i, j = i + 1, j + 1 + elif abbr[j].isalpha(): + return False + else: + subLen = 0 + while j < m and abbr[j].isdigit(): + subLen = subLen * 10 + int(abbr[j]) + j += 1 + i += subLen + + return i == n and j == m +``` + +```java +public class Solution { + public boolean validWordAbbreviation(String word, String abbr) { + int n = word.length(), m = abbr.length(); + int i = 0, j = 0; + + while (i < n && j < m) { + if (abbr.charAt(j) == '0') return false; + + if (Character.isLetter(abbr.charAt(j))) { + if (i < n && word.charAt(i) == abbr.charAt(j)) { + i++; + j++; + } else { + return false; + } + } else { + int subLen = 0; + while (j < m && Character.isDigit(abbr.charAt(j))) { + subLen = subLen * 10 + (abbr.charAt(j) - '0'); + j++; + } + i += subLen; + } + } + + return i == n && j == m; + } +} +``` + +```cpp +class Solution { +public: + bool validWordAbbreviation(string word, string abbr) { + int n = word.length(), m = abbr.length(); + int i = 0, j = 0; + + while (i < n && j < m) { + if (abbr[j] == '0') return false; + + if (isalpha(abbr[j])) { + if (word[i] == abbr[j]) { + i++; j++; + } else { + return false; + } + } else { + int subLen = 0; + while (j < m && isdigit(abbr[j])) { + subLen = subLen * 10 + (abbr[j] - '0'); + j++; + } + i += subLen; + } + } + + return i == n && j == m; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} word + * @param {string} abbr + * @return {boolean} + */ + validWordAbbreviation(word, abbr) { + let n = word.length, m = abbr.length; + let i = 0, j = 0; + + while (i < n && j < m) { + if (abbr[j] === '0') return false; + + if (isNaN(abbr[j])) { + if (word[i] === abbr[j]) { + i++; j++; + } else { + return false; + } + } else { + let subLen = 0; + while (j < m && !isNaN(abbr[j]) && abbr[j] !== ' ') { + subLen = subLen * 10 + parseInt(abbr[j]); + j++; + } + i += subLen; + } + } + + return i === n && j === m; + } +} +``` + +```csharp +public class Solution { + public bool ValidWordAbbreviation(string word, string abbr) { + int n = word.Length, m = abbr.Length; + int i = 0, j = 0; + + while (i < n && j < m) { + if (abbr[j] == '0') return false; + + if (char.IsLetter(abbr[j])) { + if (i < n && word[i] == abbr[j]) { + i++; j++; + } else { + return false; + } + } else { + int subLen = 0; + while (j < m && char.IsDigit(abbr[j])) { + subLen = subLen * 10 + (abbr[j] - '0'); + j++; + } + i += subLen; + } + } + + return i == n && j == m; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n + m)$ +* Space complexity: $O(1)$ + +> Where $n$ and $m$ are the lengths of the strings $word$ and $abbr$, respectively. \ No newline at end of file diff --git a/articles/word-subsets.md b/articles/word-subsets.md new file mode 100644 index 000000000..d96eab686 --- /dev/null +++ b/articles/word-subsets.md @@ -0,0 +1,293 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def wordSubsets(self, words1: List[str], words2: List[str]) -> List[str]: + res = [] + for w1 in words1: + count1 = Counter(w1) + is_subset = True + + for w2 in words2: + count2 = Counter(w2) + for c in count2: + if count2[c] > count1[c]: + is_subset = False + break + + if not is_subset: break + + if is_subset: + res.append(w1) + + return res +``` + +```java +public class Solution { + public List wordSubsets(String[] words1, String[] words2) { + List res = new ArrayList<>(); + + for (String w1 : words1) { + int[] count1 = new int[26]; + for (char c : w1.toCharArray()) count1[c - 'a']++; + + boolean isSubset = true; + for (String w2 : words2) { + int[] count2 = new int[26]; + for (char c : w2.toCharArray()) count2[c - 'a']++; + + for (int i = 0; i < 26; i++) { + if (count2[i] > count1[i]) { + isSubset = false; + break; + } + } + + if (!isSubset) break; + } + + if (isSubset) res.add(w1); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector wordSubsets(vector& words1, vector& words2) { + vector res; + + for (const string& w1 : words1) { + vector count1(26, 0); + for (char c : w1) count1[c - 'a']++; + + bool isSubset = true; + for (const string& w2 : words2) { + vector count2(26, 0); + for (char c : w2) count2[c - 'a']++; + + for (int i = 0; i < 26; i++) { + if (count2[i] > count1[i]) { + isSubset = false; + break; + } + } + + if (!isSubset) break; + } + + if (isSubset) res.push_back(w1); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} words1 + * @param {string[]} words2 + * @return {string[]} + */ + wordSubsets(words1, words2) { + const res = []; + + for (const w1 of words1) { + const count1 = Array(26).fill(0); + for (const c of w1) count1[c.charCodeAt(0) - 97]++; + + let isSubset = true; + for (const w2 of words2) { + const count2 = Array(26).fill(0); + for (const c of w2) count2[c.charCodeAt(0) - 97]++; + + for (let i = 0; i < 26; i++) { + if (count2[i] > count1[i]) { + isSubset = false; + break; + } + } + + if (!isSubset) break; + } + + if (isSubset) res.push(w1); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(N * n + N * M * m)$ +* Space complexity: + * $O(1)$ extra space, since we have at most $26$ different characters. + * $O(N * n)$ space for the output list. + +> Where $N$ is the size of the array $words1$, $n$ is the length of the longest word in $words1$, $M$ is the size of the array $words2$, and $m$ is the length of the longest word in $words2$. + +--- + +## 2. Greedy + Hash Map + +::tabs-start + +```python +class Solution: + def wordSubsets(self, words1: List[str], words2: List[str]) -> List[str]: + count_2 = defaultdict(int) + for w in words2: + count_w = Counter(w) + for c, cnt in count_w.items(): + count_2[c] = max(count_2[c], cnt) + + res = [] + for w in words1: + count_w = Counter(w) + flag = True + for c, cnt in count_2.items(): + if count_w[c] < cnt: + flag = False + break + if flag: + res.append(w) + + return res +``` + +```java +public class Solution { + public List wordSubsets(String[] words1, String[] words2) { + int[] count2 = new int[26]; + for (String w : words2) { + int[] countW = new int[26]; + for (char c : w.toCharArray()) { + countW[c - 'a']++; + } + for (int i = 0; i < 26; i++) { + count2[i] = Math.max(count2[i], countW[i]); + } + } + + List res = new ArrayList<>(); + for (String w : words1) { + int[] countW = new int[26]; + for (char c : w.toCharArray()) { + countW[c - 'a']++; + } + + boolean flag = true; + for (int i = 0; i < 26; i++) { + if (countW[i] < count2[i]) { + flag = false; + break; + } + } + + if (flag) { + res.add(w); + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector wordSubsets(vector& words1, vector& words2) { + vector count2(26, 0); + for (string& w : words2) { + vector countW(26, 0); + for (char c : w) countW[c - 'a']++; + for (int i = 0; i < 26; ++i) + count2[i] = max(count2[i], countW[i]); + } + + vector res; + for (string& w : words1) { + vector countW(26, 0); + for (char c : w) countW[c - 'a']++; + + bool flag = true; + for (int i = 0; i < 26; ++i) { + if (countW[i] < count2[i]) { + flag = false; + break; + } + } + + if (flag) res.push_back(w); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} words1 + * @param {string[]} words2 + * @return {string[]} + */ + wordSubsets(words1, words2) { + const count2 = new Array(26).fill(0); + for (let w of words2) { + const countW = new Array(26).fill(0); + for (let c of w) { + countW[c.charCodeAt(0) - 97]++; + } + for (let i = 0; i < 26; i++) { + count2[i] = Math.max(count2[i], countW[i]); + } + } + + const res = []; + for (let w of words1) { + const countW = new Array(26).fill(0); + for (let c of w) { + countW[c.charCodeAt(0) - 97]++; + } + + let flag = true; + for (let i = 0; i < 26; i++) { + if (countW[i] < count2[i]) { + flag = false; + break; + } + } + + if (flag) res.push(w); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(N * n + M * m)$ +* Space complexity: + * $O(1)$ extra space, since we have at most $26$ different characters. + * $O(N * n)$ space for the output list. + +> Where $N$ is the size of the array $words1$, $n$ is the length of the longest word in $words1$, $M$ is the size of the array $words2$, and $m$ is the length of the longest word in $words2$. \ No newline at end of file From c92da38a5b7a8a5e9b2bb3a1fa0e4338894a53ce Mon Sep 17 00:00:00 2001 From: Chiao Yang Date: Fri, 18 Apr 2025 14:45:41 +0800 Subject: [PATCH 07/12] Update 0020-valid-parentheses.py avoid using 'map' as variable name to avoid overriding a built-in Signed-off-by: Chiao Yang --- python/0020-valid-parentheses.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/python/0020-valid-parentheses.py b/python/0020-valid-parentheses.py index 4d0ae3424..ce3bf39cd 100644 --- a/python/0020-valid-parentheses.py +++ b/python/0020-valid-parentheses.py @@ -1,13 +1,13 @@ class Solution: def isValid(self, s: str) -> bool: - Map = {")": "(", "]": "[", "}": "{"} + bracketMap = {")": "(", "]": "[", "}": "{"} stack = [] for c in s: - if c not in Map: + if c not in bracketMap: stack.append(c) continue - if not stack or stack[-1] != Map[c]: + if not stack or stack[-1] != bracketMap[c]: return False stack.pop() From 525065cba2b33369f6d790f75d27f78bf480c429 Mon Sep 17 00:00:00 2001 From: Sri Hari <94112314+Srihari2222@users.noreply.github.com> Date: Sat, 19 Apr 2025 23:19:31 +0530 Subject: [PATCH 08/12] Sri Hari: Batch-6/Neetcode-All/Added-articles (#4061) * Batch-6/Neetcode-ALL/Added-articles * Batch-6/Neetcode-ALL/Added-articles --- .../analyze-user-website-visit-pattern.md | 224 ++++++++ .../binary-tree-vertical-order-traversal.md | 22 +- articles/maximum-profit-in-job-scheduling.md | 155 ++++++ articles/put-marbles-in-bags.md | 501 ++++++++++++++++++ articles/reorganize-string.md | 117 ++++ 5 files changed, 1008 insertions(+), 11 deletions(-) create mode 100644 articles/analyze-user-website-visit-pattern.md create mode 100644 articles/put-marbles-in-bags.md diff --git a/articles/analyze-user-website-visit-pattern.md b/articles/analyze-user-website-visit-pattern.md new file mode 100644 index 000000000..c43fce6ba --- /dev/null +++ b/articles/analyze-user-website-visit-pattern.md @@ -0,0 +1,224 @@ +## 1. Hash Map + +::tabs-start + +```python +class Solution: + def mostVisitedPattern(self, username: List[str], timestamp: List[int], website: List[str]) -> List[str]: + arr = list(zip(timestamp, username, website)) + arr.sort() + + mp = defaultdict(list) + for time, user, site in arr: + mp[user].append(site) + + count = defaultdict(int) + for user in mp: + patterns = set() + cur = mp[user] + for i in range(len(cur)): + for j in range(i + 1, len(cur)): + for k in range(j + 1, len(cur)): + patterns.add((cur[i], cur[j], cur[k])) + for p in patterns: + count[p] += 1 + + max_count = 0 + res = tuple() + for pattern in count: + if count[pattern] > max_count or (count[pattern] == max_count and pattern < res): + max_count = count[pattern] + res = pattern + + return list(res) +``` + +```java +public class Solution { + public List mostVisitedPattern(String[] username, int[] timestamp, String[] website) { + int n = timestamp.length; + List arr = new ArrayList<>(); + for (int i = 0; i < n; i++) arr.add(new int[]{timestamp[i], i}); + arr.sort((a, b) -> Integer.compare(a[0], b[0])); + + Map> mp = new HashMap<>(); + for (int[] p : arr) { + int idx = p[1]; + mp.computeIfAbsent(username[idx], k -> new ArrayList<>()).add(website[idx]); + } + + Map count = new HashMap<>(); + for (String user : mp.keySet()) { + List cur = mp.get(user); + Set patterns = new HashSet<>(); + for (int i = 0; i < cur.size(); i++) + for (int j = i + 1; j < cur.size(); j++) + for (int k = j + 1; k < cur.size(); k++) + patterns.add(cur.get(i) + "#" + cur.get(j) + "#" + cur.get(k)); + for (String p : patterns) + count.put(p, count.getOrDefault(p, 0) + 1); + } + + String res = ""; + int max_count = 0; + for (String p : count.keySet()) { + int c = count.get(p); + if (c > max_count || (c == max_count && p.compareTo(res) < 0)) { + max_count = c; + res = p; + } + } + return Arrays.asList(res.split("#")); + } +} +``` + +```cpp +class Solution { +public: + vector mostVisitedPattern(vector& username, vector& timestamp, vector& website) { + int n = timestamp.size(); + vector> arr; + for (int i = 0; i < n; ++i) arr.push_back({timestamp[i], i}); + sort(arr.begin(), arr.end(), + [](auto& a, auto& b){ return a.first < b.first; }); + + unordered_map> mp; + for (auto& p : arr) mp[username[p.second]].push_back(website[p.second]); + + unordered_map count; + for (auto& kv : mp) { + auto& cur = kv.second; + unordered_set patterns; + for (int i = 0; i < (int)cur.size(); ++i) + for (int j = i + 1; j < (int)cur.size(); ++j) + for (int k = j + 1; k < (int)cur.size(); ++k) + patterns.insert(cur[i] + "#" + cur[j] + "#" + cur[k]); + for (auto& p : patterns) ++count[p]; + } + + int maxCnt = 0; + string res; + for (auto& kv : count) + if (kv.second > maxCnt || + (kv.second == maxCnt && (res.empty() || kv.first < res))) { + maxCnt = kv.second; + res = kv.first; + } + + vector ans; + string tmp; + for (char ch : res) { + if (ch == '#') { + ans.push_back(tmp); + tmp.clear(); + } else { + tmp += ch; + } + } + ans.push_back(tmp); + return ans; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} username + * @param {number[]} timestamp + * @param {string[]} website + * @return {string[]} + */ + mostVisitedPattern(username, timestamp, website) { + const n = timestamp.length; + const arr = []; + for (let i = 0; i < n; i++) arr.push([timestamp[i], i]); + arr.sort((a, b) => a[0] - b[0]); + + const mp = new Map(); + for (const [, idx] of arr) { + const user = username[idx], site = website[idx]; + if (!mp.has(user)) mp.set(user, []); + mp.get(user).push(site); + } + + const count = new Map(); + for (const user of mp.keys()) { + const cur = mp.get(user); + const patterns = new Set(); + for (let i = 0; i < cur.length; i++) { + for (let j = i + 1; j < cur.length; j++) { + for (let k = j + 1; k < cur.length; k++) { + patterns.add(`${cur[i]}#${cur[j]}#${cur[k]}`); + } + } + } + for (const p of patterns) { + count.set(p, (count.get(p) || 0) + 1); + } + } + + let maxCnt = 0, res = ""; + for (const [pat, c] of count.entries()) { + if (c > maxCnt || (c === maxCnt && (res === "" || pat < res))) { + maxCnt = c; + res = pat; + } + } + return res.split("#"); + } +} +``` + +```csharp +public class Solution { + public List MostVisitedPattern(string[] username, int[] timestamp, string[] website) { + int n = timestamp.Length; + var arr = new List<(int t, int i)>(); + for (int i = 0; i < n; i++) arr.Add((timestamp[i], i)); + arr.Sort((a, b) => a.t.CompareTo(b.t)); + + var mp = new Dictionary>(); + foreach (var (t, idx) in arr) { + string user = username[idx], site = website[idx]; + if (!mp.ContainsKey(user)) mp[user] = new List(); + mp[user].Add(site); + } + + var count = new Dictionary(); + foreach (var kv in mp) { + var cur = kv.Value; + var patterns = new HashSet(); + for (int i = 0; i < cur.Count; i++) + for (int j = i + 1; j < cur.Count; j++) + for (int k = j + 1; k < cur.Count; k++) + patterns.Add($"{cur[i]}#{cur[j]}#{cur[k]}"); + foreach (var p in patterns) { + count[p] = count.ContainsKey(p) ? count[p] + 1 : 1; + } + } + + int maxCnt = 0; + string res = ""; + foreach (var kv in count) { + if (kv.Value > maxCnt || + (kv.Value == maxCnt && + (res == "" || string.Compare(kv.Key, res, StringComparison.Ordinal) < 0))) { + maxCnt = kv.Value; + res = kv.Key; + } + } + return new List(res.Split('#')); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n + n * u + n ^ 3 * w)$ +* Space complexity: $O(n * u + n ^ 3 * w)$ + +> Where $n$ is the size of the array $timestamp$, $u$ is the maximum length of any string in the array $username$, and $w$ is the maximum length of any string in the array $website$. \ No newline at end of file diff --git a/articles/binary-tree-vertical-order-traversal.md b/articles/binary-tree-vertical-order-traversal.md index 506fdad2c..c66e08d0b 100644 --- a/articles/binary-tree-vertical-order-traversal.md +++ b/articles/binary-tree-vertical-order-traversal.md @@ -151,8 +151,8 @@ class Solution { * } */ public class Solution { - public IList> VerticalOrder(TreeNode root) { - if (root == null) return new List>(); + public List> VerticalOrder(TreeNode root) { + if (root == null) return new List>(); var cols = new SortedDictionary>(); var queue = new Queue<(TreeNode node, int pos)>(); @@ -169,7 +169,7 @@ public class Solution { if (node.right != null) queue.Enqueue((node.right, pos + 1)); } - return cols.Values.ToList>(); + return cols.Values.ToList>(); } } ``` @@ -354,10 +354,10 @@ class Solution { public class Solution { private SortedDictionary> cols = new(); - public IList> VerticalOrder(TreeNode root) { + public List> VerticalOrder(TreeNode root) { DFS(root, 0, 0); - List> res = new(); + List> res = new(); foreach (var entry in cols) { var list = entry.Value.OrderBy(x => x.Item1).Select(x => x.Item2).ToList(); res.Add(list); @@ -565,8 +565,8 @@ class Solution { * } */ public class Solution { - public IList> VerticalOrder(TreeNode root) { - if (root == null) return new List>(); + public List> VerticalOrder(TreeNode root) { + if (root == null) return new List>(); Dictionary> cols = new(); Queue<(TreeNode node, int col)> queue = new(); @@ -585,7 +585,7 @@ public class Solution { if (node.right != null) queue.Enqueue((node.right, col + 1)); } - var res = new List>(); + var res = new List>(); for (int c = minCol; c <= maxCol; c++) { res.Add(cols[c]); } @@ -801,10 +801,10 @@ public class Solution { private Dictionary> cols = new(); private int minCol = 0, maxCol = 0; - public IList> VerticalOrder(TreeNode root) { - if (root == null) return new List>(); + public List> VerticalOrder(TreeNode root) { + if (root == null) return new List>(); DFS(root, 0, 0); - var res = new List>(); + var res = new List>(); for (int c = minCol; c <= maxCol; c++) { var list = cols.ContainsKey(c) ? cols[c] : new List<(int, int)>(); diff --git a/articles/maximum-profit-in-job-scheduling.md b/articles/maximum-profit-in-job-scheduling.md index 181614b62..0c0d40541 100644 --- a/articles/maximum-profit-in-job-scheduling.md +++ b/articles/maximum-profit-in-job-scheduling.md @@ -155,6 +155,42 @@ class Solution { } ``` +```csharp +public class Solution { + public int JobScheduling(int[] startTime, int[] endTime, int[] profit) { + int n = startTime.Length; + var intervals = new List<(int start, int end, int profit)>(); + + for (int i = 0; i < n; i++) { + intervals.Add((startTime[i], endTime[i], profit[i])); + } + + intervals.Sort((a, b) => a.start.CompareTo(b.start)); + Dictionary cache = new(); + + int Dfs(int i) { + if (i == n) return 0; + if (cache.ContainsKey(i)) return cache[i]; + + // Option 1: don't include + int res = Dfs(i + 1); + + // Option 2: include current job + int j = i + 1; + while (j < n && intervals[j].start < intervals[i].end) { + j++; + } + + res = Math.Max(res, intervals[i].profit + Dfs(j)); + cache[i] = res; + return res; + } + + return Dfs(0); + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -328,6 +364,48 @@ class Solution { } ``` +```csharp +public class Solution { + private int[][] intervals; + private int[] cache; + + public int JobScheduling(int[] startTime, int[] endTime, int[] profit) { + int n = startTime.Length; + intervals = new int[n][]; + cache = new int[n]; + Array.Fill(cache, -1); + + for (int i = 0; i < n; i++) { + intervals[i] = new int[] { startTime[i], endTime[i], profit[i] }; + } + + Array.Sort(intervals, (a, b) => a[0].CompareTo(b[0])); + return Dfs(0); + } + + private int Dfs(int i) { + if (i == intervals.Length) return 0; + if (cache[i] != -1) return cache[i]; + + int res = Dfs(i + 1); + + int left = i + 1, right = intervals.Length, j = intervals.Length; + while (left < right) { + int mid = left + (right - left) / 2; + if (intervals[mid][0] >= intervals[i][1]) { + j = mid; + right = mid; + } else { + left = mid + 1; + } + } + + cache[i] = Math.Max(res, intervals[i][2] + Dfs(j)); + return cache[i]; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -517,6 +595,52 @@ class Solution { } ``` +```csharp +public class Solution { + private int[] startTime, endTime, profit, cache; + private int[] index; + private int n; + + public int JobScheduling(int[] startTime, int[] endTime, int[] profit) { + this.n = startTime.Length; + this.startTime = startTime; + this.endTime = endTime; + this.profit = profit; + this.index = new int[n]; + this.cache = new int[n]; + Array.Fill(cache, -1); + + for (int i = 0; i < n; i++) { + index[i] = i; + } + + Array.Sort(index, (a, b) => startTime[a].CompareTo(startTime[b])); + + return Dfs(0); + } + + private int Dfs(int i) { + if (i == n) return 0; + if (cache[i] != -1) return cache[i]; + + int res = Dfs(i + 1); + + int left = i + 1, right = n, j = n; + while (left < right) { + int mid = left + (right - left) / 2; + if (startTime[index[mid]] >= endTime[index[i]]) { + j = mid; + right = mid; + } else { + left = mid + 1; + } + } + + return cache[i] = Math.Max(res, profit[index[i]] + Dfs(j)); + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -647,6 +771,37 @@ class Solution { } ``` +```csharp +public class Solution { + public int JobScheduling(int[] startTime, int[] endTime, int[] profit) { + int n = startTime.Length; + int[] index = new int[n]; + for (int i = 0; i < n; i++) index[i] = i; + + Array.Sort(index, (a, b) => startTime[a].CompareTo(startTime[b])); + + int[] dp = new int[n + 1]; + + for (int i = n - 1; i >= 0; i--) { + int left = i + 1, right = n, j = n; + while (left < right) { + int mid = left + (right - left) / 2; + if (startTime[index[mid]] >= endTime[index[i]]) { + j = mid; + right = mid; + } else { + left = mid + 1; + } + } + + dp[i] = Math.Max(dp[i + 1], profit[index[i]] + dp[j]); + } + + return dp[0]; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/put-marbles-in-bags.md b/articles/put-marbles-in-bags.md new file mode 100644 index 000000000..a0abf8a29 --- /dev/null +++ b/articles/put-marbles-in-bags.md @@ -0,0 +1,501 @@ +## 1. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def putMarbles(self, weights: List[int], k: int) -> int: + n = len(weights) + cache = {} + + def dfs(i, k): + if (i, k) in cache: + return cache[(i, k)] + if k == 0: + return [0, 0] + if i == n - 1 or n - i - 1 < k: + return [-float("inf"), float("inf")] + + res = [0, float("inf")] # [maxScore, minScore] + + # make partition + cur = dfs(i + 1, k - 1) + res[0] = max(res[0], weights[i] + weights[i + 1] + cur[0]) + res[1] = min(res[1], weights[i] + weights[i + 1] + cur[1]) + + # skip + cur = dfs(i + 1, k) + res[0] = max(res[0], cur[0]) + res[1] = min(res[1], cur[1]) + + cache[(i, k)] = res + return res + + ans = dfs(0, k - 1) + return ans[0] - ans[1] +``` + +```java +public class Solution { + Map cache = new HashMap<>(); + + public long putMarbles(int[] weights, int k) { + int n = weights.length; + long[] ans = dfs(0, k - 1, weights, n); + return ans[0] - ans[1]; + } + + private long[] dfs(int i, int k, int[] weights, int n) { + String key = i + "," + k; + if (cache.containsKey(key)) return cache.get(key); + if (k == 0) return new long[]{0L, 0L}; + if (i == n - 1 || n - i - 1 < k) { + return new long[]{(long)-1e15, (long)1e15}; + } + + long[] res = new long[]{0L, (long)1e15}; + + long[] cur = dfs(i + 1, k - 1, weights, n); + res[0] = Math.max(res[0], weights[i] + weights[i + 1] + cur[0]); + res[1] = Math.min(res[1], weights[i] + weights[i + 1] + cur[1]); + + cur = dfs(i + 1, k, weights, n); + res[0] = Math.max(res[0], cur[0]); + res[1] = Math.min(res[1], cur[1]); + + cache.put(key, res); + return res; + } +} +``` + +```cpp +class Solution { +public: + unordered_map> cache; + + long long putMarbles(vector& weights, int k) { + int n = weights.size(); + auto ans = dfs(0, k - 1, weights, n); + return ans.first - ans.second; + } + + pair dfs(int i, int k, vector& weights, int n) { + string key = to_string(i) + "," + to_string(k); + if (cache.count(key)) return cache[key]; + if (k == 0) return {0LL, 0LL}; + if (i == n - 1 || n - i - 1 < k) { + return {-1000000000000000LL, 1000000000000000LL}; + } + + pair res = {0LL, 1000000000000000LL}; + + auto cur = dfs(i + 1, k - 1, weights, n); + res.first = max(res.first, (long long)weights[i] + weights[i + 1] + cur.first); + res.second = min(res.second, (long long)weights[i] + weights[i + 1] + cur.second); + + cur = dfs(i + 1, k, weights, n); + res.first = max(res.first, cur.first); + res.second = min(res.second, cur.second); + + return cache[key] = res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} weights + * @param {number} k + * @return {number} + */ + putMarbles(weights, k) { + const n = weights.length; + const cache = new Map(); + + const dfs = (i, k) => { + const key = `${i},${k}`; + if (cache.has(key)) return cache.get(key); + if (k === 0) return [0, 0]; + if (i === n - 1 || n - i - 1 < k) return [-1e15, 1e15]; + + let res = [0, 1e15]; + + let cur = dfs(i + 1, k - 1); + res[0] = Math.max(res[0], weights[i] + weights[i + 1] + cur[0]); + res[1] = Math.min(res[1], weights[i] + weights[i + 1] + cur[1]); + + cur = dfs(i + 1, k); + res[0] = Math.max(res[0], cur[0]); + res[1] = Math.min(res[1], cur[1]); + + cache.set(key, res); + return res; + }; + + const ans = dfs(0, k - 1); + return ans[0] - ans[1]; + } +} +``` + +```csharp +public class Solution { + Dictionary cache = new Dictionary(); + + public long PutMarbles(int[] weights, int k) { + int n = weights.Length; + long[] ans = Dfs(0, k - 1, weights, n); + return (int)(ans[0] - ans[1]); + } + + private long[] Dfs(int i, int k, int[] weights, int n) { + string key = $"{i},{k}"; + if (cache.ContainsKey(key)) return cache[key]; + if (k == 0) return new long[] { 0L, 0L }; + if (i == n - 1 || n - i - 1 < k) { + return new long[] { -1000000000000000L, 1000000000000000L }; + } + + long[] res = new long[] { 0L, 1000000000000000L }; + + long[] cur = Dfs(i + 1, k - 1, weights, n); + res[0] = Math.Max(res[0], weights[i] + weights[i + 1] + cur[0]); + res[1] = Math.Min(res[1], weights[i] + weights[i + 1] + cur[1]); + + cur = Dfs(i + 1, k, weights, n); + res[0] = Math.Max(res[0], cur[0]); + res[1] = Math.Min(res[1], cur[1]); + + cache[key] = res; + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * k)$ +* Space complexity: $O(n * k)$ + +> Where $n$ is the number of marbles, and $k$ is the number of bags. + +--- + +## 2. Greedy + Sorting + +::tabs-start + +```python +class Solution: + def putMarbles(self, weights: List[int], k: int) -> int: + if k == 1: + return 0 + + splits = [] + for i in range(len(weights) - 1): + splits.append(weights[i] + weights[i + 1]) + + splits.sort() + i = k - 1 + + max_score = sum(splits[-i:]) + min_score = sum(splits[:i]) + return max_score - min_score +``` + +```java +public class Solution { + public long putMarbles(int[] weights, int k) { + if (k == 1) return 0L; + + int n = weights.length; + List splits = new ArrayList<>(); + + for (int i = 0; i < n - 1; i++) { + splits.add(weights[i] + weights[i + 1]); + } + + Collections.sort(splits); + int i = k - 1; + long maxScore = 0, minScore = 0; + + for (int j = 0; j < i; j++) minScore += splits.get(j); + for (int j = splits.size() - i; j < splits.size(); j++) { + maxScore += splits.get(j); + } + + return maxScore - minScore; + } +} +``` + +```cpp +class Solution { +public: + long long putMarbles(vector& weights, int k) { + if (k == 1) return 0LL; + + int n = weights.size(); + vector splits; + + for (int i = 0; i < n - 1; ++i) { + splits.push_back(weights[i] + weights[i + 1]); + } + + sort(splits.begin(), splits.end()); + int i = k - 1; + long long minScore = 0, maxScore = 0; + + for (int j = 0; j < i; ++j) minScore += splits[j]; + for (int j = splits.size() - i; j < splits.size(); ++j) { + maxScore += splits[j]; + } + + return maxScore - minScore; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} weights + * @param {number} k + * @return {number} + */ + putMarbles(weights, k) { + if (k === 1) return 0; + + const splits = []; + for (let i = 0; i < weights.length - 1; i++) { + splits.push(weights[i] + weights[i + 1]); + } + + splits.sort((a, b) => a - b); + const i = k - 1; + + let minScore = 0, maxScore = 0; + for (let j = 0; j < i; j++) minScore += splits[j]; + for (let j = splits.length - i; j < splits.length; j++) { + maxScore += splits[j]; + } + + return maxScore - minScore; + } +} +``` + +```csharp +public class Solution { + public long PutMarbles(int[] weights, int k) { + if (k == 1) return 0L; + + int n = weights.Length; + List splits = new List(); + + for (int i = 0; i < n - 1; i++) { + splits.Add(weights[i] + weights[i + 1]); + } + + splits.Sort(); + int iVal = k - 1; + long minScore = 0, maxScore = 0; + + for (int j = 0; j < iVal; j++) minScore += splits[j]; + for (int j = splits.Count - iVal; j < splits.Count; j++) { + maxScore += splits[j]; + } + + return maxScore - minScore; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(n)$ + +> Where $n$ is the number of marbles, and $k$ is the number of bags. + +--- + +## 3. Heap + +::tabs-start + +```python +class Solution: + def putMarbles(self, weights: List[int], k: int) -> int: + if k == 1: + return 0 + + max_heap = [] + min_heap = [] + + for i in range(len(weights) - 1): + split = weights[i] + weights[i + 1] + + if len(max_heap) < k - 1: + heapq.heappush(max_heap, split) + else: + heapq.heappushpop(max_heap, split) + + if len(min_heap) < k - 1: + heapq.heappush(min_heap, -split) + else: + heapq.heappushpop(min_heap, -split) + + max_score = sum(max_heap) + min_score = -sum(min_heap) + return max_score - min_score +``` + +```java +public class Solution { + public long putMarbles(int[] weights, int k) { + if (k == 1) return 0L; + + PriorityQueue maxHeap = new PriorityQueue<>(); + PriorityQueue minHeap = new PriorityQueue<>(Collections.reverseOrder()); + + for (int i = 0; i < weights.length - 1; i++) { + int split = weights[i] + weights[i + 1]; + + if (maxHeap.size() < k - 1) maxHeap.offer(split); + else if (split > maxHeap.peek()) { + maxHeap.poll(); + maxHeap.offer(split); + } + + if (minHeap.size() < k - 1) minHeap.offer(split); + else if (split < minHeap.peek()) { + minHeap.poll(); + minHeap.offer(split); + } + } + + long maxScore = 0, minScore = 0; + for (int val : maxHeap) maxScore += val; + for (int val : minHeap) minScore += val; + + return maxScore - minScore; + } +} +``` + +```cpp +class Solution { +public: + long long putMarbles(vector& weights, int k) { + if (k == 1) return 0LL; + + priority_queue, greater> maxHeap; + priority_queue minHeap; + + for (int i = 0; i < weights.size() - 1; ++i) { + int split = weights[i] + weights[i + 1]; + + if ((int)maxHeap.size() < k - 1) maxHeap.push(split); + else if (split > maxHeap.top()) { + maxHeap.pop(); + maxHeap.push(split); + } + + if ((int)minHeap.size() < k - 1) minHeap.push(split); + else if (split < minHeap.top()) { + minHeap.pop(); + minHeap.push(split); + } + } + + long long maxScore = 0, minScore = 0; + while (!maxHeap.empty()) { + maxScore += maxHeap.top(); + maxHeap.pop(); + } + while (!minHeap.empty()) { + minScore += minHeap.top(); + minHeap.pop(); + } + + return maxScore - minScore; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} weights + * @param {number} k + * @return {number} + */ + putMarbles(weights, k) { + if (k === 1) return 0; + + const minHeap = new MinPriorityQueue(); + const maxHeap = new MaxPriorityQueue(); + + for (let i = 0; i < weights.length - 1; i++) { + const sum = weights[i] + weights[i + 1]; + + minHeap.enqueue(sum); + if (minHeap.size() > k - 1) minHeap.dequeue(); + + maxHeap.enqueue(sum); + if (maxHeap.size() > k - 1) maxHeap.dequeue(); + } + + let maxScore = 0, minScore = 0; + while (!minHeap.isEmpty()) maxScore += minHeap.dequeue(); + while (!maxHeap.isEmpty()) minScore += maxHeap.dequeue(); + + return maxScore - minScore; + } +} +``` + +```csharp +public class Solution { + public long PutMarbles(int[] weights, int k) { + if (k == 1) return 0L; + + var maxHeap = new PriorityQueue(); + var minHeap = new PriorityQueue( + Comparer.Create((a, b) => b.CompareTo(a)) + ); + + for (int i = 0; i < weights.Length - 1; i++) { + int split = weights[i] + weights[i + 1]; + + maxHeap.Enqueue(split, split); + if (maxHeap.Count > k - 1) maxHeap.Dequeue(); + + minHeap.Enqueue(split, split); + if (minHeap.Count > k - 1) minHeap.Dequeue(); + } + + long maxScore = 0, minScore = 0; + while (maxHeap.Count > 0) maxScore += maxHeap.Dequeue(); + while (minHeap.Count > 0) minScore += minHeap.Dequeue(); + + return maxScore - minScore; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log k)$ +* Space complexity: $O(k)$ + +> Where $n$ is the number of marbles, and $k$ is the number of bags. \ No newline at end of file diff --git a/articles/reorganize-string.md b/articles/reorganize-string.md index 57d672327..868c78dca 100644 --- a/articles/reorganize-string.md +++ b/articles/reorganize-string.md @@ -183,6 +183,42 @@ class Solution { } ``` +```csharp +public class Solution { + public string ReorganizeString(string s) { + int[] freq = new int[26]; + foreach (char c in s) { + freq[c - 'a']++; + } + + int maxFreq = freq.Max(); + if (maxFreq > (s.Length + 1) / 2) { + return ""; + } + + List res = new List(); + while (res.Count < s.Length) { + int maxIdx = Array.IndexOf(freq, freq.Max()); + char ch = (char)(maxIdx + 'a'); + res.Add(ch); + freq[maxIdx]--; + + if (freq[maxIdx] == 0) continue; + + int tmp = freq[maxIdx]; + freq[maxIdx] = int.MinValue; + int nextMaxIdx = Array.IndexOf(freq, freq.Max()); + char nextCh = (char)(nextMaxIdx + 'a'); + res.Add(nextCh); + freq[maxIdx] = tmp; + freq[nextMaxIdx]--; + } + + return new string(res.ToArray()); + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -352,6 +388,45 @@ class Solution { } ``` +```csharp +public class Solution { + public string ReorganizeString(string s) { + Dictionary count = new(); + foreach (char c in s) { + if (!count.ContainsKey(c)) count[c] = 0; + count[c]++; + } + + PriorityQueue maxHeap = new(); + foreach (var kvp in count) { + maxHeap.Enqueue(new int[] { kvp.Value, kvp.Key }, -kvp.Value); + } + + string res = ""; + int[] prev = null; + + while (maxHeap.Count > 0 || prev != null) { + if (prev != null && maxHeap.Count == 0) return ""; + + int[] curr = maxHeap.Dequeue(); + res += (char)curr[1]; + curr[0]--; + + if (prev != null) { + maxHeap.Enqueue(prev, -prev[0]); + prev = null; + } + + if (curr[0] > 0) { + prev = curr; + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -536,6 +611,48 @@ class Solution { } ``` +```csharp +public class Solution { + public string ReorganizeString(string s) { + int[] freq = new int[26]; + foreach (char c in s) { + freq[c - 'a']++; + } + + int maxIdx = 0; + for (int i = 1; i < 26; i++) { + if (freq[i] > freq[maxIdx]) { + maxIdx = i; + } + } + + int maxFreq = freq[maxIdx]; + if (maxFreq > (s.Length + 1) / 2) return ""; + + char[] res = new char[s.Length]; + int idx = 0; + char maxChar = (char)(maxIdx + 'a'); + + while (freq[maxIdx] > 0) { + res[idx] = maxChar; + idx += 2; + freq[maxIdx]--; + } + + for (int i = 0; i < 26; i++) { + while (freq[i] > 0) { + if (idx >= s.Length) idx = 1; + res[idx] = (char)(i + 'a'); + idx += 2; + freq[i]--; + } + } + + return new string(res); + } +} +``` + ::tabs-end ### Time & Space Complexity From 1c50915ffda8db92d3b40a8e0292718903f44837 Mon Sep 17 00:00:00 2001 From: Sri Hari <94112314+Srihari2222@users.noreply.github.com> Date: Mon, 28 Apr 2025 22:58:15 +0530 Subject: [PATCH 09/12] Sri Hari: Batch-6/Neetcode-All/Added-articles (#4074) * Batch-6/Neetcode-ALL/Added-articles * Batch-6/Neetcode-ALL/Added-articles --- .../best-time-to-buy-and-sell-stock-ii.md | 109 +++++++ articles/boats-to-save-people.md | 59 ++++ articles/concatenation-of-array.md | 30 +- articles/first-missing-positive.md | 131 +++++++++ articles/longest-common-prefix.md | 120 +++++++- articles/majority-element-ii.md | 149 ++++++++++ articles/majority-element.md | 112 ++++++++ articles/merge-sorted-array.md | 74 +++++ articles/merge-strings-alternately.md | 64 +++++ articles/remove-element.md | 49 ++++ articles/rotate-array.md | 96 +++++++ articles/sort-an-array.md | 267 ++++++++++++++++++ articles/sort-colors.md | 93 ++++++ articles/subarray-sum-equals-k.md | 44 +++ 14 files changed, 1395 insertions(+), 2 deletions(-) diff --git a/articles/best-time-to-buy-and-sell-stock-ii.md b/articles/best-time-to-buy-and-sell-stock-ii.md index e6abb861a..6562e3544 100644 --- a/articles/best-time-to-buy-and-sell-stock-ii.md +++ b/articles/best-time-to-buy-and-sell-stock-ii.md @@ -85,6 +85,30 @@ class Solution { } ``` +```csharp +public class Solution { + public int MaxProfit(int[] prices) { + return Rec(prices, 0, false); + } + + private int Rec(int[] prices, int i, bool bought) { + if (i == prices.Length) { + return 0; + } + + int res = Rec(prices, i + 1, bought); + + if (bought) { + res = Math.Max(res, prices[i] + Rec(prices, i + 1, false)); + } else { + res = Math.Max(res, -prices[i] + Rec(prices, i + 1, true)); + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -211,6 +235,43 @@ class Solution { } ``` +```csharp +public class Solution { + public int MaxProfit(int[] prices) { + int n = prices.Length; + int[,] dp = new int[n, 2]; + + for (int i = 0; i < n; i++) { + dp[i, 0] = -1; + dp[i, 1] = -1; + } + + return Rec(prices, 0, 0, dp); + } + + private int Rec(int[] prices, int i, int bought, int[,] dp) { + if (i == prices.Length) { + return 0; + } + + if (dp[i, bought] != -1) { + return dp[i, bought]; + } + + int res = Rec(prices, i + 1, bought, dp); + + if (bought == 1) { + res = Math.Max(res, prices[i] + Rec(prices, i + 1, 0, dp)); + } else { + res = Math.Max(res, -prices[i] + Rec(prices, i + 1, 1, dp)); + } + + dp[i, bought] = res; + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -290,6 +351,22 @@ class Solution { } ``` +```csharp +public class Solution { + public int MaxProfit(int[] prices) { + int n = prices.Length; + int[,] dp = new int[n + 1, 2]; + + for (int i = n - 1; i >= 0; i--) { + dp[i, 0] = Math.Max(dp[i + 1, 0], -prices[i] + dp[i + 1, 1]); + dp[i, 1] = Math.Max(dp[i + 1, 1], prices[i] + dp[i + 1, 0]); + } + + return dp[0, 0]; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -378,6 +455,24 @@ class Solution { } ``` +```csharp +public class Solution { + public int MaxProfit(int[] prices) { + int nextBuy = 0, nextSell = 0; + int curBuy = 0, curSell = 0; + + for (int i = prices.Length - 1; i >= 0; i--) { + curBuy = Math.Max(nextBuy, -prices[i] + nextSell); + curSell = Math.Max(nextSell, prices[i] + nextBuy); + nextBuy = curBuy; + nextSell = curSell; + } + + return curBuy; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -450,6 +545,20 @@ class Solution { } ``` +```csharp +public class Solution { + public int MaxProfit(int[] prices) { + int profit = 0; + for (int i = 1; i < prices.Length; i++) { + if (prices[i] > prices[i - 1]) { + profit += prices[i] - prices[i - 1]; + } + } + return profit; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/boats-to-save-people.md b/articles/boats-to-save-people.md index 8abd6a9a7..ce0498e89 100644 --- a/articles/boats-to-save-people.md +++ b/articles/boats-to-save-people.md @@ -73,6 +73,27 @@ class Solution { } ``` +```csharp +public class Solution { + public int NumRescueBoats(int[] people, int limit) { + Array.Sort(people); + int res = 0, l = 0, r = people.Length - 1; + + while (l <= r) { + int remain = limit - people[r]; + r--; + res++; + + if (l <= r && remain >= people[l]) { + l++; + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -211,6 +232,44 @@ class Solution { } ``` +```csharp +public class Solution { + public int NumRescueBoats(int[] people, int limit) { + int m = 0; + foreach (int p in people) { + m = Math.Max(m, p); + } + + int[] count = new int[m + 1]; + foreach (int p in people) { + count[p]++; + } + + int idx = 0, iVal = 1; + while (idx < people.Length) { + while (count[iVal] == 0) { + iVal++; + } + people[idx] = iVal; + count[iVal]--; + idx++; + } + + int res = 0, l = 0, r = people.Length - 1; + while (l <= r) { + int remain = limit - people[r]; + r--; + res++; + if (l <= r && remain >= people[l]) { + l++; + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/concatenation-of-array.md b/articles/concatenation-of-array.md index 3ea2a1e68..f3740ed68 100644 --- a/articles/concatenation-of-array.md +++ b/articles/concatenation-of-array.md @@ -15,7 +15,7 @@ class Solution: ```java public class Solution { public int[] getConcatenation(int[] nums) { - int[] ans=new int[2 * nums.length]; + int[] ans = new int[2 * nums.length]; int idx = 0; for (int i = 0; i < 2; i++) { for (int num : nums) { @@ -60,6 +60,21 @@ class Solution { } ``` +```csharp +public class Solution { + public int[] GetConcatenation(int[] nums) { + int[] ans = new int[2 * nums.Length]; + int idx = 0; + for (int i = 0; i < 2; i++) { + foreach (int num in nums) { + ans[idx++] = num; + } + } + return ans; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -127,6 +142,19 @@ class Solution { } ``` +```csharp +public class Solution { + public int[] GetConcatenation(int[] nums) { + int n = nums.Length; + int[] ans = new int[2 * n]; + for (int i = 0; i < n; i++) { + ans[i] = ans[i + n] = nums[i]; + } + return ans; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/first-missing-positive.md b/articles/first-missing-positive.md index f0bef0643..09f5f9678 100644 --- a/articles/first-missing-positive.md +++ b/articles/first-missing-positive.md @@ -80,6 +80,31 @@ class Solution { } ``` +```csharp +public class Solution { + public int FirstMissingPositive(int[] nums) { + int missing = 1; + + while (true) { + bool found = false; + + foreach (int num in nums) { + if (num == missing) { + found = true; + break; + } + } + + if (!found) { + return missing; + } + + missing++; + } + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -183,6 +208,29 @@ class Solution { } ``` +```csharp +public class Solution { + public int FirstMissingPositive(int[] nums) { + int n = nums.Length; + bool[] seen = new bool[n]; + + foreach (int num in nums) { + if (num > 0 && num <= n) { + seen[num - 1] = true; + } + } + + for (int num = 1; num <= n; num++) { + if (!seen[num - 1]) { + return num; + } + } + + return n + 1; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -257,6 +305,23 @@ class Solution { } ``` +```csharp +public class Solution { + public int FirstMissingPositive(int[] nums) { + Array.Sort(nums); + int missing = 1; + + foreach (int num in nums) { + if (num > 0 && num == missing) { + missing++; + } + } + + return missing; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -396,6 +461,39 @@ class Solution { } ``` +```csharp +public class Solution { + public int FirstMissingPositive(int[] nums) { + int n = nums.Length; + + for (int i = 0; i < n; i++) { + if (nums[i] < 0) { + nums[i] = 0; + } + } + + for (int i = 0; i < n; i++) { + int val = Math.Abs(nums[i]); + if (val >= 1 && val <= n) { + if (nums[val - 1] > 0) { + nums[val - 1] *= -1; + } else if (nums[val - 1] == 0) { + nums[val - 1] = -(n + 1); + } + } + } + + for (int i = 0; i < n; i++) { + if (nums[i] >= 0) { + return i + 1; + } + } + + return n + 1; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -528,6 +626,39 @@ class Solution { } ``` +```csharp +public class Solution { + public int FirstMissingPositive(int[] nums) { + int n = nums.Length; + int i = 0; + + while (i < n) { + if (nums[i] <= 0 || nums[i] > n) { + i++; + continue; + } + + int index = nums[i] - 1; + if (nums[i] != nums[index]) { + int temp = nums[i]; + nums[i] = nums[index]; + nums[index] = temp; + } else { + i++; + } + } + + for (i = 0; i < n; i++) { + if (nums[i] != i + 1) { + return i + 1; + } + } + + return n + 1; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/longest-common-prefix.md b/articles/longest-common-prefix.md index e5941f9a6..936377d1c 100644 --- a/articles/longest-common-prefix.md +++ b/articles/longest-common-prefix.md @@ -78,6 +78,27 @@ class Solution { } ``` +```csharp +public class Solution { + public string LongestCommonPrefix(string[] strs) { + string prefix = strs[0]; + + for (int i = 1; i < strs.Length; i++) { + int j = 0; + while (j < Math.Min(prefix.Length, strs[i].Length)) { + if (prefix[j] != strs[i][j]) { + break; + } + j++; + } + prefix = prefix.Substring(0, j); + } + + return prefix; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -153,6 +174,21 @@ class Solution { } ``` +```csharp +public class Solution { + public string LongestCommonPrefix(string[] strs) { + for (int i = 0; i < strs[0].Length; i++) { + foreach (string s in strs) { + if (i == s.Length || s[i] != strs[0][i]) { + return s.Substring(0, i); + } + } + } + return strs[0]; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -242,6 +278,30 @@ class Solution { } ``` +```csharp +public class Solution { + public string LongestCommonPrefix(string[] strs) { + if (strs.Length == 1) { + return strs[0]; + } + + Array.Sort(strs); + string first = strs[0]; + string last = strs[strs.Length - 1]; + + int i = 0; + while (i < Math.Min(first.Length, last.Length)) { + if (first[i] != last[i]) { + return first.Substring(0, i); + } + i++; + } + + return first; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -493,6 +553,64 @@ class Solution { } ``` +```csharp +public class TrieNode { + public Dictionary Children = new Dictionary(); +} + +public class Trie { + public TrieNode Root; + + public Trie() { + Root = new TrieNode(); + } + + public void Insert(string word) { + TrieNode node = Root; + foreach (char c in word) { + if (!node.Children.ContainsKey(c)) { + node.Children[c] = new TrieNode(); + } + node = node.Children[c]; + } + } + + public int Lcp(string word, int prefixLen) { + TrieNode node = Root; + for (int i = 0; i < Math.Min(word.Length, prefixLen); i++) { + if (!node.Children.ContainsKey(word[i])) { + return i; + } + node = node.Children[word[i]]; + } + return Math.Min(word.Length, prefixLen); + } +} + +public class Solution { + public string LongestCommonPrefix(string[] strs) { + if (strs.Length == 1) return strs[0]; + + int mini = 0; + for (int i = 1; i < strs.Length; i++) { + if (strs[i].Length < strs[mini].Length) { + mini = i; + } + } + + Trie trie = new Trie(); + trie.Insert(strs[mini]); + + int prefixLen = strs[mini].Length; + for (int i = 0; i < strs.Length; i++) { + prefixLen = trie.Lcp(strs[i], prefixLen); + } + + return strs[0].Substring(0, prefixLen); + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -500,4 +618,4 @@ class Solution { * Time complexity: $O(n * m)$ * Space complexity: $O(n)$ -> Where $n$ is the length of the shortest string and $m$ is the number of strings. +> Where $n$ is the length of the shortest string and $m$ is the number of strings. \ No newline at end of file diff --git a/articles/majority-element-ii.md b/articles/majority-element-ii.md index 6ba0f2fd1..aca6e49c3 100644 --- a/articles/majority-element-ii.md +++ b/articles/majority-element-ii.md @@ -72,6 +72,24 @@ class Solution { } ``` +```csharp +public class Solution { + public List MajorityElement(int[] nums) { + HashSet res = new HashSet(); + int n = nums.Length; + + foreach (int num in nums) { + int count = nums.Count(x => x == num); + if (count > n / 3) { + res.Add(num); + } + } + + return res.ToList(); + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -180,6 +198,30 @@ class Solution { } ``` +```csharp +public class Solution { + public List MajorityElement(int[] nums) { + Array.Sort(nums); + List res = new List(); + int n = nums.Length; + + int i = 0; + while (i < n) { + int j = i + 1; + while (j < n && nums[j] == nums[i]) { + j++; + } + if (j - i > n / 3) { + res.Add(nums[i]); + } + i = j; + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -271,6 +313,31 @@ class Solution { } ``` +```csharp +public class Solution { + public List MajorityElement(int[] nums) { + Dictionary count = new Dictionary(); + List res = new List(); + int n = nums.Length; + + foreach (int num in nums) { + if (!count.ContainsKey(num)) { + count[num] = 0; + } + count[num]++; + } + + foreach (var kvp in count) { + if (kvp.Value > n / 3) { + res.Add(kvp.Key); + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -444,6 +511,45 @@ class Solution { } ``` +```csharp +public class Solution { + public List MajorityElement(int[] nums) { + int n = nums.Length; + int num1 = -1, num2 = -1; + int cnt1 = 0, cnt2 = 0; + + foreach (int num in nums) { + if (num == num1) { + cnt1++; + } else if (num == num2) { + cnt2++; + } else if (cnt1 == 0) { + num1 = num; + cnt1 = 1; + } else if (cnt2 == 0) { + num2 = num; + cnt2 = 1; + } else { + cnt1--; + cnt2--; + } + } + + cnt1 = cnt2 = 0; + foreach (int num in nums) { + if (num == num1) cnt1++; + else if (num == num2) cnt2++; + } + + List res = new List(); + if (cnt1 > n / 3) res.Add(num1); + if (cnt2 > n / 3) res.Add(num2); + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -589,6 +695,49 @@ class Solution { } ``` +```csharp +public class Solution { + public List MajorityElement(int[] nums) { + Dictionary count = new Dictionary(); + + foreach (int num in nums) { + if (count.ContainsKey(num)) { + count[num]++; + } else { + count[num] = 1; + } + + if (count.Count <= 2) { + continue; + } + + Dictionary newCount = new Dictionary(); + foreach (var kvp in count) { + if (kvp.Value > 1) { + newCount[kvp.Key] = kvp.Value - 1; + } + } + count = newCount; + } + + List res = new List(); + foreach (int candidate in count.Keys) { + int freq = 0; + foreach (int num in nums) { + if (num == candidate) { + freq++; + } + } + if (freq > nums.Length / 3) { + res.Add(candidate); + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/majority-element.md b/articles/majority-element.md index 9ac32df2c..225347051 100644 --- a/articles/majority-element.md +++ b/articles/majority-element.md @@ -72,6 +72,26 @@ class Solution { } ``` +```csharp +public class Solution { + public int MajorityElement(int[] nums) { + int n = nums.Length; + foreach (int num in nums) { + int count = 0; + foreach (int i in nums) { + if (i == num) { + count++; + } + } + if (count > n / 2) { + return num; + } + } + return -1; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -158,6 +178,29 @@ class Solution { } ``` +```csharp +public class Solution { + public int MajorityElement(int[] nums) { + Dictionary count = new Dictionary(); + int res = 0, maxCount = 0; + + foreach (int num in nums) { + if (!count.ContainsKey(num)) { + count[num] = 0; + } + count[num]++; + + if (count[num] > maxCount) { + res = num; + maxCount = count[num]; + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -210,6 +253,15 @@ class Solution { } ``` +```csharp +public class Solution { + public int MajorityElement(int[] nums) { + Array.Sort(nums); + return nums[nums.Length / 2]; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -313,6 +365,30 @@ class Solution { } ``` +```csharp +public class Solution { + public int MajorityElement(int[] nums) { + int n = nums.Length; + int[] bit = new int[32]; + + foreach (int num in nums) { + for (int i = 0; i < 32; i++) { + bit[i] += (num >> i) & 1; + } + } + + int res = 0; + for (int i = 0; i < 32; i++) { + if (bit[i] > n / 2) { + res |= (1 << i); + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -393,6 +469,23 @@ class Solution { } ``` +```csharp +public class Solution { + public int MajorityElement(int[] nums) { + int res = 0, count = 0; + + foreach (int num in nums) { + if (count == 0) { + res = num; + } + count += (num == res) ? 1 : -1; + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -484,6 +577,25 @@ class Solution { } ``` +```csharp +public class Solution { + private static Random random = new Random(); + + public int MajorityElement(int[] nums) { + int n = nums.Length; + + while (true) { + int candidate = nums[random.Next(n)]; + int count = nums.Count(x => x == candidate); + + if (count > n / 2) { + return candidate; + } + } + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/merge-sorted-array.md b/articles/merge-sorted-array.md index aab35dc73..a0e701ef0 100644 --- a/articles/merge-sorted-array.md +++ b/articles/merge-sorted-array.md @@ -53,6 +53,17 @@ class Solution { } ``` +```csharp +public class Solution { + public void Merge(int[] nums1, int m, int[] nums2, int n) { + for (int i = 0; i < n; i++) { + nums1[i + m] = nums2[i]; + } + Array.Sort(nums1); + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -146,6 +157,25 @@ class Solution { } ``` +```csharp +public class Solution { + public void Merge(int[] nums1, int m, int[] nums2, int n) { + int[] nums1Copy = new int[m]; + Array.Copy(nums1, nums1Copy, m); + + int idx = 0, i = 0, j = 0; + + while (idx < m + n) { + if (j >= n || (i < m && nums1Copy[i] <= nums2[j])) { + nums1[idx++] = nums1Copy[i++]; + } else { + nums1[idx++] = nums2[j++]; + } + } + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -270,6 +300,33 @@ class Solution { } ``` +```csharp +public class Solution { + public void Merge(int[] nums1, int m, int[] nums2, int n) { + int last = m + n - 1; + + // Merge in reverse order + while (m > 0 && n > 0) { + if (nums1[m - 1] > nums2[n - 1]) { + nums1[last] = nums1[m - 1]; + m--; + } else { + nums1[last] = nums2[n - 1]; + n--; + } + last--; + } + + // Fill nums1 with leftover nums2 elements + while (n > 0) { + nums1[last] = nums2[n - 1]; + n--; + last--; + } + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -364,6 +421,23 @@ class Solution { } ``` +```csharp +public class Solution { + public void Merge(int[] nums1, int m, int[] nums2, int n) { + int last = m + n - 1; + int i = m - 1, j = n - 1; + + while (j >= 0) { + if (i >= 0 && nums1[i] > nums2[j]) { + nums1[last--] = nums1[i--]; + } else { + nums1[last--] = nums2[j--]; + } + } + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/merge-strings-alternately.md b/articles/merge-strings-alternately.md index 04d95926d..d61a657cd 100644 --- a/articles/merge-strings-alternately.md +++ b/articles/merge-strings-alternately.md @@ -70,6 +70,27 @@ class Solution { } ``` +```csharp +public class Solution { + public string MergeAlternately(string word1, string word2) { + int i = 0, j = 0; + StringBuilder res = new StringBuilder(); + + while (i < word1.Length && j < word2.Length) { + res.Append(word1[i]); + res.Append(word2[j]); + i++; + j++; + } + + res.Append(word1.Substring(i)); + res.Append(word2.Substring(j)); + + return res.ToString(); + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -152,6 +173,29 @@ class Solution { } ``` +```csharp +public class Solution { + public string MergeAlternately(string word1, string word2) { + int n = word1.Length, m = word2.Length; + int i = 0, j = 0; + StringBuilder res = new StringBuilder(); + + while (i < n || j < m) { + if (i < n) { + res.Append(word1[i]); + } + if (j < m) { + res.Append(word2[j]); + } + i++; + j++; + } + + return res.ToString(); + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -240,6 +284,26 @@ class Solution { } ``` +```csharp +public class Solution { + public string MergeAlternately(string word1, string word2) { + int n = word1.Length, m = word2.Length; + StringBuilder res = new StringBuilder(); + + for (int i = 0; i < Math.Max(n, m); i++) { + if (i < n) { + res.Append(word1[i]); + } + if (i < m) { + res.Append(word2[i]); + } + } + + return res.ToString(); + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/remove-element.md b/articles/remove-element.md index 1c3d722e4..14d2c78b4 100644 --- a/articles/remove-element.md +++ b/articles/remove-element.md @@ -72,6 +72,25 @@ class Solution { } ``` +```csharp +public class Solution { + public int RemoveElement(int[] nums, int val) { + List tmp = new List(); + foreach (int num in nums) { + if (num != val) { + tmp.Add(num); + } + } + + for (int i = 0; i < tmp.Count; i++) { + nums[i] = tmp[i]; + } + + return tmp.Count; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -144,6 +163,20 @@ class Solution { } ``` +```csharp +public class Solution { + public int RemoveElement(int[] nums, int val) { + int k = 0; + for (int i = 0; i < nums.Length; i++) { + if (nums[i] != val) { + nums[k++] = nums[i]; + } + } + return k; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -225,6 +258,22 @@ class Solution { } ``` +```csharp +public class Solution { + public int RemoveElement(int[] nums, int val) { + int i = 0, n = nums.Length; + while (i < n) { + if (nums[i] == val) { + nums[i] = nums[--n]; + } else { + i++; + } + } + return n; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/rotate-array.md b/articles/rotate-array.md index 72dfcb037..790679e20 100644 --- a/articles/rotate-array.md +++ b/articles/rotate-array.md @@ -75,6 +75,24 @@ class Solution { } ``` +```csharp +public class Solution { + public void Rotate(int[] nums, int k) { + int n = nums.Length; + k %= n; + + while (k > 0) { + int tmp = nums[n - 1]; + for (int i = n - 1; i > 0; i--) { + nums[i] = nums[i - 1]; + } + nums[0] = tmp; + k--; + } + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -153,6 +171,23 @@ class Solution { } ``` +```csharp +public class Solution { + public void Rotate(int[] nums, int k) { + int n = nums.Length; + int[] tmp = new int[n]; + + for (int i = 0; i < n; i++) { + tmp[(i + k) % n] = nums[i]; + } + + for (int i = 0; i < n; i++) { + nums[i] = tmp[i]; + } + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -265,6 +300,30 @@ class Solution { } ``` +```csharp +public class Solution { + public void Rotate(int[] nums, int k) { + int n = nums.Length; + k %= n; + int count = 0; + + for (int start = 0; count < n; start++) { + int current = start; + int prev = nums[start]; + + do { + int nextIdx = (current + k) % n; + int temp = nums[nextIdx]; + nums[nextIdx] = prev; + prev = temp; + current = nextIdx; + count++; + } while (start != current); + } + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -369,6 +428,29 @@ class Solution { } ``` +```csharp +public class Solution { + public void Rotate(int[] nums, int k) { + int n = nums.Length; + k %= n; + + Reverse(nums, 0, n - 1); + Reverse(nums, 0, k - 1); + Reverse(nums, k, n - 1); + } + + private void Reverse(int[] nums, int left, int right) { + while (left < right) { + int temp = nums[left]; + nums[left] = nums[right]; + nums[right] = temp; + left++; + right--; + } + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -425,6 +507,20 @@ class Solution { } ``` +```csharp +public class Solution { + public void Rotate(int[] nums, int k) { + int n = nums.Length; + k %= n; + + int[] rotated = new int[n]; + Array.Copy(nums, n - k, rotated, 0, k); + Array.Copy(nums, 0, rotated, k, n - k); + Array.Copy(rotated, nums, n); + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/sort-an-array.md b/articles/sort-an-array.md index ba9edb507..265db6b33 100644 --- a/articles/sort-an-array.md +++ b/articles/sort-an-array.md @@ -205,6 +205,58 @@ class Solution { } ``` +```csharp +public class Solution { + public int[] SortArray(int[] nums) { + QuickSort(nums, 0, nums.Length - 1); + return nums; + } + + private void QuickSort(int[] nums, int left, int right) { + if (right <= left + 1) { + if (right == left + 1 && nums[right] < nums[left]) { + Swap(nums, left, right); + } + return; + } + + int j = Partition(nums, left, right); + QuickSort(nums, left, j - 1); + QuickSort(nums, j + 1, right); + } + + private int Partition(int[] nums, int left, int right) { + int mid = (left + right) >> 1; + Swap(nums, mid, left + 1); + + if (nums[left] > nums[right]) Swap(nums, left, right); + if (nums[left + 1] > nums[right]) Swap(nums, left + 1, right); + if (nums[left] > nums[left + 1]) Swap(nums, left, left + 1); + + int pivot = nums[left + 1]; + int i = left + 1, j = right; + + while (true) { + while (++i <= right && nums[i] < pivot) ; + while (--j >= left && nums[j] > pivot) ; + + if (i > j) break; + + Swap(nums, i, j); + } + + Swap(nums, left + 1, j); + return j; + } + + private void Swap(int[] nums, int i, int j) { + int temp = nums[i]; + nums[i] = nums[j]; + nums[j] = temp; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -397,6 +449,47 @@ class Solution { } ``` +```csharp +public class Solution { + public int[] SortArray(int[] nums) { + MergeSort(nums, 0, nums.Length - 1); + return nums; + } + + private void MergeSort(int[] arr, int l, int r) { + if (l == r) return; + + int m = (l + r) / 2; + MergeSort(arr, l, m); + MergeSort(arr, m + 1, r); + Merge(arr, l, m, r); + } + + private void Merge(int[] arr, int L, int M, int R) { + int[] left = arr[L..(M + 1)]; + int[] right = arr[(M + 1)..(R + 1)]; + + int i = L, j = 0, k = 0; + + while (j < left.Length && k < right.Length) { + if (left[j] <= right[k]) { + arr[i++] = left[j++]; + } else { + arr[i++] = right[k++]; + } + } + + while (j < left.Length) { + arr[i++] = left[j++]; + } + + while (k < right.Length) { + arr[i++] = right[k++]; + } + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -580,6 +673,53 @@ class Solution { } ``` +```csharp +public class Solution { + public int[] SortArray(int[] nums) { + HeapSort(nums); + return nums; + } + + private void Heapify(int[] arr, int n, int i) { + int l = (i << 1) + 1; + int r = (i << 1) + 2; + int largestNode = i; + + if (l < n && arr[l] > arr[largestNode]) { + largestNode = l; + } + + if (r < n && arr[r] > arr[largestNode]) { + largestNode = r; + } + + if (largestNode != i) { + Swap(arr, i, largestNode); + Heapify(arr, n, largestNode); + } + } + + private void HeapSort(int[] arr) { + int n = arr.Length; + + for (int i = n / 2 - 1; i >= 0; i--) { + Heapify(arr, n, i); + } + + for (int i = n - 1; i > 0; i--) { + Swap(arr, 0, i); + Heapify(arr, i, 0); + } + } + + private void Swap(int[] arr, int i, int j) { + int temp = arr[i]; + arr[i] = arr[j]; + arr[j] = temp; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -711,6 +851,37 @@ class Solution { } ``` +```csharp +public class Solution { + public int[] SortArray(int[] nums) { + CountingSort(nums); + return nums; + } + + private void CountingSort(int[] nums) { + Dictionary count = new Dictionary(); + int minVal = int.MaxValue, maxVal = int.MinValue; + + foreach (int val in nums) { + if (!count.ContainsKey(val)) { + count[val] = 0; + } + count[val]++; + minVal = Math.Min(minVal, val); + maxVal = Math.Max(maxVal, val); + } + + int index = 0; + for (int val = minVal; val <= maxVal; val++) { + if (!count.ContainsKey(val)) continue; + while (count[val]-- > 0) { + nums[index++] = val; + } + } + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -974,6 +1145,74 @@ class Solution { } ``` +```csharp +public class Solution { + public int[] SortArray(int[] nums) { + List negatives = new List(); + List positives = new List(); + + foreach (int num in nums) { + if (num < 0) negatives.Add(-num); + else positives.Add(num); + } + + if (negatives.Count > 0) { + RadixSort(negatives); + negatives.Reverse(); + for (int i = 0; i < negatives.Count; i++) { + negatives[i] = -negatives[i]; + } + } + + if (positives.Count > 0) { + RadixSort(positives); + } + + List result = new List(); + result.AddRange(negatives); + result.AddRange(positives); + + return result.ToArray(); + } + + private void RadixSort(List arr) { + int n = arr.Count; + int maxElement = 0; + foreach (int num in arr) { + if (num > maxElement) maxElement = num; + } + + int d = 1; + while (maxElement / d > 0) { + CountSort(arr, n, d); + d *= 10; + } + } + + private void CountSort(List arr, int n, int d) { + int[] count = new int[10]; + for (int i = 0; i < n; i++) { + int digit = (arr[i] / d) % 10; + count[digit]++; + } + + for (int i = 1; i < 10; i++) { + count[i] += count[i - 1]; + } + + int[] res = new int[n]; + for (int i = n - 1; i >= 0; i--) { + int digit = (arr[i] / d) % 10; + res[--count[digit]] = arr[i]; + } + + for (int i = 0; i < n; i++) { + arr[i] = res[i]; + } + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -1097,6 +1336,34 @@ class Solution { } ``` +```csharp +public class Solution { + public int[] SortArray(int[] nums) { + int n = nums.Length; + if (n == 1) return nums; + + ShellSort(nums, n); + return nums; + } + + private void ShellSort(int[] nums, int n) { + int gap = n / 2; + while (gap >= 1) { + for (int i = gap; i < n; i++) { + int tmp = nums[i]; + int j = i - gap; + while (j >= 0 && nums[j] > tmp) { + nums[j + gap] = nums[j]; + j -= gap; + } + nums[j + gap] = tmp; + } + gap /= 2; + } + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/sort-colors.md b/articles/sort-colors.md index c94416b39..46bc4a86a 100644 --- a/articles/sort-colors.md +++ b/articles/sort-colors.md @@ -40,6 +40,14 @@ class Solution { } ``` +```csharp +public class Solution { + public void SortColors(int[] nums) { + Array.Sort(nums); + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -130,6 +138,24 @@ class Solution { } ``` +```csharp +public class Solution { + public void SortColors(int[] nums) { + int[] count = new int[3]; + foreach (int num in nums) { + count[num]++; + } + + int index = 0; + for (int i = 0; i < 3; i++) { + while (count[i]-- > 0) { + nums[index++] = i; + } + } + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -236,6 +262,32 @@ class Solution { } ``` +```csharp +public class Solution { + public void SortColors(int[] nums) { + int i = 0, l = 0, r = nums.Length - 1; + + while (i <= r) { + if (nums[i] == 0) { + Swap(nums, l, i); + l++; + } else if (nums[i] == 2) { + Swap(nums, i, r); + r--; + i--; + } + i++; + } + } + + private void Swap(int[] nums, int i, int j) { + int temp = nums[i]; + nums[i] = nums[j]; + nums[j] = temp; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -339,6 +391,27 @@ class Solution { } ``` +```csharp +public class Solution { + public void SortColors(int[] nums) { + int zero = 0, one = 0, two = 0; + + for (int i = 0; i < nums.Length; i++) { + if (nums[i] == 0) { + nums[two++] = 2; + nums[one++] = 1; + nums[zero++] = 0; + } else if (nums[i] == 1) { + nums[two++] = 2; + nums[one++] = 1; + } else { + nums[two++] = 2; + } + } + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -429,6 +502,26 @@ class Solution { } ``` +```csharp +public class Solution { + public void SortColors(int[] nums) { + int zero = 0, one = 0; + + for (int two = 0; two < nums.Length; two++) { + int tmp = nums[two]; + nums[two] = 2; + + if (tmp < 2) { + nums[one++] = 1; + } + if (tmp < 1) { + nums[zero++] = 0; + } + } + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/subarray-sum-equals-k.md b/articles/subarray-sum-equals-k.md index 5afa95bd3..fa979f529 100644 --- a/articles/subarray-sum-equals-k.md +++ b/articles/subarray-sum-equals-k.md @@ -69,6 +69,24 @@ class Solution { } ``` +```csharp +public class Solution { + public int SubarraySum(int[] nums, int k) { + int res = 0; + for (int i = 0; i < nums.Length; i++) { + int sum = 0; + for (int j = i; j < nums.Length; j++) { + sum += nums[j]; + if (sum == k) { + res++; + } + } + } + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -161,6 +179,32 @@ class Solution { } ``` +```csharp +public class Solution { + public int SubarraySum(int[] nums, int k) { + int res = 0, curSum = 0; + Dictionary prefixSums = new Dictionary(); + prefixSums[0] = 1; + + foreach (int num in nums) { + curSum += num; + int diff = curSum - k; + + if (prefixSums.ContainsKey(diff)) { + res += prefixSums[diff]; + } + + if (!prefixSums.ContainsKey(curSum)) { + prefixSums[curSum] = 0; + } + prefixSums[curSum]++; + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity From c57cf461bbc4cd27e050a2cada488be4b567202d Mon Sep 17 00:00:00 2001 From: neetcode-gh <77742485+neetcode-gh@users.noreply.github.com> Date: Fri, 2 May 2025 06:41:51 -0700 Subject: [PATCH 10/12] Update combinations-of-a-phone-number.md --- articles/combinations-of-a-phone-number.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/articles/combinations-of-a-phone-number.md b/articles/combinations-of-a-phone-number.md index 6f6bfd6dd..51796e3f7 100644 --- a/articles/combinations-of-a-phone-number.md +++ b/articles/combinations-of-a-phone-number.md @@ -1,4 +1,4 @@ -## 1. Bactracking +## 1. Backtracking ::tabs-start @@ -497,4 +497,4 @@ class Solution { * Time complexity: $O(n * 4 ^ n)$ * Space complexity: * $O(n)$ extra space. - * $O(n * 4 ^ n)$ space for the output list. \ No newline at end of file + * $O(n * 4 ^ n)$ space for the output list. From d2bcd42a22a671dffab507ad76c38baa3838285b Mon Sep 17 00:00:00 2001 From: neetcode-gh <77742485+neetcode-gh@users.noreply.github.com> Date: Sun, 11 May 2025 08:41:57 -0700 Subject: [PATCH 11/12] Update sort-an-array.md --- articles/sort-an-array.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/articles/sort-an-array.md b/articles/sort-an-array.md index 265db6b33..6b34f49d2 100644 --- a/articles/sort-an-array.md +++ b/articles/sort-an-array.md @@ -261,7 +261,7 @@ public class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ in average case, $O(n ^ 2)$ in worst case. +* Time complexity: $O(n \log n)$ in average case, $O(n ^ 2)$ in worst case. * Space complexity: $O(\log n)$ for recursive stack. --- @@ -1369,4 +1369,4 @@ public class Solution { ### Time & Space Complexity * Time complexity: $O(n \log n)$ in average case, $O(n ^ 2)$ in worst case. -* Space complexity: $O(1)$ \ No newline at end of file +* Space complexity: $O(1)$ From 3d2b2c0429a514c1565add058c23bf8187370276 Mon Sep 17 00:00:00 2001 From: Sri Hari <94112314+Srihari2222@users.noreply.github.com> Date: Tue, 20 May 2025 22:00:48 +0530 Subject: [PATCH 12/12] Sri Hari: Batch-7/Added articles (#4148) * Batch-7/Neetcode-ALL/Added-articles * Batch-7/Neetcode-ALL/Added-articles * Batch-7/Neetcode-ALL/Added-articles * Batch-7/Neetcode-ALL/Added-articles * Batch-7/Neetcode-ALL/Added-articles * Batch-7/Neetcode-ALL/Added-articles * Batch-7/Neetcode-ALL/Added-articles * Batch-7/Neetcode-ALL/Added-articles * Batch-7/Neetcode-ALL/Added-articles * Batch-7/Neetcode-ALL/Added-articles * Batch-7/Neetcode-ALL/Added-articles * Batch-7/Neetcode-ALL/Added-articles * Batch-7/Neetcode-ALL/Added-articles --- articles/4sum.md | 163 +++++++++ articles/accounts-merge.md | 233 ++++++++++++ articles/asteroid-collision.md | 63 ++++ articles/baseball-game.md | 64 +++- articles/binary-tree-inorder-traversal.md | 109 ++++++ articles/binary-tree-postorder-traversal.md | 160 ++++++++ articles/binary-tree-preorder-traversal.md | 111 ++++++ ...capacity-to-ship-packages-within-d-days.md | 61 ++++ articles/car-pooling.md | 122 ++++++- articles/combination-sum-iv.md | 99 +++++ articles/combinations.md | 98 +++++ articles/construct-quad-tree.md | 212 +++++++++++ articles/contains-duplicate-ii.md | 54 +++ articles/course-schedule-iv.md | 195 ++++++++++ articles/decode-string.md | 108 ++++++ articles/delete-leaves-with-a-given-value.md | 142 ++++++++ articles/delete-node-in-a-bst.md | 158 ++++++++ articles/evaluate-division.md | 201 ++++++++++ articles/extra-characters-in-a-string.md | 238 ++++++++++++ articles/find-in-mountain-array.md | 194 +++++++++- articles/find-the-town-judge.md | 46 +++ articles/greatest-common-divisor-traversal.md | 344 +++++++++++++++++- articles/guess-number-higher-or-lower.md | 81 ++++- articles/house-robber-iii.md | 106 ++++++ articles/insert-into-a-binary-search-tree.md | 71 ++++ articles/integer-break.md | 145 ++++++++ articles/ipo.md | 111 +++++- articles/island-perimeter.md | 135 +++++++ articles/longest-happy-string.md | 115 +++++- articles/matchsticks-to-square.md | 112 ++++++ articles/minimum-size-subarray-sum.md | 76 ++++ articles/n-queens-ii.md | 162 +++++++++ articles/n-th-tribonacci-number.md | 59 +++ articles/open-the-lock.md | 119 ++++++ articles/partition-to-k-equal-sum-subsets.md | 173 +++++++++ articles/path-with-minimum-effort.md | 219 ++++++++++- articles/perfect-squares.md | 126 +++++++ articles/permutations-ii.md | 180 +++++++++ .../remove-duplicates-from-sorted-array.md | 45 +++ articles/reverse-linked-list-ii.md | 177 +++++++++ articles/reverse-string.md | 73 ++++ articles/search-in-rotated-sorted-array-ii.md | 39 ++ articles/search-insert-position.md | 87 +++++ articles/simplify-path.md | 49 +++ articles/single-threaded-cpu.md | 138 ++++++- articles/split-array-largest-sum.md | 228 +++++++++++- articles/sqrtx.md | 76 ++++ articles/stone-game-iii.md | 106 ++++++ articles/sum-of-all-subset-xor-totals.md | 73 ++++ articles/verifying-an-alien-dictionary.md | 60 +++ articles/word-break-ii.md | 213 +++++++++++ 51 files changed, 6476 insertions(+), 53 deletions(-) diff --git a/articles/4sum.md b/articles/4sum.md index f99c11ddd..b590cf39e 100644 --- a/articles/4sum.md +++ b/articles/4sum.md @@ -96,6 +96,35 @@ class Solution { } ``` +```csharp +public class Solution { + public List> FourSum(int[] nums, int target) { + int n = nums.Length; + Array.Sort(nums); + HashSet<(int, int, int, int)> res = new HashSet<(int, int, int, int)>(); + + for (int a = 0; a < n; a++) { + for (int b = a + 1; b < n; b++) { + for (int c = b + 1; c < n; c++) { + for (int d = c + 1; d < n; d++) { + long sum = (long)nums[a] + nums[b] + nums[c] + nums[d]; + if (sum == target) { + res.Add((nums[a], nums[b], nums[c], nums[d])); + } + } + } + } + } + + var result = new List>(); + foreach (var quad in res) { + result.Add(new List { quad.Item1, quad.Item2, quad.Item3, quad.Item4 }); + } + return result; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -287,6 +316,58 @@ class Solution { } ``` +```csharp +public class Solution { + public List> FourSum(int[] nums, int target) { + Array.Sort(nums); + Dictionary count = new Dictionary(); + + foreach (int num in nums) { + if (!count.ContainsKey(num)) { + count[num] = 0; + } + count[num]++; + } + + List> res = new List>(); + + for (int i = 0; i < nums.Length; i++) { + count[nums[i]]--; + if (i > 0 && nums[i] == nums[i - 1]) continue; + + for (int j = i + 1; j < nums.Length; j++) { + count[nums[j]]--; + if (j > i + 1 && nums[j] == nums[j - 1]) continue; + + for (int k = j + 1; k < nums.Length; k++) { + count[nums[k]]--; + if (k > j + 1 && nums[k] == nums[k - 1]) continue; + + long fourth = (long)target - (long)nums[i] - (long)nums[j] - (long)nums[k]; + if (fourth > int.MaxValue || fourth < int.MinValue) { + continue; + } + + if (count.ContainsKey((int)fourth) && count[(int)fourth] > 0) { + res.Add(new List { nums[i], nums[j], nums[k], (int)fourth }); + } + } + + for (int k = j + 1; k < nums.Length; k++) { + count[nums[k]]++; + } + } + + for (int j = i + 1; j < nums.Length; j++) { + count[nums[j]]++; + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -448,6 +529,42 @@ class Solution { } ``` +```csharp +public class Solution { + public List> FourSum(int[] nums, int target) { + Array.Sort(nums); + List> res = new List>(); + int n = nums.Length; + + for (int i = 0; i < n; i++) { + if (i > 0 && nums[i] == nums[i - 1]) continue; + + for (int j = i + 1; j < n; j++) { + if (j > i + 1 && nums[j] == nums[j - 1]) continue; + + int left = j + 1, right = n - 1; + while (left < right) { + long sum = (long)nums[i] + nums[j] + nums[left] + nums[right]; + if (sum == target) { + res.Add(new List { nums[i], nums[j], nums[left], nums[right] }); + left++; + right--; + while (left < right && nums[left] == nums[left - 1]) left++; + while (left < right && nums[right] == nums[right + 1]) right--; + } else if (sum < target) { + left++; + } else { + right--; + } + } + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -637,6 +754,52 @@ class Solution { } ``` +```csharp +public class Solution { + private List> res; + private List quad; + + public List> FourSum(int[] nums, int target) { + Array.Sort(nums); + res = new List>(); + quad = new List(); + KSum(nums, 4, 0, target); + return res; + } + + private void KSum(int[] nums, int k, int start, long target) { + if (k == 2) { + int l = start, r = nums.Length - 1; + while (l < r) { + long sum = (long)nums[l] + nums[r]; + if (sum < target) { + l++; + } else if (sum > target) { + r--; + } else { + List newQuad = new List(quad); + newQuad.Add(nums[l]); + newQuad.Add(nums[r]); + res.Add(newQuad); + l++; + r--; + while (l < r && nums[l] == nums[l - 1]) l++; + while (l < r && nums[r] == nums[r + 1]) r--; + } + } + return; + } + + for (int i = start; i < nums.Length - k + 1; i++) { + if (i > start && nums[i] == nums[i - 1]) continue; + quad.Add(nums[i]); + KSum(nums, k - 1, i + 1, target - nums[i]); + quad.RemoveAt(quad.Count - 1); + } + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/accounts-merge.md b/articles/accounts-merge.md index 665334798..15b8e9881 100644 --- a/articles/accounts-merge.md +++ b/articles/accounts-merge.md @@ -284,6 +284,79 @@ class Solution { } ``` +```csharp +public class Solution { + private Dictionary emailIdx = new Dictionary(); + private List emails = new List(); + private List> adj; + private bool[] visited; + private Dictionary> components = new Dictionary>(); + private Dictionary componentName = new Dictionary(); + + public List> AccountsMerge(List> accounts) { + int m = 0; + + for (int accId = 0; accId < accounts.Count; accId++) { + var account = accounts[accId]; + for (int i = 1; i < account.Count; i++) { + string email = account[i]; + if (!emailIdx.ContainsKey(email)) { + emailIdx[email] = m++; + emails.Add(email); + } + } + } + + adj = new List>(); + for (int i = 0; i < m; i++) adj.Add(new List()); + + foreach (var account in accounts) { + for (int i = 2; i < account.Count; i++) { + int u = emailIdx[account[i - 1]]; + int v = emailIdx[account[i]]; + adj[u].Add(v); + adj[v].Add(u); + } + } + + visited = new bool[m]; + + foreach (var account in accounts) { + string name = account[0]; + foreach (var email in account.Skip(1)) { + int idx = emailIdx[email]; + if (!visited[idx]) { + components[idx] = new List(); + componentName[idx] = name; + Dfs(idx, idx); + } + } + } + + var res = new List>(); + foreach (var kvp in components) { + var group = kvp.Value; + group.Sort(StringComparer.Ordinal); + var merged = new List { componentName[kvp.Key] }; + merged.AddRange(group); + res.Add(merged); + } + + return res; + } + + private void Dfs(int node, int root) { + visited[node] = true; + components[root].Add(emails[node]); + foreach (int nei in adj[node]) { + if (!visited[nei]) { + Dfs(nei, root); + } + } + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -607,6 +680,85 @@ class Solution { } ``` +```csharp +public class Solution { + public List> AccountsMerge(List> accounts) { + int n = accounts.Count; + Dictionary emailIdx = new Dictionary(); + List emails = new List(); + Dictionary emailToAcc = new Dictionary(); + + int m = 0; + for (int accId = 0; accId < n; accId++) { + var account = accounts[accId]; + for (int i = 1; i < account.Count; i++) { + string email = account[i]; + if (!emailIdx.ContainsKey(email)) { + emailIdx[email] = m; + emails.Add(email); + emailToAcc[m] = accId; + m++; + } + } + } + + List> adj = new List>(); + for (int i = 0; i < m; i++) adj.Add(new List()); + + foreach (var account in accounts) { + for (int i = 2; i < account.Count; i++) { + int id1 = emailIdx[account[i]]; + int id2 = emailIdx[account[i - 1]]; + adj[id1].Add(id2); + adj[id2].Add(id1); + } + } + + Dictionary> emailGroup = new Dictionary>(); + bool[] visited = new bool[m]; + + void Bfs(int start, int accId) { + Queue queue = new Queue(); + queue.Enqueue(start); + visited[start] = true; + + if (!emailGroup.ContainsKey(accId)) + emailGroup[accId] = new List(); + + while (queue.Count > 0) { + int node = queue.Dequeue(); + emailGroup[accId].Add(emails[node]); + + foreach (int nei in adj[node]) { + if (!visited[nei]) { + visited[nei] = true; + queue.Enqueue(nei); + } + } + } + } + + for (int i = 0; i < m; i++) { + if (!visited[i]) { + Bfs(i, emailToAcc[i]); + } + } + + List> res = new List>(); + foreach (var kvp in emailGroup) { + int accId = kvp.Key; + string name = accounts[accId][0]; + List merged = new List { name }; + kvp.Value.Sort(StringComparer.Ordinal); + merged.AddRange(kvp.Value); + res.Add(merged); + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -922,6 +1074,87 @@ class Solution { } ``` +```csharp +public class UnionFind { + private int[] parent; + private int[] rank; + + public UnionFind(int n) { + parent = new int[n]; + rank = new int[n]; + for (int i = 0; i < n; i++) { + parent[i] = i; + rank[i] = 1; + } + } + + public int Find(int x) { + if (x != parent[x]) { + parent[x] = Find(parent[x]); + } + return parent[x]; + } + + public bool Union(int x, int y) { + int rootX = Find(x); + int rootY = Find(y); + + if (rootX == rootY) return false; + + if (rank[rootX] > rank[rootY]) { + parent[rootY] = rootX; + rank[rootX] += rank[rootY]; + } else { + parent[rootX] = rootY; + rank[rootY] += rank[rootX]; + } + + return true; + } +} + +public class Solution { + public List> AccountsMerge(List> accounts) { + int n = accounts.Count; + UnionFind uf = new UnionFind(n); + Dictionary emailToAcc = new Dictionary(); + + for (int i = 0; i < n; i++) { + for (int j = 1; j < accounts[i].Count; j++) { + string email = accounts[i][j]; + if (emailToAcc.ContainsKey(email)) { + uf.Union(i, emailToAcc[email]); + } else { + emailToAcc[email] = i; + } + } + } + + Dictionary> emailGroup = new Dictionary>(); + foreach (var kvp in emailToAcc) { + string email = kvp.Key; + int leader = uf.Find(kvp.Value); + if (!emailGroup.ContainsKey(leader)) { + emailGroup[leader] = new List(); + } + emailGroup[leader].Add(email); + } + + List> res = new List>(); + foreach (var kvp in emailGroup) { + int accId = kvp.Key; + List emails = kvp.Value; + emails.Sort(StringComparer.Ordinal); + List merged = new List { accounts[accId][0] }; + merged.AddRange(emails); + res.Add(merged); + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/asteroid-collision.md b/articles/asteroid-collision.md index e9634e9e8..94a5993d3 100644 --- a/articles/asteroid-collision.md +++ b/articles/asteroid-collision.md @@ -101,6 +101,35 @@ class Solution { } ``` +```csharp +public class Solution { + public int[] AsteroidCollision(int[] asteroids) { + Stack stack = new Stack(); + + foreach (int a in asteroids) { + int current = a; + while (stack.Count > 0 && current < 0 && stack.Peek() > 0) { + int diff = current + stack.Peek(); + if (diff < 0) { + stack.Pop(); + } else if (diff > 0) { + current = 0; + } else { + current = 0; + stack.Pop(); + } + } + if (current != 0) { + stack.Push(current); + } + } + + int[] result = stack.Reverse().ToArray(); + return result; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -231,6 +260,40 @@ class Solution { } ``` +```csharp +public class Solution { + public int[] AsteroidCollision(int[] asteroids) { + int n = asteroids.Length; + int j = -1; + + foreach (int a in asteroids) { + int current = a; + + while (j >= 0 && asteroids[j] > 0 && current < 0) { + if (asteroids[j] > Math.Abs(current)) { + current = 0; + break; + } else if (asteroids[j] == Math.Abs(current)) { + j--; + current = 0; + break; + } else { + j--; + } + } + + if (current != 0) { + asteroids[++j] = current; + } + } + + int[] result = new int[j + 1]; + Array.Copy(asteroids, 0, result, 0, j + 1); + return result; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/baseball-game.md b/articles/baseball-game.md index 2d04f4311..ac8e53feb 100644 --- a/articles/baseball-game.md +++ b/articles/baseball-game.md @@ -1,4 +1,4 @@ -## 1. Stack +## 1. Stack - I ::tabs-start @@ -96,6 +96,36 @@ class Solution { } ``` +```csharp +public class Solution { + public int CalPoints(string[] operations) { + Stack stack = new Stack(); + + foreach (var op in operations) { + if (op == "+") { + int top = stack.Pop(); + int newTop = top + stack.Peek(); + stack.Push(top); + stack.Push(newTop); + } else if (op == "D") { + stack.Push(2 * stack.Peek()); + } else if (op == "C") { + stack.Pop(); + } else { + stack.Push(int.Parse(op)); + } + } + + int total = 0; + foreach (var val in stack) { + total += val; + } + + return total; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -215,6 +245,38 @@ class Solution { } ``` +```csharp +public class Solution { + public int CalPoints(string[] operations) { + Stack stack = new Stack(); + int res = 0; + + foreach (var op in operations) { + if (op == "+") { + int top = stack.Pop(); + int second = stack.Peek(); + int sum = top + second; + stack.Push(top); + stack.Push(sum); + res += sum; + } else if (op == "D") { + int doubleVal = 2 * stack.Peek(); + stack.Push(doubleVal); + res += doubleVal; + } else if (op == "C") { + res -= stack.Pop(); + } else { + int num = int.Parse(op); + stack.Push(num); + res += num; + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/binary-tree-inorder-traversal.md b/articles/binary-tree-inorder-traversal.md index 4735f8400..84e525d71 100644 --- a/articles/binary-tree-inorder-traversal.md +++ b/articles/binary-tree-inorder-traversal.md @@ -126,6 +126,35 @@ class Solution { } ``` +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public int val; + * public TreeNode left; + * public TreeNode right; + * public TreeNode(int val=0, TreeNode left=null, TreeNode right=null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public List InorderTraversal(TreeNode root) { + List res = new List(); + void Inorder(TreeNode node) { + if (node == null) return; + Inorder(node.left); + res.Add(node.val); + Inorder(node.right); + } + Inorder(root); + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -273,6 +302,41 @@ class Solution { } ``` +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public int val; + * public TreeNode left; + * public TreeNode right; + * public TreeNode(int val=0, TreeNode left=null, TreeNode right=null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public IList InorderTraversal(TreeNode root) { + List res = new List(); + Stack stack = new Stack(); + TreeNode cur = root; + + while (cur != null || stack.Count > 0) { + while (cur != null) { + stack.Push(cur); + cur = cur.left; + } + cur = stack.Pop(); + res.Add(cur.val); + cur = cur.right; + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -457,6 +521,51 @@ class Solution { } ``` +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public int val; + * public TreeNode left; + * public TreeNode right; + * public TreeNode(int val=0, TreeNode left=null, TreeNode right=null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public List InorderTraversal(TreeNode root) { + List res = new List(); + TreeNode cur = root; + + while (cur != null) { + if (cur.left == null) { + res.Add(cur.val); + cur = cur.right; + } else { + TreeNode prev = cur.left; + while (prev.right != null && prev.right != cur) { + prev = prev.right; + } + + if (prev.right == null) { + prev.right = cur; + cur = cur.left; + } else { + prev.right = null; + res.Add(cur.val); + cur = cur.right; + } + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/binary-tree-postorder-traversal.md b/articles/binary-tree-postorder-traversal.md index 554c3006a..8853be764 100644 --- a/articles/binary-tree-postorder-traversal.md +++ b/articles/binary-tree-postorder-traversal.md @@ -126,6 +126,37 @@ class Solution { } ``` +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public int val; + * public TreeNode left; + * public TreeNode right; + * public TreeNode(int val=0, TreeNode left=null, TreeNode right=null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public List PostorderTraversal(TreeNode root) { + List res = new List(); + + void Postorder(TreeNode node) { + if (node == null) return; + Postorder(node.left); + Postorder(node.right); + res.Add(node.val); + } + + Postorder(root); + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -309,6 +340,52 @@ class Solution { } ``` +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public int val; + * public TreeNode left; + * public TreeNode right; + * public TreeNode(int val=0, TreeNode left=null, TreeNode right=null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public List PostorderTraversal(TreeNode root) { + var stack = new Stack(); + var visit = new Stack(); + var res = new List(); + + stack.Push(root); + visit.Push(false); + + while (stack.Count > 0) { + var cur = stack.Pop(); + var v = visit.Pop(); + + if (cur != null) { + if (v) { + res.Add(cur.val); + } else { + stack.Push(cur); + visit.Push(true); + stack.Push(cur.right); + visit.Push(false); + stack.Push(cur.left); + visit.Push(false); + } + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -464,6 +541,43 @@ class Solution { } ``` +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public int val; + * public TreeNode left; + * public TreeNode right; + * public TreeNode(int val=0, TreeNode left=null, TreeNode right=null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public List PostorderTraversal(TreeNode root) { + List res = new List(); + Stack stack = new Stack(); + TreeNode cur = root; + + while (cur != null || stack.Count > 0) { + if (cur != null) { + res.Add(cur.val); + stack.Push(cur); + cur = cur.right; + } else { + cur = stack.Pop(); + cur = cur.left; + } + } + + res.Reverse(); + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -652,6 +766,52 @@ class Solution { } ``` +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public int val; + * public TreeNode left; + * public TreeNode right; + * public TreeNode(int val=0, TreeNode left=null, TreeNode right=null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public List PostorderTraversal(TreeNode root) { + List res = new List(); + TreeNode cur = root; + + while (cur != null) { + if (cur.right == null) { + res.Add(cur.val); + cur = cur.left; + } else { + TreeNode prev = cur.right; + while (prev.left != null && prev.left != cur) { + prev = prev.left; + } + + if (prev.left == null) { + res.Add(cur.val); + prev.left = cur; + cur = cur.right; + } else { + prev.left = null; + cur = cur.left; + } + } + } + + res.Reverse(); + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/binary-tree-preorder-traversal.md b/articles/binary-tree-preorder-traversal.md index fbcc8b4d6..f7f86ffb9 100644 --- a/articles/binary-tree-preorder-traversal.md +++ b/articles/binary-tree-preorder-traversal.md @@ -126,6 +126,37 @@ class Solution { } ``` +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public int val; + * public TreeNode left; + * public TreeNode right; + * public TreeNode(int val=0, TreeNode left=null, TreeNode right=null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public List PreorderTraversal(TreeNode root) { + List res = new List(); + Preorder(root, res); + return res; + } + + private void Preorder(TreeNode node, List res) { + if (node == null) return; + + res.Add(node.val); + Preorder(node.left, res); + Preorder(node.right, res); + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -274,6 +305,41 @@ class Solution { } ``` +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public int val; + * public TreeNode left; + * public TreeNode right; + * public TreeNode(int val=0, TreeNode left=null, TreeNode right=null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public List PreorderTraversal(TreeNode root) { + List res = new List(); + Stack stack = new Stack(); + TreeNode cur = root; + + while (cur != null || stack.Count > 0) { + if (cur != null) { + res.Add(cur.val); + stack.Push(cur.right); + cur = cur.left; + } else { + cur = stack.Pop(); + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -458,6 +524,51 @@ class Solution { } ``` +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public int val; + * public TreeNode left; + * public TreeNode right; + * public TreeNode(int val=0, TreeNode left=null, TreeNode right=null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public List PreorderTraversal(TreeNode root) { + List res = new List(); + TreeNode cur = root; + + while (cur != null) { + if (cur.left == null) { + res.Add(cur.val); + cur = cur.right; + } else { + TreeNode prev = cur.left; + while (prev.right != null && prev.right != cur) { + prev = prev.right; + } + + if (prev.right == null) { + res.Add(cur.val); + prev.right = cur; + cur = cur.left; + } else { + prev.right = null; + cur = cur.right; + } + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/capacity-to-ship-packages-within-d-days.md b/articles/capacity-to-ship-packages-within-d-days.md index 9a5d4e777..dfc4f2146 100644 --- a/articles/capacity-to-ship-packages-within-d-days.md +++ b/articles/capacity-to-ship-packages-within-d-days.md @@ -97,6 +97,29 @@ class Solution { } ``` +```csharp +public class Solution { + public int ShipWithinDays(int[] weights, int days) { + int res = weights.Max(); + while (true) { + int ships = 1; + int cap = res; + foreach (int w in weights) { + if (cap - w < 0) { + ships++; + cap = res; + } + cap -= w; + } + if (ships <= days) { + return res; + } + res++; + } + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -258,6 +281,44 @@ class Solution { } ``` +```csharp +public class Solution { + public int ShipWithinDays(int[] weights, int days) { + int l = weights.Max(); + int r = weights.Sum(); + int res = r; + + bool CanShip(int cap) { + int ships = 1; + int currCap = cap; + + foreach (int w in weights) { + if (currCap - w < 0) { + ships++; + if (ships > days) return false; + currCap = cap; + } + currCap -= w; + } + + return true; + } + + while (l <= r) { + int cap = (l + r) / 2; + if (CanShip(cap)) { + res = Math.Min(res, cap); + r = cap - 1; + } else { + l = cap + 1; + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/car-pooling.md b/articles/car-pooling.md index 3eac0695d..df5745d6d 100644 --- a/articles/car-pooling.md +++ b/articles/car-pooling.md @@ -92,6 +92,28 @@ class Solution { } ``` +```csharp +public class Solution { + public bool CarPooling(int[][] trips, int capacity) { + Array.Sort(trips, (a, b) => a[1].CompareTo(b[1])); + + for (int i = 0; i < trips.Length; i++) { + int curPass = trips[i][0]; + for (int j = 0; j < i; j++) { + if (trips[j][2] > trips[i][1]) { + curPass += trips[j][0]; + } + } + if (curPass > capacity) { + return false; + } + } + + return true; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -196,12 +218,12 @@ class Solution { carPooling(trips, capacity) { trips.sort((a, b) => a[1] - b[1]); - const minHeap = new MinPriorityQueue({ priority: x => x[0] }); // [end, numPassengers] + const minHeap = new MinPriorityQueue(x => x[0]); // [end, numPassengers] let curPass = 0; for (const [numPass, start, end] of trips) { - while (!minHeap.isEmpty() && minHeap.front().element[0] <= start) { - curPass -= minHeap.dequeue().element[1]; + while (!minHeap.isEmpty() && minHeap.front()[0] <= start) { + curPass -= minHeap.dequeue()[1]; } curPass += numPass; @@ -217,6 +239,36 @@ class Solution { } ``` +```csharp +public class Solution { + public bool CarPooling(int[][] trips, int capacity) { + Array.Sort(trips, (a, b) => a[1].CompareTo(b[1])); + + var minHeap = new PriorityQueue(); + int curPass = 0; + + foreach (var trip in trips) { + int numPass = trip[0]; + int start = trip[1]; + int end = trip[2]; + + while (minHeap.Count > 0 && minHeap.Peek()[0] <= start) { + curPass -= minHeap.Dequeue()[1]; + } + + curPass += numPass; + if (curPass > capacity) { + return false; + } + + minHeap.Enqueue(new int[] { end, numPass }, end); + } + + return true; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -330,6 +382,36 @@ class Solution { } ``` +```csharp +public class Solution { + public bool CarPooling(int[][] trips, int capacity) { + List points = new List(); + + foreach (var trip in trips) { + int passengers = trip[0]; + int start = trip[1]; + int end = trip[2]; + + points.Add(new int[] { start, passengers }); + points.Add(new int[] { end, -passengers }); + } + + points.Sort((a, b) => { + if (a[0] == b[0]) return a[1] - b[1]; + return a[0] - b[0]; + }); + + int curPass = 0; + foreach (var point in points) { + curPass += point[1]; + if (curPass > capacity) return false; + } + + return true; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -459,6 +541,40 @@ class Solution { } ``` +```csharp +public class Solution { + public bool CarPooling(int[][] trips, int capacity) { + int L = int.MaxValue, R = int.MinValue; + + foreach (var trip in trips) { + int start = trip[1], end = trip[2]; + L = Math.Min(L, start); + R = Math.Max(R, end); + } + + int N = R - L + 1; + int[] passChange = new int[N + 1]; + + foreach (var trip in trips) { + int passengers = trip[0]; + int start = trip[1]; + int end = trip[2]; + + passChange[start - L] += passengers; + passChange[end - L] -= passengers; + } + + int curPass = 0; + foreach (int change in passChange) { + curPass += change; + if (curPass > capacity) return false; + } + + return true; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/combination-sum-iv.md b/articles/combination-sum-iv.md index 3a607251c..b2d2c5386 100644 --- a/articles/combination-sum-iv.md +++ b/articles/combination-sum-iv.md @@ -97,6 +97,31 @@ class Solution { } ``` +```csharp +public class Solution { + public int CombinationSum4(int[] nums, int target) { + Array.Sort(nums); + return Dfs(nums, target); + } + + private int Dfs(int[] nums, int total) { + if (total == 0) { + return 1; + } + + int res = 0; + foreach (int num in nums) { + if (total < num) { + break; + } + res += Dfs(nums, total - num); + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -222,6 +247,36 @@ class Solution { } ``` +```csharp +public class Solution { + private Dictionary memo; + + public int CombinationSum4(int[] nums, int target) { + Array.Sort(nums); + memo = new Dictionary(); + memo[0] = 1; + return Dfs(nums, target); + } + + private int Dfs(int[] nums, int total) { + if (memo.ContainsKey(total)) { + return memo[total]; + } + + int res = 0; + foreach (int num in nums) { + if (total < num) { + break; + } + res += Dfs(nums, total - num); + } + + memo[total] = res; + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -310,6 +365,26 @@ class Solution { } ``` +```csharp +public class Solution { + public int CombinationSum4(int[] nums, int target) { + Dictionary dp = new Dictionary(); + dp[0] = 1; + + for (int total = 1; total <= target; total++) { + dp[total] = 0; + foreach (int num in nums) { + if (dp.ContainsKey(total - num)) { + dp[total] += dp[total - num]; + } + } + } + + return dp[target]; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -403,6 +478,30 @@ class Solution { } ``` +```csharp +public class Solution { + public int CombinationSum4(int[] nums, int target) { + Array.Sort(nums); + Dictionary dp = new Dictionary(); + dp[target] = 1; + + for (int total = target; total > 0; total--) { + if (!dp.ContainsKey(total)) continue; + foreach (int num in nums) { + if (total < num) break; + int key = total - num; + if (!dp.ContainsKey(key)) { + dp[key] = 0; + } + dp[key] += dp[total]; + } + } + + return dp.ContainsKey(0) ? dp[0] : 0; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/combinations.md b/articles/combinations.md index d5e838baf..321ffeab1 100644 --- a/articles/combinations.md +++ b/articles/combinations.md @@ -105,6 +105,31 @@ class Solution { } ``` +```csharp +public class Solution { + public List> Combine(int n, int k) { + List> res = new List>(); + + void Backtrack(int i, List comb) { + if (i > n) { + if (comb.Count == k) { + res.Add(new List(comb)); + } + return; + } + + comb.Add(i); + Backtrack(i + 1, comb); + comb.RemoveAt(comb.Count - 1); + Backtrack(i + 1, comb); + } + + Backtrack(1, new List()); + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -220,6 +245,30 @@ class Solution { } ``` +```csharp +public class Solution { + public List> Combine(int n, int k) { + List> res = new List>(); + + void Backtrack(int start, List comb) { + if (comb.Count == k) { + res.Add(new List(comb)); + return; + } + + for (int i = start; i <= n; i++) { + comb.Add(i); + Backtrack(i + 1, comb); + comb.RemoveAt(comb.Count - 1); + } + } + + Backtrack(1, new List()); + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -348,6 +397,33 @@ class Solution { } ``` +```csharp +public class Solution { + public List> Combine(int n, int k) { + List> res = new List>(); + int[] comb = new int[k]; + int i = 0; + + while (i >= 0) { + comb[i]++; + if (comb[i] > n) { + i--; + continue; + } + + if (i == k - 1) { + res.Add(new List(comb)); + } else { + i++; + comb[i] = comb[i - 1]; + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -446,6 +522,28 @@ class Solution { } ``` +```csharp +public class Solution { + public List> Combine(int n, int k) { + List> res = new List>(); + + for (int mask = 0; mask < (1 << n); mask++) { + List comb = new List(); + for (int bit = 0; bit < n; bit++) { + if ((mask & (1 << bit)) != 0) { + comb.Add(bit + 1); + } + } + if (comb.Count == k) { + res.Add(comb); + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/construct-quad-tree.md b/articles/construct-quad-tree.md index 48e117a86..5e2b91594 100644 --- a/articles/construct-quad-tree.md +++ b/articles/construct-quad-tree.md @@ -237,6 +237,76 @@ class Solution { } ``` +```csharp +/* +// Definition for a QuadTree node. +public class Node { + public bool val; + public bool isLeaf; + public Node topLeft; + public Node topRight; + public Node bottomLeft; + public Node bottomRight; + + public Node() { + val = false; + isLeaf = false; + topLeft = null; + topRight = null; + bottomLeft = null; + bottomRight = null; + } + + public Node(bool _val, bool _isLeaf) { + val = _val; + isLeaf = _isLeaf; + topLeft = null; + topRight = null; + bottomLeft = null; + bottomRight = null; + } + + public Node(bool _val,bool _isLeaf,Node _topLeft,Node _topRight,Node _bottomLeft,Node _bottomRight) { + val = _val; + isLeaf = _isLeaf; + topLeft = _topLeft; + topRight = _topRight; + bottomLeft = _bottomLeft; + bottomRight = _bottomRight; + } +} +*/ + +public class Solution { + public Node Construct(int[][] grid) { + return Dfs(grid, grid.Length, 0, 0); + } + + private Node Dfs(int[][] grid, int n, int r, int c) { + bool allSame = true; + for (int i = 0; i < n && allSame; i++) { + for (int j = 0; j < n && allSame; j++) { + if (grid[r][c] != grid[r + i][c + j]) { + allSame = false; + } + } + } + + if (allSame) { + return new Node(grid[r][c] == 1, true); + } + + int half = n / 2; + Node topLeft = Dfs(grid, half, r, c); + Node topRight = Dfs(grid, half, r, c + half); + Node bottomLeft = Dfs(grid, half, r + half, c); + Node bottomRight = Dfs(grid, half, r + half, c + half); + + return new Node(false, false, topLeft, topRight, bottomLeft, bottomRight); + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -475,6 +545,75 @@ class Solution { } ``` +```csharp +/* +// Definition for a QuadTree node. +public class Node { + public bool val; + public bool isLeaf; + public Node topLeft; + public Node topRight; + public Node bottomLeft; + public Node bottomRight; + + public Node() { + val = false; + isLeaf = false; + topLeft = null; + topRight = null; + bottomLeft = null; + bottomRight = null; + } + + public Node(bool _val, bool _isLeaf) { + val = _val; + isLeaf = _isLeaf; + topLeft = null; + topRight = null; + bottomLeft = null; + bottomRight = null; + } + + public Node(bool _val,bool _isLeaf,Node _topLeft,Node _topRight,Node _bottomLeft,Node _bottomRight) { + val = _val; + isLeaf = _isLeaf; + topLeft = _topLeft; + topRight = _topRight; + bottomLeft = _bottomLeft; + bottomRight = _bottomRight; + } +} +*/ + +public class Solution { + public Node Construct(int[][] grid) { + return Dfs(grid, grid.Length, 0, 0); + } + + private Node Dfs(int[][] grid, int n, int r, int c) { + if (n == 1) { + return new Node(grid[r][c] == 1, true); + } + + int mid = n / 2; + Node topLeft = Dfs(grid, mid, r, c); + Node topRight = Dfs(grid, mid, r, c + mid); + Node bottomLeft = Dfs(grid, mid, r + mid, c); + Node bottomRight = Dfs(grid, mid, r + mid, c + mid); + + if (topLeft.isLeaf && topRight.isLeaf && + bottomLeft.isLeaf && bottomRight.isLeaf && + topLeft.val == topRight.val && + topRight.val == bottomLeft.val && + bottomLeft.val == bottomRight.val) { + return new Node(topLeft.val, true); + } + + return new Node(false, false, topLeft, topRight, bottomLeft, bottomRight); + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -725,6 +864,79 @@ class Solution { } ``` +```csharp +/* +// Definition for a QuadTree node. +public class Node { + public bool val; + public bool isLeaf; + public Node topLeft; + public Node topRight; + public Node bottomLeft; + public Node bottomRight; + + public Node() { + val = false; + isLeaf = false; + topLeft = null; + topRight = null; + bottomLeft = null; + bottomRight = null; + } + + public Node(bool _val, bool _isLeaf) { + val = _val; + isLeaf = _isLeaf; + topLeft = null; + topRight = null; + bottomLeft = null; + bottomRight = null; + } + + public Node(bool _val,bool _isLeaf,Node _topLeft,Node _topRight,Node _bottomLeft,Node _bottomRight) { + val = _val; + isLeaf = _isLeaf; + topLeft = _topLeft; + topRight = _topRight; + bottomLeft = _bottomLeft; + bottomRight = _bottomRight; + } +} +*/ + +public class Solution { + private readonly Node falseLeaf = new Node(false, true); + private readonly Node trueLeaf = new Node(true, true); + + public Node Construct(int[][] grid) { + int n = grid.Length; + return Dfs(grid, n, 0, 0); + } + + private Node Dfs(int[][] grid, int n, int r, int c) { + if (n == 1) { + return grid[r][c] == 1 ? trueLeaf : falseLeaf; + } + + int half = n / 2; + Node topLeft = Dfs(grid, half, r, c); + Node topRight = Dfs(grid, half, r, c + half); + Node bottomLeft = Dfs(grid, half, r + half, c); + Node bottomRight = Dfs(grid, half, r + half, c + half); + + if (topLeft.isLeaf && topRight.isLeaf && + bottomLeft.isLeaf && bottomRight.isLeaf && + topLeft.val == topRight.val && + topLeft.val == bottomLeft.val && + topLeft.val == bottomRight.val) { + return topLeft; + } + + return new Node(false, false, topLeft, topRight, bottomLeft, bottomRight); + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/contains-duplicate-ii.md b/articles/contains-duplicate-ii.md index 9e1c9367e..cc98d9da1 100644 --- a/articles/contains-duplicate-ii.md +++ b/articles/contains-duplicate-ii.md @@ -63,6 +63,21 @@ class Solution { } ``` +```csharp +public class Solution { + public bool ContainsNearbyDuplicate(int[] nums, int k) { + for (int L = 0; L < nums.Length; L++) { + for (int R = L + 1; R < Math.Min(nums.Length, L + k + 1); R++) { + if (nums[L] == nums[R]) { + return true; + } + } + } + return false; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -148,6 +163,23 @@ class Solution { } ``` +```csharp +public class Solution { + public bool ContainsNearbyDuplicate(int[] nums, int k) { + Dictionary mp = new Dictionary(); + + for (int i = 0; i < nums.Length; i++) { + if (mp.ContainsKey(nums[i]) && i - mp[nums[i]] <= k) { + return true; + } + mp[nums[i]] = i; + } + + return false; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -249,6 +281,28 @@ class Solution { } ``` +```csharp +public class Solution { + public bool ContainsNearbyDuplicate(int[] nums, int k) { + HashSet window = new HashSet(); + int L = 0; + + for (int R = 0; R < nums.Length; R++) { + if (R - L > k) { + window.Remove(nums[L]); + L++; + } + if (window.Contains(nums[R])) { + return true; + } + window.Add(nums[R]); + } + + return false; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/course-schedule-iv.md b/articles/course-schedule-iv.md index 0768d9038..0738453e4 100644 --- a/articles/course-schedule-iv.md +++ b/articles/course-schedule-iv.md @@ -109,6 +109,35 @@ class Solution { } ``` +```csharp +public class Solution { + public List CheckIfPrerequisite(int numCourses, int[][] prerequisites, int[][] queries) { + List[] adj = new List[numCourses]; + for (int i = 0; i < numCourses; i++) { + adj[i] = new List(); + } + + foreach (var pre in prerequisites) { + adj[pre[0]].Add(pre[1]); + } + + bool Dfs(int node, int target) { + if (node == target) return true; + foreach (var nei in adj[node]) { + if (Dfs(nei, target)) return true; + } + return false; + } + + var res = new List(); + foreach (var q in queries) { + res.Add(Dfs(q[0], q[1])); + } + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -259,6 +288,46 @@ class Solution { } ``` +```csharp +public class Solution { + public List CheckIfPrerequisite(int numCourses, int[][] prerequisites, int[][] queries) { + Dictionary> adj = new Dictionary>(); + for (int i = 0; i < numCourses; i++) { + adj[i] = new List(); + } + + foreach (var pair in prerequisites) { + int prereq = pair[0], crs = pair[1]; + adj[crs].Add(prereq); + } + + Dictionary> prereqMap = new Dictionary>(); + + HashSet Dfs(int crs) { + if (!prereqMap.ContainsKey(crs)) { + prereqMap[crs] = new HashSet(); + foreach (var prereq in adj[crs]) { + prereqMap[crs].UnionWith(Dfs(prereq)); + } + prereqMap[crs].Add(crs); + } + return prereqMap[crs]; + } + + for (int crs = 0; crs < numCourses; crs++) { + Dfs(crs); + } + + List res = new List(); + foreach (var q in queries) { + res.Add(prereqMap.ContainsKey(q[1]) && prereqMap[q[1]].Contains(q[0])); + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -416,6 +485,53 @@ class Solution { } ``` +```csharp +public class Solution { + public List CheckIfPrerequisite(int numCourses, int[][] prerequisites, int[][] queries) { + List[] adj = new List[numCourses]; + for (int i = 0; i < numCourses; i++) { + adj[i] = new List(); + } + + int[,] isPrereq = new int[numCourses, numCourses]; + for (int i = 0; i < numCourses; i++) { + for (int j = 0; j < numCourses; j++) { + isPrereq[i, j] = -1; + } + } + + foreach (var pair in prerequisites) { + int prereq = pair[0], crs = pair[1]; + adj[crs].Add(prereq); + isPrereq[crs, prereq] = 1; + } + + bool Dfs(int crs, int prereq) { + if (isPrereq[crs, prereq] != -1) { + return isPrereq[crs, prereq] == 1; + } + + foreach (int pre in adj[crs]) { + if (pre == prereq || Dfs(pre, prereq)) { + isPrereq[crs, prereq] = 1; + return true; + } + } + + isPrereq[crs, prereq] = 0; + return false; + } + + List res = new List(); + foreach (var q in queries) { + res.Add(Dfs(q[1], q[0])); + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -572,6 +688,56 @@ class Solution { } ``` +```csharp +public class Solution { + public List CheckIfPrerequisite(int numCourses, int[][] prerequisites, int[][] queries) { + List> adj = new List>(); + List> isPrereq = new List>(); + int[] indegree = new int[numCourses]; + + for (int i = 0; i < numCourses; i++) { + adj.Add(new HashSet()); + isPrereq.Add(new HashSet()); + } + + foreach (var pair in prerequisites) { + int pre = pair[0], crs = pair[1]; + adj[pre].Add(crs); + indegree[crs]++; + } + + Queue q = new Queue(); + for (int i = 0; i < numCourses; i++) { + if (indegree[i] == 0) { + q.Enqueue(i); + } + } + + while (q.Count > 0) { + int node = q.Dequeue(); + foreach (int neighbor in adj[node]) { + isPrereq[neighbor].Add(node); + foreach (int p in isPrereq[node]) { + isPrereq[neighbor].Add(p); + } + indegree[neighbor]--; + if (indegree[neighbor] == 0) { + q.Enqueue(neighbor); + } + } + } + + List result = new List(); + foreach (var query in queries) { + int u = query[0], v = query[1]; + result.Add(isPrereq[v].Contains(u)); + } + + return result; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -695,6 +861,35 @@ class Solution { } ``` +```csharp +public class Solution { + public List CheckIfPrerequisite(int numCourses, int[][] prerequisites, int[][] queries) { + bool[,] adj = new bool[numCourses, numCourses]; + + foreach (var pair in prerequisites) { + int pre = pair[0], crs = pair[1]; + adj[pre, crs] = 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]); + } + } + } + + List res = new List(); + foreach (var query in queries) { + int u = query[0], v = query[1]; + res.Add(adj[u, v]); + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/decode-string.md b/articles/decode-string.md index c5363f71b..c86b9b8f1 100644 --- a/articles/decode-string.md +++ b/articles/decode-string.md @@ -143,6 +143,46 @@ class Solution { } ``` +```csharp +public class Solution { + private int i; + + public string DecodeString(string s) { + i = 0; + return Helper(s); + } + + private string Helper(string s) { + string res = ""; + int k = 0; + + while (i < s.Length) { + char c = s[i]; + + if (char.IsDigit(c)) { + k = k * 10 + (c - '0'); + } else if (c == '[') { + i++; + string inner = Helper(s); + res += new string(' ', 0).PadLeft(0); + for (int j = 0; j < k; j++) { + res += inner; + } + k = 0; + } else if (c == ']') { + return res; + } else { + res += c; + } + + i++; + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -290,6 +330,41 @@ class Solution { } ``` +```csharp +public class Solution { + public string DecodeString(string s) { + Stack stack = new Stack(); + + for (int i = 0; i < s.Length; i++) { + if (s[i] != ']') { + stack.Push(s[i].ToString()); + } else { + string substr = ""; + while (stack.Peek() != "[") { + substr = stack.Pop() + substr; + } + stack.Pop(); // remove '[' + + string k = ""; + while (stack.Count > 0 && char.IsDigit(stack.Peek()[0])) { + k = stack.Pop() + k; + } + + int repeat = int.Parse(k); + string expanded = new StringBuilder().Insert(0, substr, repeat).ToString(); + stack.Push(expanded); + } + } + + var result = new StringBuilder(); + foreach (string part in stack) { + result.Insert(0, part); + } + return result.ToString(); + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -436,6 +511,39 @@ class Solution { } ``` +```csharp +public class Solution { + public string DecodeString(string s) { + Stack stringStack = new Stack(); + Stack countStack = new Stack(); + string cur = ""; + int k = 0; + + foreach (char c in s) { + if (char.IsDigit(c)) { + k = k * 10 + (c - '0'); + } else if (c == '[') { + stringStack.Push(cur); + countStack.Push(k); + cur = ""; + k = 0; + } else if (c == ']') { + string temp = cur; + cur = stringStack.Pop(); + int count = countStack.Pop(); + for (int i = 0; i < count; i++) { + cur += temp; + } + } else { + cur += c; + } + } + + return cur; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/delete-leaves-with-a-given-value.md b/articles/delete-leaves-with-a-given-value.md index ccfb4637b..add3a0494 100644 --- a/articles/delete-leaves-with-a-given-value.md +++ b/articles/delete-leaves-with-a-given-value.md @@ -122,6 +122,36 @@ class Solution { } ``` +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public int val; + * public TreeNode left; + * public TreeNode right; + * public TreeNode(int val=0, TreeNode left=null, TreeNode right=null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public TreeNode RemoveLeafNodes(TreeNode root, int target) { + if (root == null) return null; + + root.left = RemoveLeafNodes(root.left, target); + root.right = RemoveLeafNodes(root.right, target); + + if (root.left == null && root.right == null && root.val == target) { + return null; + } + + return root; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -343,6 +373,62 @@ class Solution { } ``` +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public int val; + * public TreeNode left; + * public TreeNode right; + * public TreeNode(int val=0, TreeNode left=null, TreeNode right=null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public TreeNode RemoveLeafNodes(TreeNode root, int target) { + if (root == null) return null; + + Stack stack = new Stack(); + HashSet visited = new HashSet(); + Dictionary parents = new Dictionary(); + + stack.Push(root); + parents[root] = null; + + while (stack.Count > 0) { + TreeNode node = stack.Pop(); + + if (node.left == null && node.right == null) { + if (node.val == target) { + TreeNode parent = parents[node]; + if (parent == null) { + return null; + } + if (parent.left == node) parent.left = null; + if (parent.right == node) parent.right = null; + } + } else if (!visited.Contains(node)) { + visited.Add(node); + stack.Push(node); + if (node.left != null) { + stack.Push(node.left); + parents[node.left] = node; + } + if (node.right != null) { + stack.Push(node.right); + parents[node.right] = node; + } + } + } + + return root; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -569,6 +655,62 @@ class Solution { } ``` +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public int val; + * public TreeNode left; + * public TreeNode right; + * public TreeNode(int val=0, TreeNode left=null, TreeNode right=null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public TreeNode RemoveLeafNodes(TreeNode root, int target) { + if (root == null) return null; + + Stack stack = new Stack(); + TreeNode cur = root; + TreeNode visited = null; + + while (stack.Count > 0 || cur != null) { + while (cur != null) { + stack.Push(cur); + cur = cur.left; + } + + cur = stack.Peek(); + if (cur.right != null && cur.right != visited) { + cur = cur.right; + continue; + } + + stack.Pop(); + if (cur.left == null && cur.right == null && cur.val == target) { + if (stack.Count == 0) return null; + + TreeNode parent = stack.Peek(); + if (parent.left == cur) { + parent.left = null; + } else if (parent.right == cur) { + parent.right = null; + } + } else { + visited = cur; + } + + cur = null; + } + + return root; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/delete-node-in-a-bst.md b/articles/delete-node-in-a-bst.md index 4b086145a..0a9617193 100644 --- a/articles/delete-node-in-a-bst.md +++ b/articles/delete-node-in-a-bst.md @@ -153,6 +153,45 @@ class Solution { } ``` +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public int val; + * public TreeNode left; + * public TreeNode right; + * public TreeNode(int val=0, TreeNode left=null, TreeNode right=null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public TreeNode DeleteNode(TreeNode root, int key) { + if (root == null) return null; + + if (key > root.val) { + root.right = DeleteNode(root.right, key); + } else if (key < root.val) { + root.left = DeleteNode(root.left, key); + } else { + if (root.left == null) return root.right; + if (root.right == null) return root.left; + + TreeNode cur = root.right; + while (cur.left != null) { + cur = cur.left; + } + root.val = cur.val; + root.right = DeleteNode(root.right, root.val); + } + + return root; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -327,6 +366,46 @@ class Solution { } ``` +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public int val; + * public TreeNode left; + * public TreeNode right; + * public TreeNode(int val=0, TreeNode left=null, TreeNode right=null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public TreeNode DeleteNode(TreeNode root, int key) { + if (root == null) return null; + + if (key > root.val) { + root.right = DeleteNode(root.right, key); + } else if (key < root.val) { + root.left = DeleteNode(root.left, key); + } else { + if (root.left == null) return root.right; + if (root.right == null) return root.left; + + TreeNode cur = root.right; + while (cur.left != null) { + cur = cur.left; + } + cur.left = root.left; + TreeNode res = root.right; + return res; + } + + return root; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -622,6 +701,85 @@ class Solution { } ``` +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public int val; + * public TreeNode left; + * public TreeNode right; + * public TreeNode(int val=0, TreeNode left=null, TreeNode right=null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public TreeNode DeleteNode(TreeNode root, int key) { + if (root == null) return null; + + TreeNode parent = null; + TreeNode cur = root; + + // Find the node to delete + while (cur != null && cur.val != key) { + parent = cur; + if (key > cur.val) { + cur = cur.right; + } else { + cur = cur.left; + } + } + + if (cur == null) return root; + + // Node with one or no child + if (cur.left == null || cur.right == null) { + TreeNode child = cur.left != null ? cur.left : cur.right; + + if (parent == null) { + return child; + } + + if (parent.left == cur) { + parent.left = child; + } else { + parent.right = child; + } + } else { + // Node with two children + TreeNode par = null; + TreeNode delNode = cur; + cur = cur.right; + while (cur.left != null) { + par = cur; + cur = cur.left; + } + + if (par != null) { + par.left = cur.right; + cur.right = delNode.right; + } + + cur.left = delNode.left; + + if (parent == null) { + return cur; + } + + if (parent.left == delNode) { + parent.left = cur; + } else { + parent.right = cur; + } + } + + return root; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/evaluate-division.md b/articles/evaluate-division.md index 647a8002b..9be40ad06 100644 --- a/articles/evaluate-division.md +++ b/articles/evaluate-division.md @@ -199,6 +199,56 @@ class Solution { } ``` +```csharp +public class Solution { + public double[] CalcEquation(List> equations, double[] values, List> queries) { + var adj = new Dictionary>(); + + for (int i = 0; i < equations.Count; i++) { + string a = equations[i][0]; + string b = equations[i][1]; + double val = values[i]; + + if (!adj.ContainsKey(a)) adj[a] = new List<(string, double)>(); + if (!adj.ContainsKey(b)) adj[b] = new List<(string, double)>(); + + adj[a].Add((b, val)); + adj[b].Add((a, 1.0 / val)); + } + + double Bfs(string src, string target) { + if (!adj.ContainsKey(src) || !adj.ContainsKey(target)) return -1.0; + var queue = new Queue<(string, double)>(); + var visited = new HashSet(); + + queue.Enqueue((src, 1.0)); + visited.Add(src); + + while (queue.Count > 0) { + var (node, weight) = queue.Dequeue(); + if (node == target) return weight; + + foreach (var (nei, w) in adj[node]) { + if (!visited.Contains(nei)) { + visited.Add(nei); + queue.Enqueue((nei, weight * w)); + } + } + } + + return -1.0; + } + + double[] res = new double[queries.Count]; + for (int i = 0; i < queries.Count; i++) { + res[i] = Bfs(queries[i][0], queries[i][1]); + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -391,6 +441,51 @@ class Solution { } ``` +```csharp +public class Solution { + public double[] CalcEquation(List> equations, double[] values, List> queries) { + var adj = new Dictionary>(); + + for (int i = 0; i < equations.Count; i++) { + string a = equations[i][0], b = equations[i][1]; + double val = values[i]; + + if (!adj.ContainsKey(a)) adj[a] = new List<(string, double)>(); + if (!adj.ContainsKey(b)) adj[b] = new List<(string, double)>(); + + adj[a].Add((b, val)); + adj[b].Add((a, 1.0 / val)); + } + + double Dfs(string src, string target, HashSet visited) { + if (!adj.ContainsKey(src) || !adj.ContainsKey(target)) return -1.0; + if (src == target) return 1.0; + + visited.Add(src); + + foreach (var (nei, weight) in adj[src]) { + if (!visited.Contains(nei)) { + double result = Dfs(nei, target, visited); + if (result != -1.0) { + return weight * result; + } + } + } + + return -1.0; + } + + double[] res = new double[queries.Count]; + for (int i = 0; i < queries.Count; i++) { + var visited = new HashSet(); + res[i] = Dfs(queries[i][0], queries[i][1], visited); + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -666,6 +761,69 @@ class Solution { } ``` +```csharp +public class UnionFind { + private Dictionary parent = new Dictionary(); + private Dictionary weight = new Dictionary(); + + public void Add(string x) { + if (!parent.ContainsKey(x)) { + parent[x] = x; + weight[x] = 1.0; + } + } + + public string Find(string x) { + if (parent[x] != x) { + string origParent = parent[x]; + parent[x] = Find(origParent); + weight[x] *= weight[origParent]; + } + return parent[x]; + } + + public void Union(string x, string y, double value) { + Add(x); + Add(y); + string rootX = Find(x); + string rootY = Find(y); + + if (rootX != rootY) { + parent[rootX] = rootY; + weight[rootX] = value * weight[y] / weight[x]; + } + } + + public double GetRatio(string x, string y) { + if (!parent.ContainsKey(x) || !parent.ContainsKey(y) || Find(x) != Find(y)) { + return -1.0; + } + return weight[x] / weight[y]; + } +} + +public class Solution { + public double[] CalcEquation(List> equations, double[] values, List> queries) { + var uf = new UnionFind(); + + for (int i = 0; i < equations.Count; i++) { + string a = equations[i][0]; + string b = equations[i][1]; + uf.Union(a, b, values[i]); + } + + double[] res = new double[queries.Count]; + for (int i = 0; i < queries.Count; i++) { + string a = queries[i][0]; + string b = queries[i][1]; + res[i] = uf.GetRatio(a, b); + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -826,6 +984,49 @@ class Solution { } ``` +```csharp +public class Solution { + public double[] CalcEquation(List> equations, double[] values, List> queries) { + var graph = new Dictionary>(); + + for (int i = 0; i < equations.Count; i++) { + string a = equations[i][0]; + string b = equations[i][1]; + double val = values[i]; + + if (!graph.ContainsKey(a)) graph[a] = new Dictionary(); + if (!graph.ContainsKey(b)) graph[b] = new Dictionary(); + + graph[a][b] = val; + graph[b][a] = 1.0 / val; + } + + foreach (var k in graph.Keys.ToList()) { + foreach (var i in graph[k].Keys.ToList()) { + foreach (var j in graph[k].Keys.ToList()) { + if (!graph[i].ContainsKey(j)) { + graph[i][j] = graph[i][k] * graph[k][j]; + } + } + } + } + + double[] result = new double[queries.Count]; + for (int i = 0; i < queries.Count; i++) { + string a = queries[i][0]; + string b = queries[i][1]; + if (graph.ContainsKey(a) && graph[a].ContainsKey(b)) { + result[i] = graph[a][b]; + } else { + result[i] = -1.0; + } + } + + return result; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/extra-characters-in-a-string.md b/articles/extra-characters-in-a-string.md index b41af1f45..6b2052693 100644 --- a/articles/extra-characters-in-a-string.md +++ b/articles/extra-characters-in-a-string.md @@ -104,6 +104,30 @@ class Solution { } ``` +```csharp +public class Solution { + public int MinExtraChar(string s, string[] dictionary) { + HashSet words = new HashSet(dictionary); + return Dfs(0, s, words); + } + + private int Dfs(int i, string s, HashSet 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 - i + 1))) { + res = Math.Min(res, Dfs(j + 1, s, words)); + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -220,6 +244,34 @@ class Solution { } ``` +```csharp +public class Solution { + public int MinExtraChar(string s, string[] dictionary) { + HashSet words = new HashSet(dictionary); + int n = s.Length; + int[] dp = new int[n + 1]; + Array.Fill(dp, -1); + dp[n] = 0; + + return Dfs(0, s, words, dp); + } + + private int Dfs(int i, string s, HashSet 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 - i + 1))) { + res = Math.Min(res, Dfs(j + 1, s, words, dp)); + } + } + + dp[i] = res; + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -316,6 +368,27 @@ class Solution { } ``` +```csharp +public class Solution { + public int MinExtraChar(string s, string[] dictionary) { + HashSet words = new HashSet(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 - i + 1))) { + dp[i] = Math.Min(dp[i], dp[j + 1]); + } + } + } + + return dp[0]; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -467,6 +540,43 @@ class Solution { } ``` +```csharp +public class Solution { + public int MinExtraChar(string s, string[] dictionary) { + Dictionary dp = new Dictionary(); + dp[s.Length] = 0; + return Dfs(0, s, dictionary, dp); + } + + private int Dfs(int i, string s, string[] dictionary, Dictionary dp) { + if (dp.ContainsKey(i)) { + return dp[i]; + } + + int res = 1 + Dfs(i + 1, s, dictionary, dp); + + foreach (string word in dictionary) { + if (i + word.Length > s.Length) continue; + + bool flag = true; + for (int 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, s, dictionary, dp)); + } + } + + dp[i] = res; + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -563,6 +673,26 @@ class Solution { } ``` +```csharp +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]; + foreach (string word in dictionary) { + if (i + word.Length <= n && s.Substring(i, word.Length) == word) { + dp[i] = Math.Min(dp[i], dp[i + word.Length]); + } + } + } + + return dp[0]; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -819,6 +949,63 @@ class Solution { } ``` +```csharp +public class TrieNode { + public TrieNode[] Children = new TrieNode[26]; + public bool IsWord = false; +} + +public class Trie { + public TrieNode Root = new TrieNode(); + + public void AddWord(string word) { + TrieNode curr = Root; + foreach (char c in word) { + int idx = c - 'a'; + if (curr.Children[idx] == null) { + curr.Children[idx] = new TrieNode(); + } + curr = curr.Children[idx]; + } + curr.IsWord = true; + } +} + +public class Solution { + public int MinExtraChar(string s, string[] dictionary) { + Trie trie = new Trie(); + foreach (string word in dictionary) { + trie.AddWord(word); + } + + int[] dp = new int[s.Length + 1]; + Array.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++) { + int idx = s[j] - 'a'; + if (curr.Children[idx] == null) break; + curr = curr.Children[idx]; + if (curr.IsWord) { + res = Math.Min(res, Dfs(j + 1, s, trie, dp)); + } + } + + dp[i] = res; + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -1052,6 +1239,57 @@ class Solution { } ``` +```csharp +public class TrieNode { + public TrieNode[] Children = new TrieNode[26]; + public bool IsWord = false; +} + +public class Trie { + public TrieNode Root = new TrieNode(); + + public void AddWord(string word) { + TrieNode curr = Root; + foreach (char c in word) { + int idx = c - 'a'; + if (curr.Children[idx] == null) { + curr.Children[idx] = new TrieNode(); + } + curr = curr.Children[idx]; + } + curr.IsWord = true; + } +} + +public class Solution { + public int MinExtraChar(string s, string[] dictionary) { + Trie trie = new Trie(); + foreach (string word in 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++) { + int idx = s[j] - 'a'; + if (curr.Children[idx] == null) break; + curr = curr.Children[idx]; + if (curr.IsWord) { + dp[i] = Math.Min(dp[i], dp[j + 1]); + } + } + } + + return dp[0]; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/find-in-mountain-array.md b/articles/find-in-mountain-array.md index f687ba271..c917a7507 100644 --- a/articles/find-in-mountain-array.md +++ b/articles/find-in-mountain-array.md @@ -78,18 +78,18 @@ public: /** * // This is the MountainArray's API interface. * // You should not implement it, or speculate about its implementation - * function MountainArray() { + * class MountainArray { * @param {number} index * @return {number} - * this.get = function(index) { + * get(index) { * ... - * }; + * } * * @return {number} - * this.length = function() { + * length() { * ... - * }; - * }; + * } + * } */ class Solution { @@ -112,6 +112,31 @@ class Solution { } ``` +```csharp +/** + * // This is MountainArray's API interface. + * // You should not implement it, or speculate about its implementation + * class MountainArray { + * public int Get(int index) {} + * public int Length() {} + * } + */ + +class Solution { + public int FindInMountainArray(int target, MountainArray mountainArr) { + int n = mountainArr.Length(); + + for (int i = 0; i < n; i++) { + if (mountainArr.Get(i) == target) { + return i; + } + } + + return -1; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -316,18 +341,18 @@ public: /** * // This is the MountainArray's API interface. * // You should not implement it, or speculate about its implementation - * function MountainArray() { + * class MountainArray { * @param {number} index * @return {number} - * this.get = function(index) { + * get(index) { * ... - * }; + * } * * @return {number} - * this.length = function() { + * length() { * ... - * }; - * }; + * } + * } */ class Solution { @@ -391,6 +416,72 @@ class Solution { } ``` +```csharp +/** + * // This is MountainArray's API interface. + * // You should not implement it, or speculate about its implementation + * class MountainArray { + * public int Get(int index) {} + * public int Length() {} + * } + */ + +class Solution { + public int FindInMountainArray(int target, MountainArray mountainArr) { + int length = mountainArr.Length(); + + // Find Peak + int l = 1, r = length - 2, peak = 0; + while (l <= r) { + int m = (l + r) / 2; + int left = mountainArr.Get(m - 1); + int mid = mountainArr.Get(m); + int right = mountainArr.Get(m + 1); + if (left < mid && mid < right) { + l = m + 1; + } else if (left > mid && mid > right) { + r = m - 1; + } else { + peak = m; + break; + } + } + + // Search left portion + l = 0; + r = peak - 1; + while (l <= r) { + int m = (l + r) / 2; + int val = mountainArr.Get(m); + if (val < target) { + l = m + 1; + } else if (val > target) { + r = m - 1; + } else { + return m; + } + } + + // Search right portion + l = peak; + r = length - 1; + while (l <= r) { + int m = (l + r) / 2; + int val = mountainArr.Get(m); + if (val > target) { + l = m + 1; + } else if (val < target) { + r = m - 1; + } else { + return m; + } + } + + return -1; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -600,18 +691,18 @@ public: /** * // This is the MountainArray's API interface. * // You should not implement it, or speculate about its implementation - * function MountainArray() { + * class MountainArray { * @param {number} index * @return {number} - * this.get = function(index) { + * get(index) { * ... - * }; + * } * * @return {number} - * this.length = function() { + * length() { * ... - * }; - * }; + * } + * } */ class Solution { @@ -676,6 +767,73 @@ class Solution { } ``` +```csharp +/** + * // This is MountainArray's API interface. + * // You should not implement it, or speculate about its implementation + * class MountainArray { + * public int Get(int index) {} + * public int Length() {} + * } + */ + +class Solution { + private Dictionary cache = new Dictionary(); + + private int Get(int index, MountainArray mountainArr) { + if (!cache.ContainsKey(index)) { + cache[index] = mountainArr.Get(index); + } + return cache[index]; + } + + private int BinarySearch(int l, int r, bool ascending, MountainArray mountainArr, int target) { + while (l <= r) { + int m = (l + r) >> 1; + int val = Get(m, mountainArr); + if (val == target) { + return m; + } + if ((ascending && val < target) || (!ascending && val > target)) { + l = m + 1; + } else { + r = m - 1; + } + } + return -1; + } + + public int FindInMountainArray(int target, MountainArray mountainArr) { + int length = mountainArr.Length(); + + // Find Peak + int l = 1, r = length - 2, peak = 0; + while (l <= r) { + int m = (l + r) >> 1; + int left = Get(m - 1, mountainArr); + int mid = Get(m, mountainArr); + int right = Get(m + 1, mountainArr); + + if (left < mid && mid < right) { + l = m + 1; + } else if (left > mid && mid > right) { + r = m - 1; + } else { + peak = m; + break; + } + } + + // Search left portion + int res = BinarySearch(0, peak, true, mountainArr, target); + if (res != -1) return res; + + // Search right portion + return BinarySearch(peak, length - 1, false, mountainArr, target); + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/find-the-town-judge.md b/articles/find-the-town-judge.md index 393448cd8..a1343bd35 100644 --- a/articles/find-the-town-judge.md +++ b/articles/find-the-town-judge.md @@ -89,6 +89,30 @@ class Solution { } ``` +```csharp +public class Solution { + public int FindJudge(int n, int[][] trust) { + int[] incoming = new int[n + 1]; + int[] outgoing = new int[n + 1]; + + foreach (int[] t in trust) { + int a = t[0]; + int b = t[1]; + outgoing[a]++; + incoming[b]++; + } + + for (int i = 1; i <= n; i++) { + if (outgoing[i] == 0 && incoming[i] == n - 1) { + return i; + } + } + + return -1; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -189,6 +213,28 @@ class Solution { } ``` +```csharp +public class Solution { + public int FindJudge(int n, int[][] trust) { + int[] delta = new int[n + 1]; + + foreach (int[] t in trust) { + int a = t[0]; + int b = t[1]; + delta[a]--; + delta[b]++; + } + + for (int i = 1; i <= n; i++) { + if (delta[i] == n - 1) { + return i; + } + } + return -1; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/greatest-common-divisor-traversal.md b/articles/greatest-common-divisor-traversal.md index 79c11cf70..57628c98a 100644 --- a/articles/greatest-common-divisor-traversal.md +++ b/articles/greatest-common-divisor-traversal.md @@ -144,6 +144,53 @@ class Solution { } ``` +```csharp +public class Solution { + public bool CanTraverseAllPairs(int[] nums) { + int n = nums.Length; + bool[] visited = new bool[n]; + List[] adj = new List[n]; + for (int i = 0; i < n; i++) { + adj[i] = new List(); + } + + for (int i = 0; i < n; i++) { + for (int j = i + 1; j < n; j++) { + if (GCD(nums[i], nums[j]) > 1) { + adj[i].Add(j); + adj[j].Add(i); + } + } + } + + void DFS(int node) { + visited[node] = true; + foreach (int neighbor in adj[node]) { + if (!visited[neighbor]) { + DFS(neighbor); + } + } + } + + DFS(0); + foreach (bool v in visited) { + if (!v) return false; + } + + return true; + } + + private int GCD(int a, int b) { + while (b != 0) { + int temp = b; + b = a % b; + a = temp; + } + return a; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -189,7 +236,7 @@ class Solution: uf = UnionFind(len(nums)) factor_index = {} # f -> index of value with factor f - for i, num in enumerate(nums): + for i, n in enumerate(nums): f = 2 while f * f <= n: if n % f == 0: @@ -206,7 +253,7 @@ class Solution: else: factor_index[n] = i - return uf.isConnected() + return uf.isConnected() ``` ```java @@ -452,6 +499,87 @@ class Solution { } ``` +```csharp +public class Solution { + public class UnionFind { + public int Count; + private int[] Parent; + private int[] Size; + + public UnionFind(int n) { + Count = n; + Parent = new int[n]; + Size = new int[n]; + for (int i = 0; i < n; i++) { + Parent[i] = i; + Size[i] = 1; + } + } + + public int Find(int x) { + if (Parent[x] != x) { + Parent[x] = Find(Parent[x]); + } + return Parent[x]; + } + + public bool Union(int x, int y) { + int px = Find(x); + int py = Find(y); + if (px == py) return false; + Count--; + if (Size[px] < Size[py]) { + int temp = px; + px = py; + py = temp; + } + Size[px] += Size[py]; + Parent[py] = px; + return true; + } + + public bool IsConnected() { + return Count == 1; + } + } + + public bool CanTraverseAllPairs(int[] nums) { + int n = nums.Length; + if (n == 1) return true; + if (Array.Exists(nums, x => x == 1)) return false; + + UnionFind uf = new UnionFind(n); + Dictionary factorIndex = new Dictionary(); + + for (int i = 0; i < n; i++) { + int num = nums[i]; + int original = num; + for (int f = 2; f * f <= num; f++) { + if (num % f == 0) { + if (factorIndex.ContainsKey(f)) { + uf.Union(i, factorIndex[f]); + } else { + factorIndex[f] = i; + } + while (num % f == 0) { + num /= f; + } + } + } + if (num > 1) { + if (factorIndex.ContainsKey(num)) { + uf.Union(i, factorIndex[num]); + } else { + factorIndex[num] = i; + } + } + } + + return uf.IsConnected(); + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -790,6 +918,86 @@ class Solution { } ``` +```csharp +public class UnionFind { + public int[] Parent; + public int[] Size; + + public UnionFind(int n) { + Parent = new int[n]; + Size = new int[n]; + for (int i = 0; i < n; i++) { + Parent[i] = i; + Size[i] = 1; + } + } + + public int Find(int x) { + if (Parent[x] != x) { + Parent[x] = Find(Parent[x]); + } + return Parent[x]; + } + + public bool Union(int x, int y) { + int px = Find(x); + int py = Find(y); + if (px == py) return false; + if (Size[px] < Size[py]) { + int temp = px; + px = py; + py = temp; + } + Parent[py] = px; + Size[px] += Size[py]; + return true; + } +} + +public class Solution { + public bool CanTraverseAllPairs(int[] nums) { + int n = nums.Length; + if (n == 1) return true; + if (Array.Exists(nums, x => x == 1)) return false; + + int maxVal = nums.Max(); + int[] sieve = new int[maxVal + 1]; + for (int i = 2; i * i <= maxVal; i++) { + if (sieve[i] == 0) { + for (int j = i * i; j <= maxVal; j += i) { + if (sieve[j] == 0) sieve[j] = i; + } + } + } + + UnionFind uf = new UnionFind(n + maxVal + 1); + + for (int i = 0; i < n; i++) { + int num = nums[i]; + if (sieve[num] == 0) { + uf.Union(i, n + num); + continue; + } + + while (num > 1) { + int prime = sieve[num] != 0 ? sieve[num] : num; + uf.Union(i, n + prime); + while (num % prime == 0) { + num /= prime; + } + } + } + + int root = uf.Find(0); + for (int i = 1; i < n; i++) { + if (uf.Find(i) != root) return false; + } + + return true; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -1029,6 +1237,70 @@ class Solution { } ``` +```csharp +public class Solution { + public bool CanTraverseAllPairs(int[] nums) { + int N = nums.Length; + if (N == 1) return true; + if (Array.Exists(nums, num => num == 1)) return false; + + int MAX = nums.Max(); + int[] sieve = new int[MAX + 1]; + for (int p = 2; p * p <= MAX; p++) { + if (sieve[p] == 0) { + for (int mult = p * p; mult <= MAX; mult += p) { + if (sieve[mult] == 0) { + sieve[mult] = p; + } + } + } + } + + Dictionary> adj = new Dictionary>(); + for (int i = 0; i < N; i++) { + int num = nums[i]; + if (sieve[num] == 0) { + AddEdge(adj, i, N + num); + continue; + } + while (num > 1) { + int prime = sieve[num] != 0 ? sieve[num] : num; + AddEdge(adj, i, N + prime); + while (num % prime == 0) { + num /= prime; + } + } + } + + HashSet visited = new HashSet(); + DFS(0, adj, visited); + + for (int i = 0; i < N; i++) { + if (!visited.Contains(i)) return false; + } + + return true; + } + + private void AddEdge(Dictionary> adj, int u, int v) { + if (!adj.ContainsKey(u)) adj[u] = new List(); + if (!adj.ContainsKey(v)) adj[v] = new List(); + adj[u].Add(v); + adj[v].Add(u); + } + + private void DFS(int node, Dictionary> adj, HashSet visited) { + visited.Add(node); + if (!adj.ContainsKey(node)) return; + foreach (int nei in adj[node]) { + if (!visited.Contains(nei)) { + DFS(nei, adj, visited); + } + } + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -1295,6 +1567,74 @@ class Solution { } ``` +```csharp +public class Solution { + public bool CanTraverseAllPairs(int[] nums) { + int N = nums.Length; + if (N == 1) return true; + if (nums.Contains(1)) return false; + + int MAX = nums.Max(); + int[] sieve = new int[MAX + 1]; + for (int p = 2; p * p <= MAX; p++) { + if (sieve[p] == 0) { + for (int composite = p * p; composite <= MAX; composite += p) { + if (sieve[composite] == 0) { + sieve[composite] = p; + } + } + } + } + + Dictionary> adj = new Dictionary>(); + for (int i = 0; i < N; i++) { + int num = nums[i]; + if (sieve[num] == 0) { + AddEdge(adj, i, N + num); + continue; + } + + while (num > 1) { + int prime = sieve[num] != 0 ? sieve[num] : num; + AddEdge(adj, i, N + prime); + while (num % prime == 0) { + num /= prime; + } + } + } + + HashSet visited = new HashSet(); + Queue queue = new Queue(); + queue.Enqueue(0); + visited.Add(0); + + while (queue.Count > 0) { + int node = queue.Dequeue(); + if (!adj.ContainsKey(node)) continue; + foreach (int nei in adj[node]) { + if (!visited.Contains(nei)) { + visited.Add(nei); + queue.Enqueue(nei); + } + } + } + + for (int i = 0; i < N; i++) { + if (!visited.Contains(i)) return false; + } + + return true; + } + + private void AddEdge(Dictionary> adj, int u, int v) { + if (!adj.ContainsKey(u)) adj[u] = new List(); + if (!adj.ContainsKey(v)) adj[v] = new List(); + adj[u].Add(v); + adj[v].Add(u); + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/guess-number-higher-or-lower.md b/articles/guess-number-higher-or-lower.md index b6053e2e8..4946e4968 100644 --- a/articles/guess-number-higher-or-lower.md +++ b/articles/guess-number-higher-or-lower.md @@ -65,7 +65,7 @@ public: * @return -1 if num is higher than the picked number * 1 if num is lower than the picked number * otherwise return 0 - * var guess = function(num) {} + * function guess(num) {} */ class Solution { @@ -82,6 +82,26 @@ class Solution { } ``` +```csharp +/** + * Forward declaration of guess API. + * @param num your guess + * @return -1 if num is higher than the picked number + * 1 if num is lower than the picked number + * otherwise return 0 + * int guess(int num); + */ + +public class Solution : GuessGame { + public int GuessNumber(int n) { + for (int num = 1; num <= n; num++) { + if (guess(num) == 0) return num; + } + return n; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -181,7 +201,7 @@ public: * @return -1 if num is higher than the picked number * 1 if num is lower than the picked number * otherwise return 0 - * var guess = function(num) {} + * function guess(num) {} */ class Solution { @@ -206,6 +226,26 @@ class Solution { } ``` +```csharp +/** + * Forward declaration of guess API. + * @param num your guess + * @return -1 if num is higher than the picked number + * 1 if num is lower than the picked number + * otherwise return 0 + * int guess(int num); + */ + +public class Solution : GuessGame { + public int GuessNumber(int n) { + for (int num = 1; num <= n; num++) { + if (guess(num) == 0) return num; + } + return n; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -316,7 +356,7 @@ public: * @return -1 if num is higher than the picked number * 1 if num is lower than the picked number * otherwise return 0 - * var guess = function(num) {} + * function guess(num) {} */ class Solution { @@ -344,6 +384,41 @@ class Solution { } ``` +```csharp +/** + * Forward declaration of guess API. + * @param num your guess + * @return -1 if num is higher than the picked number + * 1 if num is lower than the picked number + * otherwise return 0 + * int guess(int num); + */ + +public class Solution : GuessGame { + public int GuessNumber(int n) { + int l = 1, r = n; + while (true) { + int m1 = l + (r - l) / 3; + int m2 = r - (r - l) / 3; + + if (guess(m1) == 0) return m1; + if (guess(m2) == 0) return m2; + + if (guess(m1) + guess(m2) == 0) { + l = m1 + 1; + r = m2 - 1; + } + else if (guess(m1) == -1) { + r = m1 - 1; + } + else { + l = m2 + 1; + } + } + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/house-robber-iii.md b/articles/house-robber-iii.md index 08d521c95..a09238c6b 100644 --- a/articles/house-robber-iii.md +++ b/articles/house-robber-iii.md @@ -128,6 +128,38 @@ class Solution { } ``` +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public int val; + * public TreeNode left; + * public TreeNode right; + * public TreeNode(int val=0, TreeNode left=null, TreeNode right=null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public int Rob(TreeNode root) { + if (root == null) return 0; + + int res = root.val; + if (root.left != null) { + res += Rob(root.left.left) + Rob(root.left.right); + } + if (root.right != null) { + res += Rob(root.right.left) + Rob(root.right.right); + } + + res = Math.Max(res, Rob(root.left) + Rob(root.right)); + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -299,6 +331,46 @@ class Solution { } ``` +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public int val; + * public TreeNode left; + * public TreeNode right; + * public TreeNode(int val=0, TreeNode left=null, TreeNode right=null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + private Dictionary cache = new(); + + public int Rob(TreeNode root) { + return Dfs(root); + } + + private int Dfs(TreeNode root) { + if (root == null) return 0; + if (cache.ContainsKey(root)) return cache[root]; + + int res = root.val; + if (root.left != null) { + res += Dfs(root.left.left) + Dfs(root.left.right); + } + if (root.right != null) { + res += Dfs(root.right.left) + Dfs(root.right.right); + } + + res = Math.Max(res, Dfs(root.left) + Dfs(root.right)); + cache[root] = res; + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -449,6 +521,40 @@ class Solution { } ``` +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public int val; + * public TreeNode left; + * public TreeNode right; + * public TreeNode(int val=0, TreeNode left=null, TreeNode right=null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public int Rob(TreeNode root) { + var result = Dfs(root); + return Math.Max(result.withRoot, result.withoutRoot); + } + + private (int withRoot, int withoutRoot) Dfs(TreeNode root) { + if (root == null) return (0, 0); + + var left = Dfs(root.left); + var right = Dfs(root.right); + + int withRoot = root.val + left.withoutRoot + right.withoutRoot; + int withoutRoot = Math.Max(left.withRoot, left.withoutRoot) + Math.Max(right.withRoot, right.withoutRoot); + + return (withRoot, withoutRoot); + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/insert-into-a-binary-search-tree.md b/articles/insert-into-a-binary-search-tree.md index d8597610b..fe0604c3a 100644 --- a/articles/insert-into-a-binary-search-tree.md +++ b/articles/insert-into-a-binary-search-tree.md @@ -118,6 +118,37 @@ class Solution { } ``` +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public int val; + * public TreeNode left; + * public TreeNode right; + * public TreeNode(int val=0, TreeNode left=null, TreeNode right=null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public TreeNode InsertIntoBST(TreeNode root, int val) { + if (root == null) { + return new TreeNode(val); + } + + if (val > root.val) { + root.right = InsertIntoBST(root.right, val); + } else { + root.left = InsertIntoBST(root.left, val); + } + + return root; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -282,6 +313,46 @@ class Solution { } ``` +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public int val; + * public TreeNode left; + * public TreeNode right; + * public TreeNode(int val=0, TreeNode left=null, TreeNode right=null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public TreeNode InsertIntoBST(TreeNode root, int val) { + if (root == null) { + return new TreeNode(val); + } + + TreeNode cur = root; + while (true) { + if (val > cur.val) { + if (cur.right == null) { + cur.right = new TreeNode(val); + return root; + } + cur = cur.right; + } else { + if (cur.left == null) { + cur.left = new TreeNode(val); + return root; + } + cur = cur.left; + } + } + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/integer-break.md b/articles/integer-break.md index eadd8856d..2330d8828 100644 --- a/articles/integer-break.md +++ b/articles/integer-break.md @@ -79,6 +79,28 @@ class Solution { } ``` +```csharp +public class Solution { + private int n; + + public int IntegerBreak(int n) { + this.n = n; + + int Dfs(int num) { + if (num == 1) return 1; + int res = num == n ? 0 : num; + for (int i = 1; i < num; i++) { + int val = Dfs(i) * Dfs(num - i); + res = Math.Max(res, val); + } + return res; + } + + return Dfs(n); + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -173,6 +195,26 @@ class Solution { } ``` +```csharp +public class Solution { + public int IntegerBreak(int n) { + int Dfs(int num, int i) { + if (Math.Min(num, i) == 0) { + return 1; + } + + if (i > num) { + return Dfs(num, num); + } + + return Math.Max(i * Dfs(num - i, i), Dfs(num, i - 1)); + } + + return Dfs(n, n - 1); + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -289,6 +331,31 @@ class Solution { } ``` +```csharp +public class Solution { + public int IntegerBreak(int n) { + Dictionary dp = new Dictionary(); + dp[1] = 1; + + int Dfs(int num) { + if (dp.ContainsKey(num)) { + return dp[num]; + } + + dp[num] = (num == n) ? 0 : num; + for (int i = 1; i < num; i++) { + int val = Dfs(i) * Dfs(num - i); + dp[num] = Math.Max(dp[num], val); + } + + return dp[num]; + } + + return Dfs(n); + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -409,6 +476,30 @@ class Solution { } ``` +```csharp +public class Solution { + public int IntegerBreak(int n) { + Dictionary<(int, int), int> dp = new Dictionary<(int, int), int>(); + + int Dfs(int num, int i) { + if (Math.Min(num, i) == 0) return 1; + + if (dp.ContainsKey((num, i))) return dp[(num, i)]; + + if (i > num) { + dp[(num, i)] = Dfs(num, num); + return dp[(num, i)]; + } + + dp[(num, i)] = Math.Max(i * Dfs(num - i, i), Dfs(num, i - 1)); + return dp[(num, i)]; + } + + return Dfs(n, n - 1); + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -495,6 +586,24 @@ class Solution { } ``` +```csharp +public class Solution { + public int IntegerBreak(int n) { + int[] dp = new int[n + 1]; + dp[1] = 1; + + for (int num = 2; num <= n; num++) { + dp[num] = num == n ? 0 : num; + for (int i = 1; i < num; i++) { + dp[num] = Math.Max(dp[num], dp[i] * dp[num - i]); + } + } + + return dp[n]; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -571,6 +680,24 @@ class Solution { } ``` +```csharp +public class Solution { + public int IntegerBreak(int n) { + if (n <= 3) { + return n - 1; + } + + int res = 1; + while (n > 4) { + res *= 3; + n -= 3; + } + + return res * n; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -653,6 +780,24 @@ class Solution { } ``` +```csharp +public class Solution { + public int IntegerBreak(int n) { + if (n <= 3) { + return n - 1; + } + + int res = (int)Math.Pow(3, n / 3); + + if (n % 3 == 1) { + return (res / 3) * 4; + } + + return res * Math.Max(1, n % 3); + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/ipo.md b/articles/ipo.md index e71ba4c34..87670000f 100644 --- a/articles/ipo.md +++ b/articles/ipo.md @@ -85,8 +85,8 @@ class Solution { * @return {number} */ findMaximizedCapital(k, w, profits, capital) { - const minCapital = new MinPriorityQueue({ compare: (a, b) => a[0] - b[0] }); // Min heap - const maxProfit = new MaxPriorityQueue({ compare: (a, b) => b - a }); // Max heap + const minCapital = new PriorityQueue((a, b) => a[0] - b[0]); // Min heap + const maxProfit = new PriorityQueue((a, b) => b - a); // Max heap for (let i = 0; i < capital.length; i++) { minCapital.enqueue([capital[i], profits[i]]); @@ -107,6 +107,39 @@ class Solution { } ``` +```csharp +public class Solution { + public int FindMaximizedCapital(int k, int w, int[] profits, int[] capital) { + var minCapital = new List<(int c, int p)>(); + for (int i = 0; i < capital.Length; i++) { + minCapital.Add((capital[i], profits[i])); + } + + // Min-heap by capital + minCapital.Sort((a, b) => a.c.CompareTo(b.c)); + + // Max-heap by profit + var maxProfit = new PriorityQueue(Comparer.Create((a, b) => b.CompareTo(a))); + int iPtr = 0; + + for (int i = 0; i < k; i++) { + while (iPtr < minCapital.Count && minCapital[iPtr].c <= w) { + maxProfit.Enqueue(minCapital[iPtr].p, minCapital[iPtr].p); + iPtr++; + } + + if (maxProfit.Count == 0) { + break; + } + + w += maxProfit.Dequeue(); + } + + return w; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -215,12 +248,12 @@ class Solution { * @return {number} */ findMaximizedCapital(k, w, profits, capital) { - const minCapital = new MinPriorityQueue({ - compare: (a, b) => capital[a] - capital[b], - }); - const maxProfit = new MaxPriorityQueue({ - compare: (a, b) => profits[b] - profits[a], - }); + const minCapital = new PriorityQueue( + (a, b) => capital[a] - capital[b], + ); + const maxProfit = new PriorityQueue( + (a, b) => profits[b] - profits[a], + ); for (let i = 0; i < capital.length; i++) { minCapital.enqueue(i); @@ -241,6 +274,34 @@ class Solution { } ``` +```csharp +public class Solution { + public int FindMaximizedCapital(int k, int w, int[] profits, int[] capital) { + var minCapital = new PriorityQueue(); // index with capital as priority + var maxProfit = new PriorityQueue(Comparer.Create((a, b) => b.CompareTo(a))); // max heap by profit + + for (int i = 0; i < capital.Length; i++) { + minCapital.Enqueue(i, capital[i]); + } + + for (int i = 0; i < k; i++) { + while (minCapital.Count > 0 && capital[minCapital.Peek()] <= w) { + int idx = minCapital.Dequeue(); + maxProfit.Enqueue(profits[idx], profits[idx]); + } + + if (maxProfit.Count == 0) { + break; + } + + w += maxProfit.Dequeue(); + } + + return w; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -358,7 +419,7 @@ class Solution { if (maxProfit.isEmpty()) { break; } - w += maxProfit.dequeue().element; + w += maxProfit.dequeue(); } return w; @@ -366,6 +427,38 @@ class Solution { } ``` +```csharp +public class Solution { + public int FindMaximizedCapital(int k, int w, int[] profits, int[] capital) { + int n = profits.Length; + int[] indices = new int[n]; + for (int i = 0; i < n; i++) { + indices[i] = i; + } + + Array.Sort(indices, (a, b) => capital[a].CompareTo(capital[b])); + + var maxProfit = new PriorityQueue(Comparer.Create((a, b) => b.CompareTo(a))); + int idx = 0; + + for (int i = 0; i < k; i++) { + while (idx < n && capital[indices[idx]] <= w) { + maxProfit.Enqueue(profits[indices[idx]], profits[indices[idx]]); + idx++; + } + + if (maxProfit.Count == 0) { + break; + } + + w += maxProfit.Dequeue(); + } + + return w; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/island-perimeter.md b/articles/island-perimeter.md index c4bb78ca5..bb87939fe 100644 --- a/articles/island-perimeter.md +++ b/articles/island-perimeter.md @@ -138,6 +138,42 @@ class Solution { } ``` +```csharp +public class Solution { + private int rows, cols; + private HashSet<(int, int)> visit; + + public int IslandPerimeter(int[][] grid) { + rows = grid.Length; + cols = grid[0].Length; + visit = new HashSet<(int, int)>(); + + int Dfs(int i, int j) { + if (i < 0 || j < 0 || i >= rows || j >= cols || grid[i][j] == 0) { + return 1; + } + if (visit.Contains((i, j))) { + return 0; + } + + visit.Add((i, j)); + int perim = Dfs(i, j + 1) + Dfs(i + 1, j) + Dfs(i, j - 1) + Dfs(i - 1, j); + return perim; + } + + 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; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -309,6 +345,56 @@ class Solution { } ``` +```csharp +public class Solution { + public int IslandPerimeter(int[][] grid) { + int rows = grid.Length; + int cols = grid[0].Length; + var visited = new HashSet<(int, int)>(); + int[][] directions = new int[][] { + new int[] { 0, 1 }, + new int[] { 1, 0 }, + new int[] { 0, -1 }, + new int[] { -1, 0 } + }; + + int Bfs(int r, int c) { + var queue = new Queue<(int, int)>(); + queue.Enqueue((r, c)); + visited.Add((r, c)); + int perimeter = 0; + + while (queue.Count > 0) { + var (x, y) = queue.Dequeue(); + foreach (var dir in directions) { + int nx = x + dir[0]; + int ny = y + dir[1]; + + if (nx < 0 || ny < 0 || nx >= rows || ny >= cols || grid[nx][ny] == 0) { + perimeter++; + } else if (!visited.Contains((nx, ny))) { + visited.Add((nx, ny)); + queue.Enqueue((nx, ny)); + } + } + } + + return perimeter; + } + + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + if (grid[i][j] == 1) { + return Bfs(i, j); + } + } + } + + return 0; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -401,6 +487,29 @@ class Solution { } ``` +```csharp +public class Solution { + public int IslandPerimeter(int[][] grid) { + int m = grid.Length; + int n = grid[0].Length; + int res = 0; + + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (grid[i][j] == 1) { + if (i + 1 >= m || grid[i + 1][j] == 0) res++; + if (j + 1 >= n || grid[i][j + 1] == 0) res++; + if (i - 1 < 0 || grid[i - 1][j] == 0) res++; + if (j - 1 < 0 || grid[i][j - 1] == 0) res++; + } + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -506,6 +615,32 @@ class Solution { } ``` +```csharp +public class Solution { + public int IslandPerimeter(int[][] grid) { + int m = grid.Length; + int 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; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/longest-happy-string.md b/articles/longest-happy-string.md index e5f2e0573..3b669e0e4 100644 --- a/articles/longest-happy-string.md +++ b/articles/longest-happy-string.md @@ -166,6 +166,45 @@ class Solution { } ``` +```csharp +public class Solution { + public string LongestDiverseString(int a, int b, int c) { + int[] count = new int[] { a, b, c }; + List res = new List(); + + int GetMax(int repeated) { + int idx = -1; + int maxCnt = 0; + for (int i = 0; i < 3; i++) { + if (i == repeated || count[i] == 0) continue; + if (maxCnt < count[i]) { + maxCnt = count[i]; + idx = i; + } + } + return idx; + } + + int repeated = -1; + while (true) { + int maxChar = GetMax(repeated); + if (maxChar == -1) break; + + res.Add((char)(maxChar + 'a')); + count[maxChar]--; + + if (res.Count > 1 && res[res.Count - 1] == res[res.Count - 2]) { + repeated = maxChar; + } else { + repeated = -1; + } + } + + return new string(res.ToArray()); + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -283,18 +322,18 @@ class Solution { */ longestDiverseString(a, b, c) { const res = []; - const maxHeap = new MaxPriorityQueue({ priority: (x) => x[0] }); + const maxHeap = new MaxPriorityQueue(x => x[0]); if (a > 0) maxHeap.enqueue([a, 'a']); if (b > 0) maxHeap.enqueue([b, 'b']); if (c > 0) maxHeap.enqueue([c, 'c']); while (!maxHeap.isEmpty()) { - const [count, char] = maxHeap.dequeue().element; + const [count, char] = maxHeap.dequeue(); if (res.length > 1 && res[res.length - 1] === char && res[res.length - 2] === char) { if (maxHeap.isEmpty()) break; - const [count2, char2] = maxHeap.dequeue().element; + const [count2, char2] = maxHeap.dequeue(); res.push(char2); if (count2 - 1 > 0) maxHeap.enqueue([count2 - 1, char2]); maxHeap.enqueue([count, char]); @@ -309,6 +348,47 @@ class Solution { } ``` +```csharp +public class Solution { + public string LongestDiverseString(int a, int b, int c) { + string res = ""; + PriorityQueue<(int count, char ch), int> maxHeap = new PriorityQueue<(int, char), int>(); + + void AddToHeap(int count, char ch) { + if (count > 0) { + maxHeap.Enqueue((count, ch), -count); + } + } + + AddToHeap(a, 'a'); + AddToHeap(b, 'b'); + AddToHeap(c, 'c'); + + while (maxHeap.Count > 0) { + var (count1, ch1) = maxHeap.Dequeue(); + if (res.Length >= 2 && res[^1] == ch1 && res[^2] == ch1) { + if (maxHeap.Count == 0) break; + var (count2, ch2) = maxHeap.Dequeue(); + res += ch2; + count2--; + if (count2 > 0) { + maxHeap.Enqueue((count2, ch2), -count2); + } + maxHeap.Enqueue((count1, ch1), -count1); + } else { + res += ch1; + count1--; + if (count1 > 0) { + maxHeap.Enqueue((count1, ch1), -count1); + } + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -448,6 +528,35 @@ class Solution { } ``` +```csharp +public class Solution { + public string LongestDiverseString(int a, int b, int c) { + return string.Join("", Rec(a, b, c, 'a', 'b', 'c')); + } + + private List Rec(int max1, int max2, int max3, char char1, char char2, char char3) { + if (max1 < max2) return Rec(max2, max1, max3, char2, char1, char3); + if (max2 < max3) return Rec(max1, max3, max2, char1, char3, char2); + if (max2 == 0) { + int use = Math.Min(2, max1); + var res = new List(); + for (int i = 0; i < use; i++) res.Add(char1); + return res; + } + + int use1 = Math.Min(2, max1); + int use2 = (max1 - use1 >= max2) ? 1 : 0; + + var result = new List(); + for (int i = 0; i < use1; i++) result.Add(char1); + for (int i = 0; i < use2; i++) result.Add(char2); + + result.AddRange(Rec(max1 - use1, max2 - use2, max3, char1, char2, char3)); + return result; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/matchsticks-to-square.md b/articles/matchsticks-to-square.md index c05819570..ae760c5ac 100644 --- a/articles/matchsticks-to-square.md +++ b/articles/matchsticks-to-square.md @@ -109,6 +109,39 @@ class Solution { } ``` +```csharp +public class Solution { + public bool Makesquare(int[] matchsticks) { + int total = 0; + foreach (int stick in matchsticks) { + total += stick; + } + if (total % 4 != 0) return false; + + int target = total / 4; + int[] sides = new int[4]; + + bool Dfs(int i) { + if (i == matchsticks.Length) { + return sides[0] == sides[1] && sides[1] == sides[2] && sides[2] == sides[3]; + } + + for (int side = 0; side < 4; side++) { + sides[side] += matchsticks[i]; + if (sides[side] <= target && Dfs(i + 1)) { + return true; + } + sides[side] -= matchsticks[i]; + } + + return false; + } + + return Dfs(0); + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -266,6 +299,45 @@ class Solution { } ``` +```csharp +public class Solution { + public bool Makesquare(int[] matchsticks) { + int totalLength = 0; + foreach (int stick in matchsticks) { + totalLength += stick; + } + + if (totalLength % 4 != 0) { + return false; + } + + int length = totalLength / 4; + int[] sides = new int[4]; + Array.Sort(matchsticks, (a, b) => b.CompareTo(a)); // Sort in descending order + + bool Dfs(int i) { + if (i == matchsticks.Length) { + return true; + } + + for (int side = 0; side < 4; side++) { + if (sides[side] + matchsticks[i] <= length) { + sides[side] += matchsticks[i]; + if (Dfs(i + 1)) return true; + sides[side] -= matchsticks[i]; + } + + if (sides[side] == 0) break; + } + + return false; + } + + return Dfs(0); + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -466,6 +538,46 @@ class Solution { } ``` +```csharp +public class Solution { + public bool Makesquare(int[] matchsticks) { + int totalLength = matchsticks.Sum(); + if (totalLength % 4 != 0) return false; + + int length = totalLength / 4; + if (matchsticks.Max() > length) return false; + + int n = matchsticks.Length; + int[] dp = Enumerable.Repeat(int.MinValue, 1 << n).ToArray(); + Array.Sort(matchsticks, (a, b) => b.CompareTo(a)); // Sort descending + + int Dfs(int mask) { + if (mask == 0) return 0; + if (dp[mask] != int.MinValue) return dp[mask]; + + for (int i = 0; i < n; i++) { + if ((mask & (1 << i)) != 0) { + int res = Dfs(mask ^ (1 << i)); + if (res >= 0 && res + matchsticks[i] <= length) { + dp[mask] = (res + matchsticks[i]) % length; + return dp[mask]; + } + if (mask == (1 << n) - 1) { + dp[mask] = -1; + return -1; + } + } + } + + dp[mask] = -1; + return -1; + } + + return Dfs((1 << n) - 1) != -1; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/minimum-size-subarray-sum.md b/articles/minimum-size-subarray-sum.md index 74be08d78..683582184 100644 --- a/articles/minimum-size-subarray-sum.md +++ b/articles/minimum-size-subarray-sum.md @@ -94,6 +94,28 @@ class Solution { } ``` +```csharp +public class Solution { + public int MinSubArrayLen(int target, int[] nums) { + int n = nums.Length; + int res = int.MaxValue; + + for (int i = 0; i < n; i++) { + int curSum = 0; + for (int j = i; j < n; j++) { + curSum += nums[j]; + if (curSum >= target) { + res = Math.Min(res, j - i + 1); + break; + } + } + } + + return res == int.MaxValue ? 0 : res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -188,6 +210,27 @@ class Solution { } ``` +```csharp +public class Solution { + public int MinSubArrayLen(int target, int[] nums) { + int l = 0, total = 0; + int res = int.MaxValue; + + for (int r = 0; r < nums.Length; r++) { + total += nums[r]; + + while (total >= target) { + res = Math.Min(res, r - l + 1); + total -= nums[l]; + l++; + } + } + + return res == int.MaxValue ? 0 : res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -324,6 +367,39 @@ class Solution { } ``` +```csharp +public class Solution { + public int MinSubArrayLen(int target, int[] nums) { + int n = nums.Length; + int[] prefixSum = new int[n + 1]; + + for (int i = 0; i < n; i++) { + prefixSum[i + 1] = prefixSum[i] + nums[i]; + } + + int res = n + 1; + + for (int i = 0; i < n; i++) { + int l = i, r = n; + while (l < r) { + int mid = (l + r) / 2; + int curSum = prefixSum[mid + 1] - prefixSum[i]; + if (curSum >= target) { + r = mid; + } else { + l = mid + 1; + } + } + if (l != n) { + res = Math.Min(res, l - i + 1); + } + } + + return res % (n + 1); + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/n-queens-ii.md b/articles/n-queens-ii.md index 1e123c887..16a94bd75 100644 --- a/articles/n-queens-ii.md +++ b/articles/n-queens-ii.md @@ -178,6 +178,57 @@ class Solution { } ``` +```csharp +public class Solution { + private int res = 0; + + public int TotalNQueens(int n) { + res = 0; + char[][] board = new char[n][]; + for (int i = 0; i < n; i++) { + board[i] = Enumerable.Repeat('.', n).ToArray(); + } + + Backtrack(0, board, n); + return res; + } + + private void Backtrack(int r, char[][] board, int n) { + if (r == n) { + res++; + return; + } + + for (int c = 0; c < n; c++) { + if (IsSafe(r, c, board)) { + board[r][c] = 'Q'; + Backtrack(r + 1, board, n); + board[r][c] = '.'; + } + } + } + + private bool IsSafe(int r, int c, char[][] board) { + // Check column + for (int row = r - 1; row >= 0; row--) { + if (board[row][c] == 'Q') return false; + } + + // Check top-left diagonal + for (int row = r - 1, col = c - 1; row >= 0 && col >= 0; row--, col--) { + if (board[row][col] == 'Q') return false; + } + + // Check top-right diagonal + for (int row = r - 1, col = c + 1; row >= 0 && col < board.Length; row--, col++) { + if (board[row][col] == 'Q') return false; + } + + return true; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -346,6 +397,43 @@ class Solution { } ``` +```csharp +public class Solution { + private HashSet col = new HashSet(); + private HashSet posDiag = new HashSet(); // r + c + private HashSet negDiag = new HashSet(); // r - c + private int res = 0; + + public int TotalNQueens(int n) { + res = 0; + Backtrack(0, n); + return res; + } + + private void Backtrack(int r, int n) { + if (r == n) { + res++; + return; + } + + for (int c = 0; c < n; c++) { + if (col.Contains(c) || posDiag.Contains(r + c) || negDiag.Contains(r - c)) + continue; + + col.Add(c); + posDiag.Add(r + c); + negDiag.Add(r - c); + + Backtrack(r + 1, n); + + col.Remove(c); + posDiag.Remove(r + c); + negDiag.Remove(r - c); + } + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -509,6 +597,42 @@ class Solution { } ``` +```csharp +public class Solution { + public int TotalNQueens(int n) { + bool[] col = new bool[n]; + bool[] posDiag = new bool[2 * n]; + bool[] negDiag = new bool[2 * n]; + int res = 0; + + void Backtrack(int r) { + if (r == n) { + res++; + return; + } + + for (int c = 0; c < n; c++) { + if (col[c] || posDiag[r + c] || negDiag[r - c + n]) + continue; + + col[c] = true; + posDiag[r + c] = true; + negDiag[r - c + n] = true; + + Backtrack(r + 1); + + col[c] = false; + posDiag[r + c] = false; + negDiag[r - c + n] = false; + } + } + + Backtrack(0); + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -664,6 +788,44 @@ class Solution { } ``` +```csharp +public class Solution { + public int TotalNQueens(int n) { + int col = 0; + int posDiag = 0; + int negDiag = 0; + int res = 0; + + void Backtrack(int r) { + if (r == n) { + res++; + return; + } + + for (int c = 0; c < n; c++) { + if (((col & (1 << c)) != 0) || + ((posDiag & (1 << (r + c))) != 0) || + ((negDiag & (1 << (r - c + n))) != 0)) + continue; + + col ^= (1 << c); + posDiag ^= (1 << (r + c)); + negDiag ^= (1 << (r - c + n)); + + Backtrack(r + 1); + + col ^= (1 << c); + posDiag ^= (1 << (r + c)); + negDiag ^= (1 << (r - c + n)); + } + } + + Backtrack(0); + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/n-th-tribonacci-number.md b/articles/n-th-tribonacci-number.md index bf04e98f7..56f6ce37a 100644 --- a/articles/n-th-tribonacci-number.md +++ b/articles/n-th-tribonacci-number.md @@ -48,6 +48,16 @@ class Solution { } ``` +```csharp +public class Solution { + public int Tribonacci(int n) { + if (n == 0) return 0; + if (n <= 2) return 1; + return Tribonacci(n - 1) + Tribonacci(n - 2) + Tribonacci(n - 3); + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -138,6 +148,21 @@ class Solution { } ``` +```csharp +public class Solution { + private Dictionary dp = new Dictionary(); + + public int Tribonacci(int n) { + if (n == 0) return 0; + if (n <= 2) return 1; + if (dp.ContainsKey(n)) return dp[n]; + + dp[n] = Tribonacci(n - 1) + Tribonacci(n - 2) + Tribonacci(n - 3); + return dp[n]; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -220,6 +245,25 @@ class Solution { } ``` +```csharp +public class Solution { + public int Tribonacci(int n) { + if (n == 0) return 0; + if (n <= 2) return 1; + + int[] dp = new int[n + 1]; + dp[0] = 0; + dp[1] = dp[2] = 1; + + for (int i = 3; i <= n; i++) { + dp[i] = dp[i - 1] + dp[i - 2] + dp[i - 3]; + } + + return dp[n]; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -293,6 +337,21 @@ class Solution { } ``` +```csharp +public class Solution { + public int Tribonacci(int n) { + int[] t = {0, 1, 1}; + if (n < 3) return t[n]; + + for (int i = 3; i <= n; i++) { + t[i % 3] = t[0] + t[1] + t[2]; + } + + return t[n % 3]; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/open-the-lock.md b/articles/open-the-lock.md index 6ded4c7ee..910704fd6 100644 --- a/articles/open-the-lock.md +++ b/articles/open-the-lock.md @@ -159,6 +159,44 @@ class Solution { } ``` +```csharp +public class Solution { + public int OpenLock(string[] deadends, string target) { + var dead = new HashSet(deadends); + if (dead.Contains("0000")) return -1; + + List Children(string lockStr) { + var res = new List(); + for (int i = 0; i < 4; i++) { + int digit = lockStr[i] - '0'; + string up = lockStr.Substring(0, i) + ((digit + 1) % 10) + lockStr.Substring(i + 1); + string down = lockStr.Substring(0, i) + ((digit + 9) % 10) + lockStr.Substring(i + 1); + res.Add(up); + res.Add(down); + } + return res; + } + + var q = new Queue<(string, int)>(); + q.Enqueue(("0000", 0)); + var visited = new HashSet(dead); + + while (q.Count > 0) { + var (lockStr, turns) = q.Dequeue(); + if (lockStr == target) return turns; + foreach (var child in Children(lockStr)) { + if (!visited.Contains(child)) { + visited.Add(child); + q.Enqueue((child, turns + 1)); + } + } + } + + return -1; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -313,6 +351,42 @@ class Solution { } ``` +```csharp +public class Solution { + public int OpenLock(string[] deadends, string target) { + if (target == "0000") return 0; + + var visited = new HashSet(deadends); + if (visited.Contains("0000")) return -1; + + var q = new Queue(); + q.Enqueue("0000"); + visited.Add("0000"); + int steps = 0; + + while (q.Count > 0) { + steps++; + int size = q.Count; + for (int i = 0; i < size; i++) { + string lockStr = q.Dequeue(); + for (int j = 0; j < 4; j++) { + foreach (int move in new int[] {1, -1}) { + int digit = (lockStr[j] - '0' + move + 10) % 10; + string nextLock = lockStr.Substring(0, j) + digit.ToString() + lockStr.Substring(j + 1); + if (visited.Contains(nextLock)) continue; + if (nextLock == target) return steps; + q.Enqueue(nextLock); + visited.Add(nextLock); + } + } + } + } + + return -1; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -491,6 +565,51 @@ class Solution { } ``` +```csharp +public class Solution { + public int OpenLock(string[] deadends, string target) { + if (target == "0000") return 0; + + var visit = new HashSet(deadends); + if (visit.Contains("0000")) return -1; + + var begin = new HashSet { "0000" }; + var end = new HashSet { target }; + int steps = 0; + + while (begin.Count > 0 && end.Count > 0) { + if (begin.Count > end.Count) { + var tempSet = begin; + begin = end; + end = tempSet; + } + + var temp = new HashSet(); + steps++; + + foreach (var lockStr in begin) { + for (int i = 0; i < 4; i++) { + foreach (int j in new int[] { -1, 1 }) { + int digit = (lockStr[i] - '0' + j + 10) % 10; + string nextLock = lockStr.Substring(0, i) + digit.ToString() + lockStr.Substring(i + 1); + + if (end.Contains(nextLock)) return steps; + if (visit.Contains(nextLock)) continue; + + visit.Add(nextLock); + temp.Add(nextLock); + } + } + } + + begin = temp; + } + + return -1; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/partition-to-k-equal-sum-subsets.md b/articles/partition-to-k-equal-sum-subsets.md index 260fe7e37..d217736df 100644 --- a/articles/partition-to-k-equal-sum-subsets.md +++ b/articles/partition-to-k-equal-sum-subsets.md @@ -132,6 +132,38 @@ class Solution { } ``` +```csharp +public class Solution { + public bool CanPartitionKSubsets(int[] nums, int k) { + int totalSum = nums.Sum(); + if (totalSum % k != 0) return false; + + int target = totalSum / k; + Array.Sort(nums); + Array.Reverse(nums); + + bool[] used = new bool[nums.Length]; + + bool Backtrack(int i, int kRemaining, int subsetSum) { + if (kRemaining == 0) return true; + if (subsetSum == target) return Backtrack(0, kRemaining - 1, 0); + + for (int j = i; j < nums.Length; j++) { + if (used[j] || subsetSum + nums[j] > target) continue; + + used[j] = true; + if (Backtrack(j + 1, kRemaining, subsetSum + nums[j])) return true; + used[j] = false; + } + + return false; + } + + return Backtrack(0, k, 0); + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -291,6 +323,39 @@ class Solution { } ``` +```csharp +public class Solution { + public bool CanPartitionKSubsets(int[] nums, int k) { + int total = nums.Sum(); + if (total % k != 0) return false; + + Array.Sort(nums); + Array.Reverse(nums); + int target = total / k; + bool[] used = new bool[nums.Length]; + + bool Backtrack(int i, int kRemaining, int subsetSum) { + if (kRemaining == 0) return true; + if (subsetSum == target) return Backtrack(0, kRemaining - 1, 0); + + for (int j = i; j < nums.Length; j++) { + if (used[j] || subsetSum + nums[j] > target) continue; + + used[j] = true; + if (Backtrack(j + 1, kRemaining, subsetSum + nums[j])) return true; + used[j] = false; + + if (subsetSum == 0) return false; // Pruning + } + + return false; + } + + return Backtrack(0, k, 0); + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -442,6 +507,38 @@ class Solution { } ``` +```csharp +public class Solution { + public bool CanPartitionKSubsets(int[] nums, int k) { + int total = nums.Sum(); + if (total % k != 0) return false; + + Array.Sort(nums); + Array.Reverse(nums); + int target = total / k; + int n = nums.Length; + + bool Backtrack(int i, int kRemaining, int subsetSum, int mask) { + if (kRemaining == 0) return true; + if (subsetSum == target) return Backtrack(0, kRemaining - 1, 0, mask); + + for (int j = i; j < n; j++) { + if ((mask & (1 << j)) == 0 || subsetSum + nums[j] > target) continue; + + if (Backtrack(j + 1, kRemaining, subsetSum + nums[j], mask ^ (1 << j))) + return true; + + if (subsetSum == 0) return false; + } + + return false; + } + + return Backtrack(0, k, 0, (1 << n) - 1); + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -641,6 +738,53 @@ class Solution { } ``` +```csharp +public class Solution { + public bool CanPartitionKSubsets(int[] nums, int k) { + int total = nums.Sum(); + if (total % k != 0) return false; + + Array.Sort(nums); + Array.Reverse(nums); + + int target = total / k; + int n = nums.Length; + bool?[] dp = new bool?[1 << n]; + + bool Backtrack(int i, int kRemaining, int subsetSum, int mask) { + if (dp[mask].HasValue) return (bool)dp[mask]; + if (kRemaining == 0) { + dp[mask] = true; + return true; + } + if (subsetSum == target) { + dp[mask] = Backtrack(0, kRemaining - 1, 0, mask); + return (bool)dp[mask]; + } + + for (int j = i; j < n; j++) { + if ((mask & (1 << j)) == 0 || subsetSum + nums[j] > target) continue; + + if (Backtrack(j + 1, kRemaining, subsetSum + nums[j], mask ^ (1 << j))) { + dp[mask] = true; + return true; + } + + if (subsetSum == 0) { + dp[mask] = false; + return false; + } + } + + dp[mask] = false; + return false; + } + + return Backtrack(0, k, 0, (1 << n) - 1); + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -764,6 +908,35 @@ class Solution { } ``` +```csharp +public class Solution { + public bool CanPartitionKSubsets(int[] nums, int k) { + int total = nums.Sum(); + if (total % k != 0) return false; + + int target = total / k; + int n = nums.Length; + int N = 1 << n; + int[] dp = new int[N]; + for (int i = 1; i < N; i++) { + dp[i] = -1; + } + + for (int mask = 0; mask < N; mask++) { + if (dp[mask] == -1) continue; + for (int i = 0; i < n; i++) { + if ((mask & (1 << i)) == 0 && dp[mask] + nums[i] <= target) { + int nextMask = mask | (1 << i); + dp[nextMask] = (dp[mask] + nums[i]) % target; + } + } + } + + return dp[N - 1] == 0; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/path-with-minimum-effort.md b/articles/path-with-minimum-effort.md index bccc0e7b9..5f151c2c8 100644 --- a/articles/path-with-minimum-effort.md +++ b/articles/path-with-minimum-effort.md @@ -132,7 +132,7 @@ class Solution { ); dist[0][0] = 0; - const minHeap = new MinPriorityQueue({ priority: (a) => a[0] }); + const minHeap = new MinPriorityQueue(a => a[0]); minHeap.enqueue([0, 0, 0]); // [diff, row, col] const directions = [ @@ -141,7 +141,7 @@ class Solution { ]; while (!minHeap.isEmpty()) { - const [diff, r, c] = minHeap.dequeue().element; + const [diff, r, c] = minHeap.dequeue(); if (r === rows - 1 && c === cols - 1) return diff; if (dist[r][c] < diff) continue; @@ -169,6 +169,50 @@ class Solution { } ``` +```csharp +public class Solution { + public int MinimumEffortPath(int[][] heights) { + int rows = heights.Length, cols = heights[0].Length; + var directions = new int[][] { + new int[] { 0, 1 }, + new int[] { 0, -1 }, + new int[] { 1, 0 }, + new int[] { -1, 0 } + }; + + var minHeap = new PriorityQueue<(int diff, int r, int c), int>(); + var visited = new HashSet<(int, int)>(); + minHeap.Enqueue((0, 0, 0), 0); + + while (minHeap.Count > 0) { + var current = minHeap.Dequeue(); + int diff = current.diff, r = current.r, c = current.c; + + if (visited.Contains((r, c))) continue; + visited.Add((r, c)); + + if (r == rows - 1 && c == cols - 1) { + return diff; + } + + foreach (var dir in directions) { + int newR = r + dir[0]; + int newC = c + dir[1]; + + if (newR < 0 || newC < 0 || newR >= rows || newC >= cols || visited.Contains((newR, newC))) { + continue; + } + + int newDiff = Math.Max(diff, Math.Abs(heights[r][c] - heights[newR][newC])); + minHeap.Enqueue((newDiff, newR, newC), newDiff); + } + } + + return 0; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -390,6 +434,59 @@ class Solution { } ``` +```csharp +public class Solution { + private int[][] directions = new int[][] { + new int[] { 0, 1 }, + new int[] { 0, -1 }, + new int[] { 1, 0 }, + new int[] { -1, 0 } + }; + + public int MinimumEffortPath(int[][] heights) { + int rows = heights.Length; + int cols = heights[0].Length; + + bool Dfs(int r, int c, int limit, HashSet<(int, int)> visited) { + if (r == rows - 1 && c == cols - 1) + return true; + + visited.Add((r, c)); + + foreach (var dir in directions) { + int newR = r + dir[0]; + int newC = c + dir[1]; + + if (newR < 0 || newC < 0 || newR >= rows || newC >= cols || + visited.Contains((newR, newC)) || + Math.Abs(heights[newR][newC] - heights[r][c]) > limit) + continue; + + if (Dfs(newR, newC, limit, visited)) + return true; + } + + return false; + } + + int left = 0, right = 1000000, res = right; + + while (left <= right) { + int mid = (left + right) / 2; + var visited = new HashSet<(int, int)>(); + if (Dfs(0, 0, mid, visited)) { + res = mid; + right = mid - 1; + } else { + left = mid + 1; + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -654,6 +751,77 @@ class Solution { } ``` +```csharp +public class DSU { + private int[] parent; + private int[] size; + + public DSU(int n) { + parent = new int[n + 1]; + size = new int[n + 1]; + for (int i = 0; i <= n; i++) { + parent[i] = i; + size[i] = 1; + } + } + + public int Find(int node) { + if (parent[node] != node) { + parent[node] = Find(parent[node]); + } + return parent[node]; + } + + public bool Union(int u, int v) { + int pu = Find(u); + int pv = Find(v); + if (pu == pv) return false; + if (size[pu] < size[pv]) { + (pu, pv) = (pv, pu); + } + size[pu] += size[pv]; + parent[pv] = pu; + return true; + } +} + +public class Solution { + public int MinimumEffortPath(int[][] heights) { + int rows = heights.Length; + int cols = heights[0].Length; + List<(int, int, int)> edges = new List<(int, int, int)>(); + + for (int r = 0; r < rows; r++) { + for (int c = 0; c < cols; c++) { + int id = r * cols + c; + if (r + 1 < rows) { + int downId = (r + 1) * cols + c; + int diff = Math.Abs(heights[r][c] - heights[r + 1][c]); + edges.Add((diff, id, downId)); + } + if (c + 1 < cols) { + int rightId = r * cols + (c + 1); + int diff = Math.Abs(heights[r][c] - heights[r][c + 1]); + edges.Add((diff, id, rightId)); + } + } + } + + edges.Sort((a, b) => a.Item1.CompareTo(b.Item1)); + DSU dsu = new DSU(rows * cols); + + foreach (var (weight, u, v) in edges) { + dsu.Union(u, v); + if (dsu.Find(0) == dsu.Find(rows * cols - 1)) { + return weight; + } + } + + return 0; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -839,6 +1007,53 @@ class Solution { } ``` +```csharp +public class Solution { + public int MinimumEffortPath(int[][] heights) { + int rows = heights.Length; + int cols = heights[0].Length; + int[] dist = Enumerable.Repeat(int.MaxValue, rows * cols).ToArray(); + bool[] inQueue = new bool[rows * cols]; + dist[0] = 0; + + int Index(int r, int c) => r * cols + c; + + Queue queue = new Queue(); + queue.Enqueue(0); + inQueue[0] = true; + + int[][] directions = new int[][] { + new int[] {0, 1}, new int[] {0, -1}, + new int[] {1, 0}, new int[] {-1, 0} + }; + + while (queue.Count > 0) { + int u = queue.Dequeue(); + inQueue[u] = false; + int r = u / cols, c = u % cols; + + foreach (var dir in directions) { + int newR = r + dir[0], newC = c + dir[1]; + if (newR >= 0 && newR < rows && newC >= 0 && newC < cols) { + int v = Index(newR, newC); + int weight = Math.Abs(heights[r][c] - heights[newR][newC]); + int newDist = Math.Max(dist[u], weight); + if (newDist < dist[v]) { + dist[v] = newDist; + if (!inQueue[v]) { + queue.Enqueue(v); + inQueue[v] = true; + } + } + } + } + } + + return dist[rows * cols - 1]; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/perfect-squares.md b/articles/perfect-squares.md index ce067516a..eb92e5450 100644 --- a/articles/perfect-squares.md +++ b/articles/perfect-squares.md @@ -83,6 +83,25 @@ class Solution { } ``` +```csharp +public class Solution { + public int NumSquares(int n) { + return Dfs(n); + } + + private int Dfs(int target) { + if (target == 0) return 0; + + int res = target; + for (int i = 1; i * i <= target; i++) { + res = Math.Min(res, 1 + Dfs(target - i * i)); + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -193,6 +212,29 @@ class Solution { } ``` +```csharp +public class Solution { + private Dictionary memo = new Dictionary(); + + public int NumSquares(int n) { + return Dfs(n); + } + + private int Dfs(int target) { + if (target == 0) return 0; + if (memo.ContainsKey(target)) return memo[target]; + + int res = target; + for (int i = 1; i * i <= target; i++) { + res = Math.Min(res, 1 + Dfs(target - i * i)); + } + + memo[target] = res; + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -279,6 +321,25 @@ class Solution { } ``` +```csharp +public class Solution { + public int NumSquares(int n) { + int[] dp = new int[n + 1]; + Array.Fill(dp, n); + dp[0] = 0; + + for (int target = 1; target <= n; target++) { + for (int s = 1; s * s <= target; s++) { + int square = s * s; + dp[target] = Math.Min(dp[target], 1 + dp[target - square]); + } + } + + return dp[n]; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -403,6 +464,40 @@ class Solution { } ``` +```csharp +public class Solution { + public int NumSquares(int n) { + Queue q = new Queue(); + HashSet seen = new HashSet(); + + int res = 0; + q.Enqueue(0); + + while (q.Count > 0) { + res++; + int size = q.Count; + for (int i = 0; i < size; i++) { + int cur = q.Dequeue(); + int s = 1; + while (s * s + cur <= n) { + int nxt = cur + s * s; + if (nxt == n) { + return res; + } + if (!seen.Contains(nxt)) { + seen.Add(nxt); + q.Enqueue(nxt); + } + s++; + } + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -540,6 +635,37 @@ class Solution { } ``` +```csharp +public class Solution { + public int NumSquares(int n) { + while (n % 4 == 0) { + n /= 4; + } + + if (n % 8 == 7) { + return 4; + } + + bool IsSquareNum(int num) { + int s = (int)Math.Sqrt(num); + return s * s == num; + } + + if (IsSquareNum(n)) { + return 1; + } + + for (int i = 1; i * i <= n; i++) { + if (IsSquareNum(n - i * i)) { + return 2; + } + } + + return 3; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/permutations-ii.md b/articles/permutations-ii.md index d4c0edd41..83aefec3b 100644 --- a/articles/permutations-ii.md +++ b/articles/permutations-ii.md @@ -121,6 +121,38 @@ class Solution { } ``` +```csharp +public class Solution { + public List> PermuteUnique(int[] nums) { + HashSet resSet = new HashSet(); + List> result = new List>(); + Backtrack(new List(), nums, resSet, result); + return result; + } + + private void Backtrack(List perm, int[] nums, HashSet resSet, List> result) { + if (perm.Count == nums.Length) { + string key = string.Join(",", perm); + if (resSet.Add(key)) { + result.Add(new List(perm)); + } + return; + } + + for (int i = 0; i < nums.Length; i++) { + if (nums[i] != int.MinValue) { + int temp = nums[i]; + perm.Add(temp); + nums[i] = int.MinValue; + Backtrack(perm, nums, resSet, result); + nums[i] = temp; + perm.RemoveAt(perm.Count - 1); + } + } + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -268,6 +300,44 @@ class Solution { } ``` +```csharp +public class Solution { + public List> PermuteUnique(int[] nums) { + var res = new List>(); + var perm = new List(); + var count = new Dictionary(); + + foreach (int num in nums) { + if (!count.ContainsKey(num)) { + count[num] = 0; + } + count[num]++; + } + + void Dfs() { + if (perm.Count == nums.Length) { + res.Add(new List(perm)); + return; + } + + foreach (var kvp in count) { + int num = kvp.Key; + if (count[num] > 0) { + perm.Add(num); + count[num]--; + Dfs(); + count[num]++; + perm.RemoveAt(perm.Count - 1); + } + } + } + + Dfs(); + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -413,6 +483,39 @@ class Solution { } ``` +```csharp +public class Solution { + public List> PermuteUnique(int[] nums) { + var res = new List>(); + var perm = new List(); + int n = nums.Length; + bool[] visit = new bool[n]; + Array.Sort(nums); + + void Dfs() { + if (perm.Count == n) { + res.Add(new List(perm)); + return; + } + + for (int i = 0; i < n; i++) { + if (visit[i]) continue; + if (i > 0 && nums[i] == nums[i - 1] && !visit[i - 1]) continue; + + visit[i] = true; + perm.Add(nums[i]); + Dfs(); + perm.RemoveAt(perm.Count - 1); + visit[i] = false; + } + } + + Dfs(); + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -552,6 +655,41 @@ class Solution { } ``` +```csharp +public class Solution { + public List> PermuteUnique(int[] nums) { + var res = new List>(); + Array.Sort(nums); + Dfs(0); + return res; + + void Dfs(int i) { + if (i == nums.Length) { + res.Add(new List(nums)); + return; + } + + for (int j = i; j < nums.Length; j++) { + if (j > i && nums[j] == nums[i]) continue; + + Swap(i, j); + Dfs(i + 1); + } + + for (int j = nums.Length - 1; j > i; j--) { + Swap(i, j); + } + } + + void Swap(int a, int b) { + int temp = nums[a]; + nums[a] = nums[b]; + nums[b] = temp; + } + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -704,6 +842,48 @@ class Solution { } ``` +```csharp +public class Solution { + public List> PermuteUnique(int[] nums) { + int n = nums.Length; + Array.Sort(nums); + var res = new List>(); + res.Add(new List(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); + + int left = i + 1, right = n - 1; + while (left < right) { + Swap(nums, left++, right--); + } + + res.Add(new List(nums)); + } + + return res; + } + + private void Swap(int[] nums, int i, int j) { + int temp = nums[i]; + nums[i] = nums[j]; + nums[j] = temp; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/remove-duplicates-from-sorted-array.md b/articles/remove-duplicates-from-sorted-array.md index 57bb96cdc..7629a2ff3 100644 --- a/articles/remove-duplicates-from-sorted-array.md +++ b/articles/remove-duplicates-from-sorted-array.md @@ -56,6 +56,16 @@ class Solution { } ``` +```csharp +public class Solution { + public int RemoveDuplicates(int[] nums) { + int[] unique = nums.Distinct().OrderBy(x => x).ToArray(); + Array.Copy(unique, nums, unique.Length); + return unique.Length; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -135,6 +145,25 @@ class Solution { } ``` +```csharp +public class Solution { + public int RemoveDuplicates(int[] nums) { + int n = nums.Length; + int l = 0, r = 0; + + while (r < n) { + nums[l] = nums[r]; + while (r < n && nums[r] == nums[l]) { + r++; + } + l++; + } + + return l; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -206,6 +235,22 @@ class Solution { } ``` +```csharp +public class Solution { + public int RemoveDuplicates(int[] nums) { + int l = 1; + for (int r = 1; r < nums.Length; r++) { + if (nums[r] != nums[r - 1]) { + nums[l] = nums[r]; + l++; + } + } + + return l; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/reverse-linked-list-ii.md b/articles/reverse-linked-list-ii.md index 5a3d69df7..98f00e838 100644 --- a/articles/reverse-linked-list-ii.md +++ b/articles/reverse-linked-list-ii.md @@ -194,6 +194,57 @@ class Solution { } ``` +```csharp +/** + * Definition for singly-linked list. + * public class ListNode { + * public int val; + * public ListNode next; + * public ListNode(int val=0, ListNode next=null) { + * this.val = val; + * this.next = next; + * } + * } + */ +public class Solution { + public ListNode ReverseBetween(ListNode head, int left, int right) { + ListNode dummy = new ListNode(0, head); + ListNode prev = dummy; + + for (int i = 0; i < left - 1; i++) { + prev = prev.next; + } + + ListNode sublistHead = prev.next; + ListNode sublistTail = sublistHead; + for (int i = 0; i < right - left; i++) { + sublistTail = sublistTail.next; + } + + ListNode nextNode = sublistTail.next; + sublistTail.next = null; + + ListNode reversedSublist = ReverseList(sublistHead); + prev.next = reversedSublist; + sublistHead.next = nextNode; + + return dummy.next; + } + + private ListNode ReverseList(ListNode head) { + if (head == null) return null; + + ListNode newHead = head; + if (head.next != null) { + newHead = ReverseList(head.next); + head.next.next = head; + } + head.next = null; + return newHead; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -334,6 +385,42 @@ class Solution { } ``` +```csharp +/** + * Definition for singly-linked list. + * public class ListNode { + * public int val; + * public ListNode next; + * public ListNode(int val=0, ListNode next=null) { + * this.val = val; + * this.next = next; + * } + * } + */ +public class Solution { + private ListNode successor = null; + + private ListNode ReverseList(ListNode node, int n) { + if (n == 1) { + successor = node.next; + return node; + } + ListNode newHead = ReverseList(node.next, n - 1); + node.next.next = node; + node.next = successor; + return newHead; + } + + public ListNode ReverseBetween(ListNode head, int left, int right) { + if (left == 1) { + return ReverseList(head, right); + } + head.next = ReverseBetween(head.next, left - 1, right - 1); + return head; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -540,6 +627,58 @@ class Solution { } ``` +```csharp +/** + * Definition for singly-linked list. + * public class ListNode { + * public int val; + * public ListNode next; + * public ListNode(int val=0, ListNode next=null) { + * this.val = val; + * this.next = next; + * } + * } + */ +public class Solution { + public ListNode ReverseBetween(ListNode head, int left, int right) { + ListNode dummy = new ListNode(0); + dummy.next = head; + ListNode prev = dummy; + + for (int i = 0; i < left - 1; i++) { + prev = prev.next; + } + + ListNode sublistHead = prev.next; + ListNode sublistTail = sublistHead; + for (int i = 0; i < right - left; i++) { + sublistTail = sublistTail.next; + } + + ListNode nextNode = sublistTail.next; + sublistTail.next = null; + + ListNode reversedSublist = ReverseList(sublistHead); + prev.next = reversedSublist; + + sublistHead.next = nextNode; + return dummy.next; + } + + private ListNode ReverseList(ListNode head) { + ListNode prev = null; + ListNode curr = head; + while (curr != null) { + ListNode temp = curr.next; + curr.next = prev; + prev = curr; + curr = temp; + } + return prev; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -699,6 +838,44 @@ class Solution { } ``` +```csharp +/** + * Definition for singly-linked list. + * public class ListNode { + * public int val; + * public ListNode next; + * public ListNode(int val=0, ListNode next=null) { + * this.val = val; + * this.next = next; + * } + * } + */ +public class Solution { + public ListNode ReverseBetween(ListNode head, int left, int right) { + ListNode dummy = new ListNode(0, head); + ListNode leftPrev = dummy, curr = head; + + for (int i = 0; i < left - 1; i++) { + leftPrev = curr; + curr = curr.next; + } + + ListNode prev = null; + for (int i = 0; i < right - left + 1; i++) { + ListNode tmpNext = curr.next; + curr.next = prev; + prev = curr; + curr = tmpNext; + } + + leftPrev.next.next = curr; + leftPrev.next = prev; + + return dummy.next; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/reverse-string.md b/articles/reverse-string.md index ac60401c5..6c671dd5f 100644 --- a/articles/reverse-string.md +++ b/articles/reverse-string.md @@ -62,6 +62,23 @@ class Solution { } ``` +```csharp +public class Solution { + public void ReverseString(char[] s) { + char[] tmp = new char[s.Length]; + int n = s.Length; + + for (int i = 0; i < n; i++) { + tmp[i] = s[n - 1 - i]; + } + + for (int i = 0; i < n; i++) { + s[i] = tmp[i]; + } + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -141,6 +158,23 @@ class Solution { } ``` +```csharp +public class Solution { + public void ReverseString(char[] s) { + Reverse(s, 0, s.Length - 1); + } + + private void Reverse(char[] s, int left, int right) { + if (left < right) { + Reverse(s, left + 1, right - 1); + char temp = s[left]; + s[left] = s[right]; + s[right] = temp; + } + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -220,6 +254,22 @@ class Solution { } ``` +```csharp +public class Solution { + public void ReverseString(char[] s) { + Stack stack = new Stack(); + + foreach (char c in s) { + stack.Push(c); + } + + for (int i = 0; i < s.Length; i++) { + s[i] = stack.Pop(); + } + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -279,6 +329,14 @@ class Solution { } ``` +```csharp +public class Solution { + public void ReverseString(char[] s) { + Array.Reverse(s); + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -349,6 +407,21 @@ class Solution { } ``` +```csharp +public class Solution { + public void ReverseString(char[] s) { + int l = 0, r = s.Length - 1; + while (l < r) { + char temp = s[l]; + s[l] = s[r]; + s[r] = temp; + l++; + r--; + } + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/search-in-rotated-sorted-array-ii.md b/articles/search-in-rotated-sorted-array-ii.md index d77b4c923..04af02db0 100644 --- a/articles/search-in-rotated-sorted-array-ii.md +++ b/articles/search-in-rotated-sorted-array-ii.md @@ -53,6 +53,14 @@ class Solution { } ``` +```csharp +public class Solution { + public bool Search(int[] nums, int target) { + return nums.Contains(target); + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -199,6 +207,37 @@ class Solution { } ``` +```csharp +public class Solution { + public bool Search(int[] nums, int target) { + int l = 0, r = nums.Length - 1; + while (l <= r) { + int m = l + (r - l) / 2; + if (nums[m] == target) { + return true; + } + + if (nums[l] < nums[m]) { + if (nums[l] <= target && target < nums[m]) { + r = m - 1; + } else { + l = m + 1; + } + } else if (nums[l] > nums[m]) { + if (nums[m] < target && target <= nums[r]) { + l = m + 1; + } else { + r = m - 1; + } + } else { + l++; + } + } + return false; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/search-insert-position.md b/articles/search-insert-position.md index 225a7e0a1..7e6cbd60e 100644 --- a/articles/search-insert-position.md +++ b/articles/search-insert-position.md @@ -56,6 +56,19 @@ class Solution { } ``` +```csharp +public class Solution { + public int SearchInsert(int[] nums, int target) { + for (int i = 0; i < nums.Length; i++) { + if (nums[i] >= target) { + return i; + } + } + return nums.Length; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -158,6 +171,30 @@ class Solution { } ``` +```csharp +public class Solution { + public int SearchInsert(int[] nums, int target) { + int res = nums.Length; + int l = 0, r = nums.Length - 1; + + while (l <= r) { + int mid = (l + r) / 2; + if (nums[mid] == target) { + return mid; + } + if (nums[mid] > target) { + res = mid; + r = mid - 1; + } else { + l = mid + 1; + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -252,6 +289,28 @@ class Solution { } ``` +```csharp +public class Solution { + public int SearchInsert(int[] nums, int target) { + int l = 0, r = nums.Length - 1; + + while (l <= r) { + int mid = (l + r) / 2; + if (nums[mid] == target) { + return mid; + } + if (nums[mid] > target) { + r = mid - 1; + } else { + l = mid + 1; + } + } + + return l; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -335,6 +394,25 @@ class Solution { } ``` +```csharp +public class Solution { + public int SearchInsert(int[] nums, int target) { + int l = 0, r = nums.Length; + + while (l < r) { + int m = l + (r - l) / 2; + if (nums[m] >= target) { + r = m; + } else { + l = m + 1; + } + } + + return l; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -388,6 +466,15 @@ class Solution { } ``` +```csharp +public class Solution { + public int SearchInsert(int[] nums, int target) { + int idx = Array.BinarySearch(nums, target); + return idx >= 0 ? idx : ~idx; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/simplify-path.md b/articles/simplify-path.md index 23fe29c96..ae0ecb3ee 100644 --- a/articles/simplify-path.md +++ b/articles/simplify-path.md @@ -105,6 +105,32 @@ class Solution { } ``` +```csharp +public class Solution { + public string SimplifyPath(string path) { + Stack stack = new Stack(); + string cur = ""; + + foreach (char c in path + "/") { + if (c == '/') { + if (cur == "..") { + if (stack.Count > 0) stack.Pop(); + } else if (cur != "" && cur != ".") { + stack.Push(cur); + } + cur = ""; + } else { + cur += c; + } + } + + var result = new List(stack); + result.Reverse(); + return "/" + string.Join("/", result); + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -205,6 +231,29 @@ class Solution { } ``` +```csharp +public class Solution { + public string SimplifyPath(string path) { + Stack stack = new Stack(); + string[] parts = path.Split('/'); + + foreach (string part in parts) { + if (part == "..") { + if (stack.Count > 0) { + stack.Pop(); + } + } else if (part != "" && part != ".") { + stack.Push(part); + } + } + + var result = new List(stack); + result.Reverse(); + return "/" + string.Join("/", result); + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/single-threaded-cpu.md b/articles/single-threaded-cpu.md index 5b7005989..16f487b94 100644 --- a/articles/single-threaded-cpu.md +++ b/articles/single-threaded-cpu.md @@ -109,12 +109,12 @@ class Solution { * @return {number[]} */ getOrder(tasks) { - const available = new MinPriorityQueue({ - compare: (a, b) => a[0] === b[0] ? a[1] - b[1] : a[0] - b[0] - }); - const pending = new MinPriorityQueue({ - compare: (a, b) => a[0] - b[0] - }); + const available = new PriorityQueue( + (a, b) => a[0] === b[0] ? a[1] - b[1] : a[0] - b[0] + ); + const pending = new PriorityQueue( + (a, b) => a[0] - b[0] + ); tasks.forEach(([enqueueTime, processTime], i) => { pending.enqueue([enqueueTime, processTime, i]); @@ -143,6 +143,42 @@ class Solution { } ``` +```csharp +public class Solution { + public int[] GetOrder(int[][] tasks) { + var available = new PriorityQueue<(int procTime, int index), (int procTime, int index)>(); + var pending = new PriorityQueue<(int startTime, int procTime, int index), int>(); + + int n = tasks.Length; + for (int i = 0; i < n; i++) { + pending.Enqueue((tasks[i][0], tasks[i][1], i), tasks[i][0]); + } + + long time = 0; + int[] res = new int[n]; + int idx = 0; + + while (pending.Count > 0 || available.Count > 0) { + while (pending.Count > 0 && pending.Peek().startTime <= time) { + var task = pending.Dequeue(); + available.Enqueue((task.procTime, task.index), (task.procTime, task.index)); + } + + if (available.Count == 0) { + time = pending.Peek().startTime; + continue; + } + + var next = available.Dequeue(); + time += next.procTime; + res[idx++] = next.index; + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -259,9 +295,9 @@ class Solution { tasks.sort((a, b) => a[0] - b[0]); const res = []; - const minHeap = new MinPriorityQueue({ compare: (a, b) => + const minHeap = new PriorityQueue((a, b) => a[0] === b[0] ? a[1] - b[1] : a[0] - b[0] - }); + ); let i = 0, time = tasks[0][0]; while (minHeap.size() || i < n) { @@ -282,6 +318,44 @@ class Solution { } ``` +```csharp +public class Solution { + public int[] GetOrder(int[][] tasks) { + int n = tasks.Length; + int i = 0; + for (; i < n; i++) { + tasks[i] = new int[] { tasks[i][0], tasks[i][1], i }; // {enqueueTime, processingTime, index} + } + + Array.Sort(tasks, (a, b) => a[0].CompareTo(b[0])); // sort by enqueueTime + + int[] res = new int[n]; + var minHeap = new PriorityQueue<(int procTime, int index), (int procTime, int index)>(); + + int idx = 0; + i = 0; + long time = tasks[0][0]; + + while (minHeap.Count > 0 || i < n) { + while (i < n && tasks[i][0] <= time) { + minHeap.Enqueue((tasks[i][1], tasks[i][2]), (tasks[i][1], tasks[i][2])); + i++; + } + + if (minHeap.Count == 0) { + time = tasks[i][0]; + } else { + var task = minHeap.Dequeue(); + time += task.procTime; + res[idx++] = task.index; + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -430,14 +504,14 @@ class Solution { return a - b; }); - const minHeap = new MinPriorityQueue({ - compare: (a, b) => { + const minHeap = new PriorityQueue( + (a, b) => { if (tasks[a][1] !== tasks[b][1]) { return tasks[a][1] - tasks[b][1]; } return a - b; } - }); + ); const res = []; let time = 0; @@ -463,6 +537,48 @@ class Solution { } ``` +```csharp +public class Solution { + public int[] GetOrder(int[][] tasks) { + int n = tasks.Length; + int[] indices = new int[n]; + int i = 0; + for (; i < n; i++) { + indices[i] = i; + } + + Array.Sort(indices, (a, b) => + tasks[a][0] != tasks[b][0] ? tasks[a][0].CompareTo(tasks[b][0]) : a.CompareTo(b) + ); + + var minHeap = new PriorityQueue(); + + int[] result = new int[n]; + long time = 0; + int resIndex = 0; + i = 0; + + while (minHeap.Count > 0 || i < n) { + while (i < n && tasks[indices[i]][0] <= time) { + int idx = indices[i]; + minHeap.Enqueue(idx, (tasks[idx][1], idx)); + i++; + } + + if (minHeap.Count == 0) { + time = tasks[indices[i]][0]; + } else { + int nextIndex = minHeap.Dequeue(); + time += tasks[nextIndex][1]; + result[resIndex++] = nextIndex; + } + } + + return result; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/split-array-largest-sum.md b/articles/split-array-largest-sum.md index dccf649c5..617691f9b 100644 --- a/articles/split-array-largest-sum.md +++ b/articles/split-array-largest-sum.md @@ -113,6 +113,36 @@ class Solution { } ``` +```csharp +public class Solution { + public int SplitArray(int[] nums, int k) { + int n = nums.Length; + return Dfs(nums, 0, k, n); + } + + private int Dfs(int[] nums, int i, int m, int n) { + if (i == n) { + return m == 0 ? 0 : int.MaxValue; + } + if (m == 0) { + return int.MaxValue; + } + + int res = int.MaxValue; + int curSum = 0; + for (int j = i; j <= n - m; j++) { + curSum += nums[j]; + int next = Dfs(nums, j + 1, m - 1, n); + if (next != int.MaxValue) { + res = Math.Min(res, Math.Max(curSum, next)); + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -231,7 +261,7 @@ class Solution { */ splitArray(nums, k) { const n = nums.length; - const dp = Array.from({ length: n }, () => Array(m + 1).fill(-1)); + const dp = Array.from({ length: n }, () => Array(k + 1).fill(-1)); const dfs = (i, m) => { if (i === n) { @@ -259,6 +289,50 @@ class Solution { } ``` +```csharp +public class Solution { + private int[,] dp; + + public int SplitArray(int[] nums, int k) { + int n = nums.Length; + dp = new int[n, k + 1]; + + for (int i = 0; i < n; i++) { + for (int j = 0; j <= k; j++) { + dp[i, j] = -1; + } + } + + return Dfs(nums, 0, k, n); + } + + private int Dfs(int[] nums, int i, int m, int n) { + if (i == n) { + return m == 0 ? 0 : int.MaxValue; + } + if (m == 0) { + return int.MaxValue; + } + if (dp[i, m] != -1) { + return dp[i, m]; + } + + int res = int.MaxValue; + int curSum = 0; + for (int j = i; j <= n - m; j++) { + curSum += nums[j]; + int next = Dfs(nums, j + 1, m - 1, n); + if (next != int.MaxValue) { + res = Math.Min(res, Math.Max(curSum, next)); + } + } + + dp[i, m] = res; + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -368,6 +442,37 @@ class Solution { } ``` +```csharp +public class Solution { + public int SplitArray(int[] nums, int k) { + int n = nums.Length; + int[,] dp = new int[n + 1, k + 1]; + + for (int i = 0; i <= n; i++) { + for (int j = 0; j <= k; j++) { + dp[i, j] = int.MaxValue; + } + } + + dp[n, 0] = 0; + + for (int m = 1; m <= k; m++) { + for (int i = n - 1; i >= 0; i--) { + int curSum = 0; + for (int j = i; j < n - m + 1; j++) { + curSum += nums[j]; + if (dp[j + 1, m - 1] != int.MaxValue) { + dp[i, m] = Math.Min(dp[i, m], Math.Max(curSum, dp[j + 1, m - 1])); + } + } + } + } + + return dp[0, k]; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -485,6 +590,36 @@ class Solution { } ``` +```csharp +public class Solution { + public int SplitArray(int[] nums, int k) { + int n = nums.Length; + int[] dp = new int[n + 1]; + int[] nextDp = new int[n + 1]; + Array.Fill(dp, int.MaxValue); + dp[n] = 0; + + for (int m = 1; m <= k; m++) { + Array.Fill(nextDp, int.MaxValue); + for (int i = n - 1; i >= 0; i--) { + int curSum = 0; + for (int j = i; j < n - m + 1; j++) { + curSum += nums[j]; + if (dp[j + 1] != int.MaxValue) { + nextDp[i] = Math.Min(nextDp[i], Math.Max(curSum, dp[j + 1])); + } + } + } + var temp = dp; + dp = nextDp; + nextDp = temp; + } + + return dp[0]; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -639,6 +774,43 @@ class Solution { } ``` +```csharp +public class Solution { + public int SplitArray(int[] nums, int k) { + int l = 0, r = 0, res = 0; + foreach (int num in nums) { + l = Math.Max(l, num); + r += num; + } + res = r; + + while (l <= r) { + int mid = l + (r - l) / 2; + if (CanSplit(nums, k, mid)) { + res = mid; + r = mid - 1; + } else { + l = mid + 1; + } + } + return res; + } + + private bool CanSplit(int[] nums, int k, int largest) { + int subarray = 1, curSum = 0; + foreach (int num in nums) { + curSum += num; + if (curSum > largest) { + subarray++; + if (subarray > k) return false; + curSum = num; + } + } + return true; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -852,6 +1024,60 @@ class Solution { } ``` +```csharp +public class Solution { + private int[] prefix; + private int n; + + public int SplitArray(int[] nums, int k) { + n = nums.Length; + prefix = new int[n + 1]; + for (int i = 0; i < n; i++) { + prefix[i + 1] = prefix[i] + nums[i]; + } + + int l = int.MinValue, r = 0; + foreach (int num in nums) { + l = Math.Max(l, num); + r += num; + } + + int res = r; + while (l <= r) { + int mid = l + (r - l) / 2; + if (CanSplit(mid, k)) { + res = mid; + r = mid - 1; + } else { + l = mid + 1; + } + } + return res; + } + + private bool CanSplit(int largest, int k) { + int subarrays = 0, i = 0; + while (i < n) { + int l = i + 1, r = n; + while (l <= r) { + int mid = l + (r - l) / 2; + if (prefix[mid] - prefix[i] <= largest) { + l = mid + 1; + } else { + r = mid - 1; + } + } + subarrays++; + i = r; + if (subarrays > k) { + return false; + } + } + return true; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/sqrtx.md b/articles/sqrtx.md index 13d854b33..bc2e10fa7 100644 --- a/articles/sqrtx.md +++ b/articles/sqrtx.md @@ -82,6 +82,23 @@ class Solution { } ``` +```csharp +public class Solution { + public int MySqrt(int x) { + if (x == 0) return 0; + + int res = 1; + for (int i = 1; i <= x; i++) { + if ((long)i * i > x) { + return res; + } + res = i; + } + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -130,6 +147,14 @@ class Solution { } ``` +```csharp +public class Solution { + public int MySqrt(int x) { + return (int)Math.Sqrt(x); + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -236,6 +261,31 @@ class Solution { } ``` +```csharp +public class Solution { + public int MySqrt(int x) { + int l = 0, r = x; + int res = 0; + + while (l <= r) { + int m = l + (r - l) / 2; + long sq = (long)m * m; + + if (sq > x) { + r = m - 1; + } else if (sq < x) { + l = m + 1; + res = m; + } else { + return m; + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -307,6 +357,20 @@ class Solution { } ``` +```csharp +public class Solution { + public int MySqrt(int x) { + if (x < 2) { + return x; + } + + int l = MySqrt(x >> 2) << 1; + int r = l + 1; + return (long)r * r > x ? l : r; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -370,6 +434,18 @@ class Solution { } ``` +```csharp +public class Solution { + public int MySqrt(int x) { + long r = x; + while (r * r > x) { + r = (r + x / r) >> 1; + } + return (int)r; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/stone-game-iii.md b/articles/stone-game-iii.md index e95a8e508..781024036 100644 --- a/articles/stone-game-iii.md +++ b/articles/stone-game-iii.md @@ -144,6 +144,40 @@ class Solution { } ``` +```csharp +public class Solution { + public string StoneGameIII(int[] stoneValue) { + int n = stoneValue.Length; + int?[,] dp = new int?[n, 2]; + + int Dfs(int i, int alice) { + if (i >= n) return 0; + if (dp[i, alice].HasValue) return dp[i, alice].Value; + + int res = alice == 1 ? int.MinValue : int.MaxValue; + int score = 0; + + for (int j = i; j < Math.Min(i + 3, n); j++) { + if (alice == 1) { + score += stoneValue[j]; + res = Math.Max(res, score + Dfs(j + 1, 0)); + } else { + score -= stoneValue[j]; + res = Math.Min(res, score + Dfs(j + 1, 1)); + } + } + + dp[i, alice] = res; + return res; + } + + int result = Dfs(0, 1); + if (result == 0) return "Tie"; + return result > 0 ? "Alice" : "Bob"; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -277,6 +311,33 @@ class Solution { } ``` +```csharp +public class Solution { + public string StoneGameIII(int[] stoneValue) { + int n = stoneValue.Length; + Dictionary dp = new Dictionary(); + + int Dfs(int i) { + if (i >= n) return 0; + if (dp.ContainsKey(i)) return dp[i]; + + int res = int.MinValue, total = 0; + for (int j = i; j < Math.Min(i + 3, n); j++) { + total += stoneValue[j]; + res = Math.Max(res, total - Dfs(j + 1)); + } + + dp[i] = res; + return res; + } + + int result = Dfs(0); + if (result == 0) return "Tie"; + return result > 0 ? "Alice" : "Bob"; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -384,6 +445,29 @@ class Solution { } ``` +```csharp +public class Solution { + public string StoneGameIII(int[] stoneValue) { + int n = stoneValue.Length; + int[] dp = new int[n + 1]; + for (int i = 0; i <= n; i++) dp[i] = int.MinValue; + dp[n] = 0; + + for (int i = n - 1; i >= 0; i--) { + int total = 0; + for (int j = i; j < Math.Min(i + 3, n); j++) { + total += stoneValue[j]; + dp[i] = Math.Max(dp[i], total - dp[j + 1]); + } + } + + int result = dp[0]; + if (result == 0) return "Tie"; + return result > 0 ? "Alice" : "Bob"; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -483,6 +567,28 @@ class Solution { } ``` +```csharp +public class Solution { + public string StoneGameIII(int[] stoneValue) { + int n = stoneValue.Length; + int[] dp = new int[4]; + + for (int i = n - 1; i >= 0; i--) { + int total = 0; + dp[i % 4] = int.MinValue; + + for (int j = i; j < Math.Min(i + 3, n); j++) { + total += stoneValue[j]; + dp[i % 4] = Math.Max(dp[i % 4], total - dp[(j + 1) % 4]); + } + } + + if (dp[0] == 0) return "Tie"; + return dp[0] > 0 ? "Alice" : "Bob"; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/sum-of-all-subset-xor-totals.md b/articles/sum-of-all-subset-xor-totals.md index b1f8dc9ae..b35c24e37 100644 --- a/articles/sum-of-all-subset-xor-totals.md +++ b/articles/sum-of-all-subset-xor-totals.md @@ -98,6 +98,31 @@ class Solution { } ``` +```csharp +public class Solution { + private int res = 0; + + public int SubsetXORSum(int[] nums) { + Backtrack(0, new List(), nums); + return res; + } + + private void Backtrack(int i, List subset, int[] nums) { + int xorr = 0; + foreach (int num in subset) { + xorr ^= num; + } + res += xorr; + + for (int j = i; j < nums.Length; j++) { + subset.Add(nums[j]); + Backtrack(j + 1, subset, nums); + subset.RemoveAt(subset.Count - 1); + } + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -173,6 +198,21 @@ class Solution { } ``` +```csharp +public class Solution { + public int SubsetXORSum(int[] nums) { + return Dfs(0, 0, nums); + } + + private int Dfs(int i, int total, int[] nums) { + if (i == nums.Length) { + return total; + } + return Dfs(i + 1, total ^ nums[i], nums) + Dfs(i + 1, total, nums); + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -270,6 +310,27 @@ class Solution { } ``` +```csharp +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; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -333,6 +394,18 @@ class Solution { } ``` +```csharp +public class Solution { + public int SubsetXORSum(int[] nums) { + int res = 0; + foreach (int num in nums) { + res |= num; + } + return res << (nums.Length - 1); + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/verifying-an-alien-dictionary.md b/articles/verifying-an-alien-dictionary.md index 7ab6ac58d..86694cf0a 100644 --- a/articles/verifying-an-alien-dictionary.md +++ b/articles/verifying-an-alien-dictionary.md @@ -84,6 +84,35 @@ class Solution { } ``` +```csharp +public class Solution { + public bool IsAlienSorted(string[] words, string order) { + int[] orderIndex = new int[26]; + for (int i = 0; i < order.Length; i++) { + orderIndex[order[i] - 'a'] = i; + } + + string[] sortedWords = (string[])words.Clone(); + Array.Sort(sortedWords, (w1, w2) => { + for (int i = 0; i < Math.Min(w1.Length, w2.Length); i++) { + if (w1[i] != w2[i]) { + return orderIndex[w1[i] - 'a'] - orderIndex[w2[i] - 'a']; + } + } + return w1.Length - w2.Length; + }); + + for (int i = 0; i < words.Length; i++) { + if (!words[i].Equals(sortedWords[i])) { + return false; + } + } + + return true; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -201,6 +230,37 @@ class Solution { } ``` +```csharp +public class Solution { + public bool IsAlienSorted(string[] words, string order) { + Dictionary orderIndex = new Dictionary(); + for (int i = 0; i < order.Length; i++) { + orderIndex[order[i]] = i; + } + + for (int i = 0; i < words.Length - 1; i++) { + string w1 = words[i]; + string w2 = words[i + 1]; + + for (int j = 0; j < w1.Length; j++) { + if (j == w2.Length) { + return false; + } + + if (w1[j] != w2[j]) { + if (orderIndex[w1[j]] > orderIndex[w2[j]]) { + return false; + } + break; + } + } + } + + return true; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/word-break-ii.md b/articles/word-break-ii.md index c075d2b67..45660e5f9 100644 --- a/articles/word-break-ii.md +++ b/articles/word-break-ii.md @@ -131,6 +131,35 @@ class Solution { } ``` +```csharp +public class Solution { + public List WordBreak(string s, List wordDict) { + HashSet wordSet = new HashSet(wordDict); + List res = new List(); + List cur = new List(); + + void Backtrack(int i) { + if (i == s.Length) { + res.Add(string.Join(" ", cur)); + return; + } + + for (int j = i; j < s.Length; j++) { + string word = s.Substring(i, j - i + 1); + if (wordSet.Contains(word)) { + cur.Add(word); + Backtrack(j + 1); + cur.RemoveAt(cur.Count - 1); + } + } + } + + Backtrack(0); + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -401,6 +430,66 @@ class Solution { } ``` +```csharp +public class TrieNode { + public Dictionary children = new Dictionary(); + public bool isWord = false; +} + +public class Trie { + public TrieNode root = new TrieNode(); + + public void AddWord(string word) { + TrieNode curr = root; + foreach (char c in word) { + if (!curr.children.ContainsKey(c)) { + curr.children[c] = new TrieNode(); + } + curr = curr.children[c]; + } + curr.isWord = true; + } +} + +public class Solution { + public List WordBreak(string s, List wordDict) { + Trie trie = new Trie(); + foreach (string word in wordDict) { + trie.AddWord(word); + } + + List res = new List(); + + void Backtrack(int index, List path) { + if (index == s.Length) { + res.Add(string.Join(" ", path)); + return; + } + + TrieNode node = trie.root; + StringBuilder word = new StringBuilder(); + + for (int i = index; i < s.Length; i++) { + char c = s[i]; + if (!node.children.ContainsKey(c)) break; + + word.Append(c); + node = node.children[c]; + + if (node.isWord) { + path.Add(word.ToString()); + Backtrack(i + 1, path); + path.RemoveAt(path.Count - 1); + } + } + } + + Backtrack(0, new List()); + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -561,6 +650,40 @@ class Solution { } ``` +```csharp +public class Solution { + public List WordBreak(string s, List wordDictList) { + HashSet wordDict = new HashSet(wordDictList); + Dictionary> cache = new Dictionary>(); + + List Backtrack(int i) { + if (i == s.Length) return new List { "" }; + if (cache.ContainsKey(i)) return cache[i]; + + List res = new List(); + for (int j = i; j < s.Length; j++) { + string w = s.Substring(i, j - i + 1); + if (!wordDict.Contains(w)) continue; + + List substrings = Backtrack(j + 1); + foreach (string substr in substrings) { + string sentence = w; + if (!string.IsNullOrEmpty(substr)) { + sentence += " " + substr; + } + res.Add(sentence); + } + } + + cache[i] = res; + return res; + } + + return Backtrack(0); + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -676,6 +799,34 @@ class Solution { } ``` +```csharp +public class Solution { + public List WordBreak(string s, List wordDictList) { + HashSet wordSet = new HashSet(wordDictList); + int n = s.Length; + List[] dp = new List[n + 1]; + for (int i = 0; i <= n; i++) { + dp[i] = new List(); + } + dp[0].Add(""); + + for (int i = 1; i <= n; i++) { + for (int j = 0; j < i; j++) { + string word = s.Substring(j, i - j); + if (wordSet.Contains(word)) { + foreach (string sentence in dp[j]) { + string space = string.IsNullOrEmpty(sentence) ? "" : " "; + dp[i].Add(sentence + space + word); + } + } + } + } + + return dp[n]; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -965,6 +1116,68 @@ class Solution { } ``` +```csharp +public class TrieNode { + public Dictionary Children = new Dictionary(); + public bool IsWord = false; +} + +public class Trie { + public TrieNode Root = new TrieNode(); + + public void AddWord(string word) { + TrieNode curr = Root; + foreach (char c in word) { + if (!curr.Children.ContainsKey(c)) { + curr.Children[c] = new TrieNode(); + } + curr = curr.Children[c]; + } + curr.IsWord = true; + } +} + +public class Solution { + private Dictionary> cache = new Dictionary>(); + + public List WordBreak(string s, List wordDict) { + Trie trie = new Trie(); + foreach (string word in wordDict) { + trie.AddWord(word); + } + return Backtrack(0, s, trie.Root, trie); + } + + private List Backtrack(int index, string s, TrieNode root, Trie trie) { + if (index == s.Length) return new List { "" }; + if (cache.ContainsKey(index)) return cache[index]; + + List res = new List(); + TrieNode curr = root; + + for (int i = index; i < s.Length; i++) { + char c = s[i]; + if (!curr.Children.ContainsKey(c)) break; + + curr = curr.Children[c]; + if (curr.IsWord) { + List suffixes = Backtrack(i + 1, s, root, trie); + foreach (string suffix in suffixes) { + if (suffix == "") { + res.Add(s.Substring(index, i - index + 1)); + } else { + res.Add(s.Substring(index, i - index + 1) + " " + suffix); + } + } + } + } + + cache[index] = res; + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity