diff --git a/articles/best-team-with-no-conflicts.md b/articles/best-team-with-no-conflicts.md new file mode 100644 index 000000000..a4e77a374 --- /dev/null +++ b/articles/best-team-with-no-conflicts.md @@ -0,0 +1,649 @@ +## 1. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def bestTeamScore(self, scores: List[int], ages: List[int]) -> int: + pairs = [[scores[i], ages[i]] for i in range(len(scores))] + pairs.sort() + dp = {} + + def dfs(i, j): + if i == len(pairs): + return 0 + if (i, j) in dp: + return dp[(i, j)] + + mScore, mAge = pairs[j] if j >= 0 else [0, 0] + score, age = pairs[i] + res = 0 + if not (score > mScore and age < mAge): + res = dfs(i + 1, i) + score # add score + dp[(i, j)] = max(res, dfs(i + 1, j)) # skip score + return dp[(i, j)] + + return dfs(0, -1) +``` + +```java +public class Solution { + private int[][] pairs; + private int[][] dp; + + public int bestTeamScore(int[] scores, int[] ages) { + int n = scores.length; + pairs = new int[n][2]; + for (int i = 0; i < n; i++) { + pairs[i][0] = scores[i]; + pairs[i][1] = ages[i]; + } + Arrays.sort(pairs, (a, b) -> a[0] == b[0] ? Integer.compare(a[1], b[1]) : Integer.compare(a[0], b[0])); + + dp = new int[n][n + 1]; + for (int[] row : dp) { + Arrays.fill(row, -1); + } + + return dfs(0, -1); + } + + private int dfs(int i, int j) { + if (i == pairs.length) { + return 0; + } + if (dp[i][j + 1] != -1) { + return dp[i][j + 1]; + } + + int mScore = j >= 0 ? pairs[j][0] : 0; + int mAge = j >= 0 ? pairs[j][1] : 0; + int score = pairs[i][0]; + int age = pairs[i][1]; + + int res = 0; + if (!(score > mScore && age < mAge)) { + res = dfs(i + 1, i) + score; + } + dp[i][j + 1] = Math.max(res, dfs(i + 1, j)); + return dp[i][j + 1]; + } +} +``` + +```cpp +class Solution { +private: + vector> pairs; + vector> dp; + +public: + int bestTeamScore(vector& scores, vector& ages) { + int n = scores.size(); + pairs.resize(n); + for (int i = 0; i < n; i++) { + pairs[i] = {scores[i], ages[i]}; + } + sort(pairs.begin(), pairs.end()); + + dp = vector>(n, vector(n + 1, -1)); + return dfs(0, -1); + } + +private: + int dfs(int i, int j) { + if (i == pairs.size()) { + return 0; + } + if (dp[i][j + 1] != -1) { + return dp[i][j + 1]; + } + + int mScore = j >= 0 ? pairs[j].first : 0; + int mAge = j >= 0 ? pairs[j].second : 0; + int score = pairs[i].first; + int age = pairs[i].second; + + int res = 0; + if (!(score > mScore && age < mAge)) { + res = dfs(i + 1, i) + score; + } + dp[i][j + 1] = max(res, dfs(i + 1, j)); + return dp[i][j + 1]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} scores + * @param {number[]} ages + * @return {number} + */ + bestTeamScore(scores, ages) { + const n = scores.length; + const pairs = []; + for (let i = 0; i < n; i++) { + pairs.push([scores[i], ages[i]]); + } + pairs.sort((a, b) => (a[0] === b[0] ? a[1] - b[1] : a[0] - b[0])); + + const 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]; + } + + const [mScore, mAge] = j >= 0 ? pairs[j] : [0, 0]; + const [score, age] = pairs[i]; + + let res = 0; + if (!(score > mScore && age < mAge)) { + res = dfs(i + 1, i) + score; + } + dp[i][j + 1] = Math.max(res, dfs(i + 1, j)); + return dp[i][j + 1]; + }; + + return dfs(0, -1); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n ^ 2)$ + +--- + +## 2. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def bestTeamScore(self, scores: List[int], ages: List[int]) -> int: + pairs = [[scores[i], ages[i]] for i in range(len(scores))] + pairs.sort() + dp = [pairs[i][0] for i in range(len(pairs))] + + for i in range(len(pairs)): + mScore, mAge = pairs[i] + for j in range(i): + score, age = pairs[j] + if mAge >= age: + dp[i] = max(dp[i], mScore + dp[j]) + + return max(dp) +``` + +```java +public class Solution { + public int bestTeamScore(int[] scores, int[] ages) { + int n = scores.length; + int[][] pairs = new int[n][2]; + for (int i = 0; i < n; i++) { + pairs[i][0] = scores[i]; + pairs[i][1] = ages[i]; + } + Arrays.sort(pairs, (a, b) -> a[0] == b[0] ? Integer.compare(a[1], b[1]) : Integer.compare(a[0], b[0])); + + int[] dp = new int[n]; + for (int i = 0; i < n; i++) { + dp[i] = pairs[i][0]; + } + + for (int i = 0; i < n; i++) { + int mScore = pairs[i][0], mAge = pairs[i][1]; + for (int j = 0; j < i; j++) { + int score = pairs[j][0], age = pairs[j][1]; + if (mAge >= age) { + dp[i] = Math.max(dp[i], mScore + dp[j]); + } + } + } + + int maxScore = 0; + for (int score : dp) { + maxScore = Math.max(maxScore, score); + } + return maxScore; + } +} +``` + +```cpp +class Solution { +public: + int bestTeamScore(vector& scores, vector& ages) { + int n = scores.size(); + vector> pairs(n); + for (int i = 0; i < n; i++) { + pairs[i] = {scores[i], ages[i]}; + } + sort(pairs.begin(), pairs.end()); + + vector dp(n); + for (int i = 0; i < n; i++) { + dp[i] = pairs[i].first; + } + + for (int i = 0; i < n; i++) { + int mScore = pairs[i].first, mAge = pairs[i].second; + for (int j = 0; j < i; j++) { + int score = pairs[j].first, age = pairs[j].second; + if (mAge >= age) { + dp[i] = max(dp[i], mScore + dp[j]); + } + } + } + + return *max_element(dp.begin(), dp.end()); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} scores + * @param {number[]} ages + * @return {number} + */ + bestTeamScore(scores, ages) { + const n = scores.length; + const pairs = []; + for (let i = 0; i < n; i++) { + pairs.push([scores[i], ages[i]]); + } + pairs.sort((a, b) => (a[0] === b[0] ? a[1] - b[1] : a[0] - b[0])); + + const dp = new Array(n).fill(0); + for (let i = 0; i < n; i++) { + dp[i] = pairs[i][0]; + } + + for (let i = 0; i < n; i++) { + const [mScore, mAge] = pairs[i]; + for (let j = 0; j < i; j++) { + const [score, age] = pairs[j]; + if (mAge >= age) { + dp[i] = Math.max(dp[i], mScore + dp[j]); + } + } + } + + return Math.max(...dp); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* 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.build() + + def build(self): + self.tree = [0] * (2 * self.n) + + def update(self, i, val): + pos = self.n + i + self.tree[pos] = max(self.tree[pos], val) + pos >>= 1 + while pos >= 1: + self.tree[pos] = max(self.tree[pos << 1], self.tree[pos << 1 | 1]) + pos >>= 1 + + def query(self, l, r): + res = 0 + 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 res + +class Solution: + def bestTeamScore(self, scores: list[int], ages: list[int]) -> int: + pairs = [[scores[i], ages[i]] for i in range(len(scores))] + pairs.sort() + + dp = [pairs[i][0] for i in range(len(pairs))] + unique_ages = sorted({ age for _, age in pairs }) + ageId = { val: idx for idx, val in enumerate(unique_ages) } + + segtree = SegmentTree(len(pairs)) + + res = 0 + for i in range(len(pairs)): + mScore, mAge = pairs[i] + idx = ageId[mAge] + j = segtree.query(0, idx) + dp[i] = j + mScore + segtree.update(idx, dp[i]) + res = max(res, dp[i]) + + return res +``` + +```java +class SegmentTree { + private int n; + private int[] tree; + + public SegmentTree(int N) { + n = N; + while ((n & (n - 1)) != 0) { + n++; + } + build(); + } + + private void build() { + tree = new int[2 * n]; + } + + public void update(int i, int val) { + int pos = n + i; + tree[pos] = Math.max(tree[pos], val); + pos >>= 1; + while (pos >= 1) { + tree[pos] = Math.max(tree[pos << 1], tree[pos << 1 | 1]); + pos >>= 1; + } + } + + public int query(int l, int r) { + int res = 0; + 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 res; + } +} + +public class Solution { + public int bestTeamScore(int[] scores, int[] ages) { + int n = scores.length; + int[][] pairs = new int[n][2]; + for (int i = 0; i < n; i++) { + pairs[i][0] = scores[i]; + pairs[i][1] = ages[i]; + } + Arrays.sort(pairs, (a, b) -> a[0] == b[0] ? Integer.compare(a[1], b[1]) : Integer.compare(a[0], b[0])); + + int[] dp = new int[n]; + for (int i = 0; i < n; i++) { + dp[i] = pairs[i][0]; + } + + Set uniqueAgesSet = new TreeSet<>(); + for (int[] pair : pairs) { + uniqueAgesSet.add(pair[1]); + } + List uniqueAges = new ArrayList<>(uniqueAgesSet); + Map ageId = new HashMap<>(); + for (int i = 0; i < uniqueAges.size(); i++) { + ageId.put(uniqueAges.get(i), i); + } + + SegmentTree segtree = new SegmentTree(uniqueAges.size()); + + int res = 0; + for (int i = 0; i < n; i++) { + int mScore = pairs[i][0]; + int mAge = pairs[i][1]; + int idx = ageId.get(mAge); + int j = segtree.query(0, idx); + dp[i] = j + mScore; + segtree.update(idx, dp[i]); + res = Math.max(res, dp[i]); + } + + return res; + } +} +``` + +```cpp +class SegmentTree { +private: + int n; + vector tree; + +public: + SegmentTree(int N) { + n = N; + while ((n & (n - 1)) != 0) { + n++; + } + build(); + } + + void build() { + tree.resize(2 * n, 0); + } + + void update(int i, int val) { + int pos = n + i; + tree[pos] = max(tree[pos], val); + pos >>= 1; + while (pos >= 1) { + tree[pos] = max(tree[pos << 1], tree[pos << 1 | 1]); + pos >>= 1; + } + } + + int query(int l, int r) { + int res = 0; + 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 res; + } +}; + +class Solution { +public: + int bestTeamScore(vector& scores, vector& ages) { + int n = scores.size(); + vector> pairs(n); + for (int i = 0; i < n; i++) { + pairs[i] = {scores[i], ages[i]}; + } + sort(pairs.begin(), pairs.end()); + + vector dp(n); + for (int i = 0; i < n; i++) { + dp[i] = pairs[i].first; + } + + set uniqueAgesSet; + for (auto& pair : pairs) { + uniqueAgesSet.insert(pair.second); + } + vector uniqueAges(uniqueAgesSet.begin(), uniqueAgesSet.end()); + map ageId; + for (int i = 0; i < uniqueAges.size(); i++) { + ageId[uniqueAges[i]] = i; + } + + SegmentTree segtree(uniqueAges.size()); + + int res = 0; + for (int i = 0; i < n; i++) { + int mScore = pairs[i].first; + int mAge = pairs[i].second; + int idx = ageId[mAge]; + int j = segtree.query(0, idx); + dp[i] = j + mScore; + segtree.update(idx, dp[i]); + res = max(res, dp[i]); + } + + return res; + } +}; +``` + +```javascript +class SegmentTree { + /** + * @constructor + * @param {number} N + */ + constructor(N) { + this.n = N; + while ((this.n & (this.n - 1)) !== 0) { + this.n++; + } + this.build(); + } + + /** + * @return {void} + */ + build() { + this.tree = new Array(2 * this.n).fill(0); + } + + /** + * @param {number} i + * @param {number} val + * @return {void} + */ + update(i, val) { + let pos = this.n + i; + this.tree[pos] = Math.max(this.tree[pos], val); + pos >>= 1; + while (pos >= 1) { + this.tree[pos] = Math.max(this.tree[pos << 1], this.tree[pos << 1 | 1]); + pos >>= 1; + } + } + + /** + * @param {number} l + * @param {number} r + * @return {number} + */ + query(l, r) { + let res = 0; + 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 res; + } +} + +class Solution { + /** + * @param {number[]} scores + * @param {number[]} ages + * @return {number} + */ + bestTeamScore(scores, ages) { + const n = scores.length; + const pairs = []; + + for (let i = 0; i < n; i++) { + pairs.push([scores[i], ages[i]]); + } + pairs.sort((a, b) => (a[0] === b[0] ? a[1] - b[1] : a[0] - b[0])); + + const dp = new Array(n).fill(0); + for (let i = 0; i < n; i++) { + dp[i] = pairs[i][0]; + } + + const uniqueAges = [...new Set(pairs.map((p) => p[1]))].sort((a, b) => a - b); + const ageId = new Map(); + uniqueAges.forEach((val, idx) => ageId.set(val, idx)); + + const segtree = new SegmentTree(uniqueAges.length); + + let res = 0; + + for (let i = 0; i < n; i++) { + const [mScore, mAge] = pairs[i]; + const idx = ageId.get(mAge); + const j = segtree.query(0, idx); + dp[i] = j + mScore; + segtree.update(idx, dp[i]); + res = Math.max(res, dp[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/count-ways-to-build-good-strings.md b/articles/count-ways-to-build-good-strings.md new file mode 100644 index 000000000..d1808c1e9 --- /dev/null +++ b/articles/count-ways-to-build-good-strings.md @@ -0,0 +1,283 @@ +## 1. Recursion + +::tabs-start + +```python +class Solution: + def countGoodStrings(self, low: int, high: int, zero: int, one: int) -> int: + mod = 10**9 + 7 + + def dfs(length): + if length > high: + return 0 + res = 1 if length >= low else 0 + res += dfs(length + zero) + dfs(length + one) + return res % mod + + return dfs(0) +``` + +```java +public class Solution { + final int mod = 1_000_000_007; + + public int countGoodStrings(int low, int high, int zero, int one) { + return dfs(low, high, zero, one, 0); + } + + private int dfs(int low, int high, int zero, int one, int length) { + if (length > high) return 0; + int res = (length >= low) ? 1 : 0; + res = (res + dfs(low, high, zero, one, length + zero)) % mod; + res = (res + dfs(low, high, zero, one, length + one)) % mod; + return res; + } +} +``` + +```cpp +class Solution { +public: + int countGoodStrings(int low, int high, int zero, int one) { + const int mod = 1e9 + 7; + + function dfs = [&](int length) { + if (length > high) return 0; + int res = (length >= low) ? 1 : 0; + res = (res + dfs(length + zero)) % mod; + res = (res + dfs(length + one)) % mod; + return res; + }; + + return dfs(0); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} low + * @param {number} high + * @param {number} zero + * @param {number} one + * @return {number} + */ + countGoodStrings(low, high, zero, one) { + const mod = 1e9 + 7; + + const dfs = length => { + if (length > high) return 0; + let res = length >= low ? 1 : 0; + res = (res + dfs(length + zero)) % mod; + res = (res + dfs(length + one)) % mod; + return res; + }; + + return dfs(0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(2 ^ n)$ +* Space complexity: $O(n)$ + +> Where $n$ is equal to the given $high$ value. + +--- + +## 2. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def countGoodStrings(self, low: int, high: int, zero: int, one: int) -> int: + mod = 10**9 + 7 + dp = {} + + def dfs(length): + if length > high: + return 0 + if length in dp: + return dp[length] + + dp[length] = 1 if length >= low else 0 + dp[length] += dfs(length + zero) + dfs(length + one) + return dp[length] % mod + + return dfs(0) +``` + +```java +public class Solution { + final int mod = 1_000_000_007; + private int[] dp; + + public int countGoodStrings(int low, int high, int zero, int one) { + dp = new int[high + 1]; + Arrays.fill(dp, -1); + return dfs(low, high, zero, one, 0); + } + + private int dfs(int low, int high, int zero, int one, int length) { + if (length > high) return 0; + if (dp[length] != -1) return dp[length]; + + dp[length] = (length >= low) ? 1 : 0; + dp[length] = (dp[length] + dfs(low, high, zero, one, length + zero)) % mod; + dp[length] = (dp[length] + dfs(low, high, zero, one, length + one)) % mod; + return dp[length]; + } +} +``` + +```cpp +class Solution { + const int mod = 1e9 + 7; + vector dp; + +public: + int countGoodStrings(int low, int high, int zero, int one) { + dp.assign(high + 1, -1); + return dfs(low, high, zero, one, 0); + } + +private: + int dfs(int low, int high, int zero, int one, int length) { + if (length > high) return 0; + if (dp[length] != -1) return dp[length]; + dp[length] = (length >= low) ? 1 : 0; + dp[length] = (dp[length] + dfs(low, high, zero, one, length + zero)) % mod; + dp[length] = (dp[length] + dfs(low, high, zero, one, length + one)) % mod; + return dp[length]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} low + * @param {number} high + * @param {number} zero + * @param {number} one + * @return {number} + */ + countGoodStrings(low, high, zero, one) { + const mod = 1e9 + 7; + const dp = new Array(high + 1).fill(-1); + + const dfs = length => { + if (length > high) return 0; + if (dp[length] !== -1) return dp[length]; + dp[length] = length >= low ? 1 : 0; + dp[length] = (dp[length] + dfs(length + zero)) % mod; + dp[length] = (dp[length] + dfs(length + one)) % mod; + return dp[length]; + }; + + return dfs(0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +> Where $n$ is equal to the given $high$ value. + +--- + +## 3. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def countGoodStrings(self, low: int, high: int, zero: int, one: int) -> int: + dp = { 0 : 1 } + mod = 10**9 + 7 + + for i in range(1, high + 1): + dp[i] = (dp.get(i - one, 0) + dp.get(i - zero, 0)) % mod + + return sum(dp[i] for i in range(low, high + 1)) % mod +``` + +```java +public class Solution { + public int countGoodStrings(int low, int high, int zero, int one) { + int[] dp = new int[high + 1]; + int mod = 1_000_000_007, res = 0; + dp[0] = 1; + + for (int i = 1; i <= high; i++) { + if (i >= zero) dp[i] = (dp[i] + dp[i - zero]) % mod; + if (i >= one) dp[i] = (dp[i] + dp[i - one]) % mod; + if (i >= low) res = (res + dp[i]) % mod; + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int countGoodStrings(int low, int high, int zero, int one) { + vector dp(high + 1); + int mod = 1e9 + 7, res = 0; + dp[0] = 1; + + for (int i = 1; i <= high; i++) { + if (i >= zero) dp[i] = (dp[i] + dp[i - zero]) % mod; + if (i >= one) dp[i] = (dp[i] + dp[i - one]) % mod; + if (i >= low) res = (res + dp[i]) % mod; + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} low + * @param {number} high + * @param {number} zero + * @param {number} one + * @return {number} + */ + countGoodStrings(low, high, zero, one) { + const mod = 1e9 + 7; + const dp = new Int32Array(high + 1); + let res = 0; + dp[0] = 1; + + for (let i = 1; i <= high; i++) { + if (i >= zero) dp[i] = (dp[i] + dp[i - zero]) % mod; + if (i >= one) dp[i] = (dp[i] + dp[i - one]) % mod; + if (i >= low) res = (res + dp[i]) % mod; + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +> Where $n$ is equal to the given $high$ value. \ No newline at end of file diff --git a/articles/integer-break.md b/articles/integer-break.md new file mode 100644 index 000000000..eadd8856d --- /dev/null +++ b/articles/integer-break.md @@ -0,0 +1,661 @@ +## 1. Recursion (Brute Force) + +::tabs-start + +```python +class Solution: + def integerBreak(self, n: int) -> int: + def dfs(num): + if num == 1: + return 1 + res = 0 if num == n else num + for i in range(1, num): + val = dfs(i) * dfs(num - i) + res = max(res, val) + return res + return dfs(n) +``` + +```java +public class Solution { + public int integerBreak(int n) { + return dfs(n, n); + } + + private int dfs(int num, int original) { + if (num == 1) return 1; + + int res = (num == original) ? 0 : num; + for (int i = 1; i < num; i++) { + int val = dfs(i, original) * dfs(num - i, original); + res = Math.max(res, val); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int integerBreak(int n) { + return dfs(n, n); + } + +private: + int dfs(int num, int original) { + if (num == 1) return 1; + + int res = (num == original) ? 0 : num; + for (int i = 1; i < num; i++) { + int val = dfs(i, original) * dfs(num - i, original); + res = max(res, val); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + integerBreak(n) { + const dfs = (num) => { + if (num === 1) return 1; + + let res = (num === n) ? 0 : num; + for (let i = 1; i < num; i++) { + const val = dfs(i) * dfs(num - i); + res = Math.max(res, val); + } + return res; + }; + + return dfs(n, n); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ n)$ +* Space complexity: $O(n)$ for recursion stack. + +--- + +## 2. Recursion + +::tabs-start + +```python +class Solution: + def integerBreak(self, n: int) -> int: + def dfs(num, i): + if min(num, i) == 0: + return 1 + + if i > num: + return dfs(num, num) + + return max(i * dfs(num - i, i), dfs(num, i - 1)) + + return dfs(n, n - 1) +``` + +```java +public class Solution { + public int integerBreak(int n) { + return dfs(n, n - 1); + } + + private 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)); + } +} +``` + +```cpp +class Solution { +public: + int integerBreak(int n) { + return dfs(n, n - 1); + } + +private: + int dfs(int num, int i) { + if (min(num, i) == 0) { + return 1; + } + + if (i > num) { + return dfs(num, num); + } + + return max(i * dfs(num - i, i), dfs(num, i - 1)); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + integerBreak(n) { + const dfs = (num, 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 + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n)$ for recursion stack. + +--- + +## 3. Dynamic Programming (Top-Down) - I + +::tabs-start + +```python +class Solution: + def integerBreak(self, n: int) -> int: + dp = {1: 1} + + def dfs(num): + if num in dp: + return dp[num] + + dp[num] = 0 if num == n else num + for i in range(1, num): + val = dfs(i) * dfs(num - i) + dp[num] = max(dp[num], val) + return dp[num] + + return dfs(n) +``` + +```java +public class Solution { + private Map dp; + + public int integerBreak(int n) { + dp = new HashMap<>(); + dp.put(1, 1); + return dfs(n, n); + } + + private int dfs(int num, int n) { + if (dp.containsKey(num)) { + return dp.get(num); + } + + int res = (num == n) ? 0 : num; + for (int i = 1; i < num; i++) { + int val = dfs(i, n) * dfs(num - i, n); + res = Math.max(res, val); + } + + dp.put(num, res); + return res; + } +} +``` + +```cpp +class Solution { + unordered_map dp; + +public: + int integerBreak(int n) { + dp[1] = 1; + return dfs(n, n); + } + +private: + int dfs(int num, int n) { + if (dp.find(num) != dp.end()) { + return dp[num]; + } + + int res = (num == n) ? 0 : num; + for (int i = 1; i < num; i++) { + int val = dfs(i, n) * dfs(num - i, n); + res = max(res, val); + } + + dp[num] = res; + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + integerBreak(n) { + const dp = new Map(); + dp.set(1, 1); + + const dfs = (num) => { + if (dp.has(num)) { + return dp.get(num); + } + + let res = (num === n) ? 0 : num; + for (let i = 1; i < num; i++) { + const val = dfs(i) * dfs(num - i); + res = Math.max(res, val); + } + + dp.set(num, res); + return res; + }; + + return dfs(n); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n)$ + +--- + +## 4. Dynamic Programming (Top-Down) - II + +::tabs-start + +```python +class Solution: + def integerBreak(self, n: int) -> int: + dp = {} + def dfs(num, i): + if min(num, i) == 0: + return 1 + if (num, i) in dp: + return dp[(num, i)] + if i > num: + dp[(num, i)] = dfs(num, num) + return dp[(num, i)] + + dp[(num, i)] = max(i * dfs(num - i, i), dfs(num, i - 1)) + return dp[(num, i)] + + return dfs(n, n - 1) +``` + +```java +public class Solution { + private int[][] dp; + + public int integerBreak(int n) { + dp = new int[n + 1][n]; + for (int i = 0; i <= n; i++) { + for (int j = 0; j < n; j++) { + dp[i][j] = -1; + } + } + return dfs(n, n - 1); + } + + private int dfs(int num, int i) { + if (Math.min(num, i) == 0) { + return 1; + } + if (dp[num][i] != -1) { + 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]; + } +} +``` + +```cpp +class Solution { + vector> dp; + +public: + int integerBreak(int n) { + dp.assign(n + 1, vector(n, -1)); + return dfs(n, n - 1); + } + +private: + int dfs(int num, int i) { + if (min(num, i) == 0) { + return 1; + } + if (dp[num][i] != -1) { + return dp[num][i]; + } + if (i > num) { + dp[num][i] = dfs(num, num); + return dp[num][i]; + } + dp[num][i] = max(i * dfs(num - i, i), dfs(num, i - 1)); + return dp[num][i]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + integerBreak(n) { + const dp = Array.from({ length: n + 1 }, () => Array(n).fill(-1)); + + const dfs = (num, i) => { + if (Math.min(num, i) === 0) { + return 1; + } + if (dp[num][i] !== -1) { + 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 + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n ^ 2)$ + +--- + +## 5. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def integerBreak(self, n: int) -> int: + dp = [0] * (n + 1) + dp[1] = 1 + + for num in range(2, n + 1): + dp[num] = 0 if num == n else num + for i in range(1, num): + dp[num] = max(dp[num], dp[i] * dp[num - i]) + + return dp[n] +``` + +```java +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]; + } +} +``` + +```cpp +class Solution { +public: + int integerBreak(int n) { + vector dp(n + 1, 0); + 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] = max(dp[num], dp[i] * dp[num - i]); + } + } + + return dp[n]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + integerBreak(n) { + const dp = new Array(n + 1).fill(0); + dp[1] = 1; + + for (let num = 2; num <= n; num++) { + dp[num] = (num === n) ? 0 : num; + for (let i = 1; i < num; i++) { + dp[num] = Math.max(dp[num], dp[i] * dp[num - i]); + } + } + + return dp[n]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n)$ + +--- + +## 6. Math + +::tabs-start + +```python +class Solution: + def integerBreak(self, n: int) -> int: + if n <= 3: + return n - 1 + + res = 1 + while n > 4: + res *= 3 + n -= 3 + return res * n +``` + +```java +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; + } +} +``` + +```cpp +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; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + integerBreak(n) { + if (n <= 3) return n - 1; + + let res = 1; + while (n > 4) { + res *= 3; + n -= 3; + } + return res * n; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ + +--- + +## 7. Math (Optimal) + +::tabs-start + +```python +class Solution: + def integerBreak(self, n: int) -> int: + if n <= 3: + return n - 1 + + res = 3 ** (n // 3) + if n % 3 == 1: + return (res // 3) * 4 + + return res * max(1, (n % 3)) +``` + +```java +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); + } +} +``` + +```cpp +class Solution { +public: + int integerBreak(int n) { + if (n <= 3) { + return n - 1; + } + + int res = pow(3, n / 3); + if (n % 3 == 1) { + return (res / 3) * 4; + } + + return res * max(1, n % 3); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + integerBreak(n) { + if (n <= 3) { + return n - 1; + } + + let res = Math.pow(3, Math.floor(n / 3)); + if (n % 3 === 1) { + return Math.floor(res / 3) * 4; + } + + return res * Math.max(1, n % 3); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(\log n)$ +* Space complexity: $O(1)$ \ No newline at end of file diff --git a/articles/last-stone-weight-ii.md b/articles/last-stone-weight-ii.md new file mode 100644 index 000000000..f902d45d2 --- /dev/null +++ b/articles/last-stone-weight-ii.md @@ -0,0 +1,619 @@ +## 1. Recursion + +::tabs-start + +```python +class Solution: + def lastStoneWeightII(self, stones: List[int]) -> int: + stoneSum = sum(stones) + target = (stoneSum + 1) // 2 + + def dfs(i, total): + if total >= target or i == len(stones): + return abs(total - (stoneSum - total)) + return min(dfs(i + 1, total), dfs(i + 1, total + stones[i])) + + return dfs(0, 0) +``` + +```java +public class Solution { + public int lastStoneWeightII(int[] stones) { + int stoneSum = 0; + for (int stone : stones) { + stoneSum += stone; + } + int target = (stoneSum + 1) / 2; + + return dfs(0, 0, stones, stoneSum, target); + } + + private int dfs(int i, int total, int[] stones, int stoneSum, int target) { + if (total >= target || i == stones.length) { + return Math.abs(total - (stoneSum - total)); + } + return Math.min( + dfs(i + 1, total, stones, stoneSum, target), + dfs(i + 1, total + stones[i], stones, stoneSum, target) + ); + } +} +``` + +```cpp +class Solution { +public: + int lastStoneWeightII(vector& stones) { + int stoneSum = accumulate(stones.begin(), stones.end(), 0); + int target = (stoneSum + 1) / 2; + return dfs(0, 0, stones, stoneSum, target); + } + +private: + int dfs(int i, int total, const vector& stones, int stoneSum, int target) { + if (total >= target || i == stones.size()) { + return abs(total - (stoneSum - total)); + } + return min( + dfs(i + 1, total, stones, stoneSum, target), + dfs(i + 1, total + stones[i], stones, stoneSum, target) + ); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} stones + * @return {number} + */ + lastStoneWeightII(stones) { + const stoneSum = stones.reduce((a, b) => a + b, 0); + const target = Math.ceil(stoneSum / 2); + + const dfs = (i, total) => { + if (total >= target || i === stones.length) { + return Math.abs(total - (stoneSum - total)); + } + return Math.min( + dfs(i + 1, total), + dfs(i + 1, total + stones[i]) + ); + }; + + return dfs(0, 0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(2 ^ n)$ +* Space complexity: $O(min(n, m))$ for recursion stack. + +> Where $n$ is the number of stones and $m$ is the sum of the weights of the stones. + +--- + +## 2. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def lastStoneWeightII(self, stones: List[int]) -> int: + stoneSum = sum(stones) + target = (stoneSum + 1) // 2 + dp = {} + + def dfs(i, total): + if total >= target or i == len(stones): + return abs(total - (stoneSum - total)) + if (i, total) in dp: + return dp[(i, total)] + + dp[(i, total)] = min(dfs(i + 1, total), dfs(i + 1, total + stones[i])) + return dp[(i, total)] + + return dfs(0, 0) +``` + +```java +public class Solution { + private int[][] dp; + + public int lastStoneWeightII(int[] stones) { + int stoneSum = 0; + for (int stone : stones) { + stoneSum += stone; + } + int target = (stoneSum + 1) / 2; + dp = new int[stones.length][target + 1]; + for (int i = 0; i < stones.length; i++) { + for (int j = 0; j <= target; j++) { + dp[i][j] = -1; + } + } + + return dfs(0, 0, stones, stoneSum, target); + } + + private int dfs(int i, int total, int[] stones, int stoneSum, int target) { + if (total >= target || i == stones.length) { + return Math.abs(total - (stoneSum - total)); + } + if (dp[i][total] != -1) { + return dp[i][total]; + } + + dp[i][total] = Math.min( + dfs(i + 1, total, stones, stoneSum, target), + dfs(i + 1, total + stones[i], stones, stoneSum, target) + ); + return dp[i][total]; + } +} +``` + +```cpp +class Solution { +private: + vector> dp; + +public: + int lastStoneWeightII(vector& stones) { + int stoneSum = accumulate(stones.begin(), stones.end(), 0); + int target = (stoneSum + 1) / 2; + dp = vector>(stones.size(), vector(target + 1, -1)); + return dfs(0, 0, stones, stoneSum, target); + } + +private: + int dfs(int i, int total, const vector& stones, int stoneSum, int target) { + if (total >= target || i == stones.size()) { + return abs(total - (stoneSum - total)); + } + if (dp[i][total] != -1) { + return dp[i][total]; + } + + dp[i][total] = min( + dfs(i + 1, total, stones, stoneSum, target), + dfs(i + 1, total + stones[i], stones, stoneSum, target) + ); + return dp[i][total]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} stones + * @return {number} + */ + lastStoneWeightII(stones) { + const stoneSum = stones.reduce((a, b) => a + b, 0); + const target = Math.ceil(stoneSum / 2); + const dp = Array.from({ length: stones.length }, () => Array(target + 1).fill(-1)); + + const dfs = (i, total) => { + if (total >= target || i === stones.length) { + return Math.abs(total - (stoneSum - total)); + } + if (dp[i][total] !== -1) { + return dp[i][total]; + } + + dp[i][total] = Math.min( + dfs(i + 1, total), + dfs(i + 1, total + stones[i]) + ); + return dp[i][total]; + }; + + return dfs(0, 0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * m)$ +* Space complexity: $O(n * m)$ + +> Where $n$ is the number of stones and $m$ is the sum of the weights of the stones. + +--- + +## 3. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def lastStoneWeightII(self, stones: List[int]) -> int: + stoneSum = sum(stones) + target = stoneSum // 2 + n = len(stones) + + dp = [[0] * (target + 1) for _ in range(n + 1)] + + for i in range(1, n + 1): + for t in range(target + 1): + if t >= stones[i - 1]: + dp[i][t] = max(dp[i - 1][t], dp[i - 1][t - stones[i - 1]] + stones[i - 1]) + else: + dp[i][t] = dp[i - 1][t] + + return stoneSum - 2 * dp[n][target] +``` + +```java +public class Solution { + public int lastStoneWeightII(int[] stones) { + int stoneSum = 0; + for (int stone : stones) { + stoneSum += stone; + } + int target = stoneSum / 2; + int n = stones.length; + + int[][] dp = new int[n + 1][target + 1]; + + for (int i = 1; i <= n; i++) { + for (int t = 0; t <= target; t++) { + if (t >= stones[i - 1]) { + dp[i][t] = Math.max(dp[i - 1][t], dp[i - 1][t - stones[i - 1]] + stones[i - 1]); + } else { + dp[i][t] = dp[i - 1][t]; + } + } + } + + return stoneSum - 2 * dp[n][target]; + } +} +``` + +```cpp +class Solution { +public: + int lastStoneWeightII(vector& stones) { + int stoneSum = accumulate(stones.begin(), stones.end(), 0); + int target = stoneSum / 2; + int n = stones.size(); + + vector> dp(n + 1, vector(target + 1, 0)); + + for (int i = 1; i <= n; i++) { + for (int t = 0; t <= target; t++) { + if (t >= stones[i - 1]) { + dp[i][t] = max(dp[i - 1][t], dp[i - 1][t - stones[i - 1]] + stones[i - 1]); + } else { + dp[i][t] = dp[i - 1][t]; + } + } + } + + return stoneSum - 2 * dp[n][target]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} stones + * @return {number} + */ + lastStoneWeightII(stones) { + const stoneSum = stones.reduce((a, b) => a + b, 0); + const target = Math.floor(stoneSum / 2); + const n = stones.length; + + const dp = Array.from({ length: n + 1 }, () => Array(target + 1).fill(0)); + + for (let i = 1; i <= n; i++) { + for (let t = 0; t <= target; t++) { + if (t >= stones[i - 1]) { + dp[i][t] = Math.max(dp[i - 1][t], dp[i - 1][t - stones[i - 1]] + stones[i - 1]); + } else { + dp[i][t] = dp[i - 1][t]; + } + } + } + + return stoneSum - 2 * dp[n][target]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * m)$ +* Space complexity: $O(n * m)$ + +> Where $n$ is the number of stones and $m$ is the sum of the weights of the stones. + +--- + +## 4. Dynamic Programming (Space Optimized) + +::tabs-start + +```python +class Solution: + def lastStoneWeightII(self, stones: List[int]) -> int: + stoneSum = sum(stones) + target = stoneSum // 2 + dp = [0] * (target + 1) + + for stone in stones: + for t in range(target, stone - 1, -1): + dp[t] = max(dp[t], dp[t - stone] + stone) + + return stoneSum - 2 * dp[target] +``` + +```java +public class Solution { + public int lastStoneWeightII(int[] stones) { + int stoneSum = 0; + for (int stone : stones) { + stoneSum += stone; + } + int target = stoneSum / 2; + int[] dp = new int[target + 1]; + + for (int stone : stones) { + for (int t = target; t >= stone; t--) { + dp[t] = Math.max(dp[t], dp[t - stone] + stone); + } + } + + return stoneSum - 2 * dp[target]; + } +} +``` + +```cpp +class Solution { +public: + int lastStoneWeightII(vector& stones) { + int stoneSum = accumulate(stones.begin(), stones.end(), 0); + int target = stoneSum / 2; + vector dp(target + 1, 0); + + for (int stone : stones) { + for (int t = target; t >= stone; t--) { + dp[t] = max(dp[t], dp[t - stone] + stone); + } + } + + return stoneSum - 2 * dp[target]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} stones + * @return {number} + */ + lastStoneWeightII(stones) { + const stoneSum = stones.reduce((a, b) => a + b, 0); + const target = Math.floor(stoneSum / 2); + const dp = new Array(target + 1).fill(0); + + for (const stone of stones) { + for (let t = target; t >= stone; t--) { + dp[t] = Math.max(dp[t], dp[t - stone] + stone); + } + } + + return stoneSum - 2 * dp[target]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * m)$ +* Space complexity: $O(m)$ + +> Where $n$ is the number of stones and $m$ is the sum of the weights of the stones. + +--- + +## 5. Dynamic Programming (Hash Set) + +::tabs-start + +```python +class Solution: + def lastStoneWeightII(self, stones: List[int]) -> int: + stoneSum = sum(stones) + target = stoneSum // 2 + dp = {0} + + for stone in stones: + new_dp = set(dp) + for val in dp: + if val + stone == target: + return stoneSum - 2 * target + if val + stone < target: + new_dp.add(val + stone) + dp = new_dp + + return stoneSum - 2 * max(dp) +``` + +```java +public class Solution { + public int lastStoneWeightII(int[] stones) { + int stoneSum = 0; + for (int stone : stones) { + stoneSum += stone; + } + int target = stoneSum / 2; + + Set dp = new HashSet<>(); + dp.add(0); + + for (int stone : stones) { + Set newDp = new HashSet<>(dp); + for (int val : dp) { + if (val + stone == target) { + return stoneSum - 2 * target; + } + if (val + stone < target) { + newDp.add(val + stone); + } + } + dp = newDp; + } + + int maxVal = 0; + for (int val : dp) { + maxVal = Math.max(maxVal, val); + } + + return stoneSum - 2 * maxVal; + } +} +``` + +```cpp +class Solution { +public: + int lastStoneWeightII(vector& stones) { + int stoneSum = accumulate(stones.begin(), stones.end(), 0); + int target = stoneSum / 2; + + unordered_set dp = {0}; + + for (int& stone : stones) { + unordered_set newDp(dp); + for (int val : dp) { + if (val + stone == target) { + return stoneSum - 2 * target; + } + if (val + stone < target) { + newDp.insert(val + stone); + } + } + dp = newDp; + } + + int maxVal = 0; + for (int val : dp) { + maxVal = max(maxVal, val); + } + + return stoneSum - 2 * maxVal; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} stones + * @return {number} + */ + lastStoneWeightII(stones) { + const stoneSum = stones.reduce((a, b) => a + b, 0); + const target = Math.floor(stoneSum / 2); + + let dp = new Set([0]); + + for (const stone of stones) { + const newDp = new Set(dp); + for (const val of dp) { + if (val + stone === target) { + return stoneSum - 2 * target; + } + if (val + stone < target) { + newDp.add(val + stone); + } + } + dp = newDp; + } + + return stoneSum - 2 * Math.max(...dp); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * m)$ +* Space complexity: $O(m)$ + +> Where $n$ is the number of stones and $m$ is the sum of the weights of the stones. + +--- + +## 6. Dynamic Programming (Bitset) + +::tabs-start + +```python +class Solution: + def lastStoneWeightII(self, stones: List[int]) -> int: + stoneSum = sum(stones) + target = stoneSum // 2 + dp = 1 + + for stone in stones: + dp |= dp << stone + + for t in range(target, -1, -1): + if dp & (1 << t): + return stoneSum - 2 * t +``` + +```cpp +class Solution { +public: + int lastStoneWeightII(vector& stones) { + int stoneSum = accumulate(stones.begin(), stones.end(), 0); + int target = stoneSum / 2; + bitset<3001> dp; + dp[0] = true; + + for (int stone : stones) { + dp |= (dp << stone); + } + + for (int t = target; t >= 0; --t) { + if (dp[t]) { + return stoneSum - 2 * t; + } + } + return 0; + } +}; +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * m)$ +* Space complexity: $O(m)$ + +> Where $n$ is the number of stones and $m$ is the sum of the weights of the stones. \ No newline at end of file diff --git a/articles/longest-palindromic-subsequence.md b/articles/longest-palindromic-subsequence.md new file mode 100644 index 000000000..c216ab542 --- /dev/null +++ b/articles/longest-palindromic-subsequence.md @@ -0,0 +1,557 @@ +## 1. Dynamic Programming (Top Down) + +::tabs-start + +```python +class Solution: + def longestPalindromeSubseq(self, s: str) -> int: + n = len(s) + dp = [[-1] * n for _ in range(n)] + + def dfs(i, j): + if i < 0 or j == n: + return 0 + if dp[i][j] != -1: + return dp[i][j] + + if s[i] == s[j]: + length = 1 if i == j else 2 + dp[i][j] = length + dfs(i - 1, j + 1) + else: + dp[i][j] = max(dfs(i - 1, j), dfs(i, j + 1)) + + return dp[i][j] + + for i in range(n): + dfs(i, i) # odd length + dfs(i, i + 1) # even length + + return max(max(row) for row in dp if row != -1) +``` + +```java +public class Solution { + private int[][] dp; + + public int longestPalindromeSubseq(String s) { + int n = s.length(); + dp = new int[n][n]; + + for (int[] row : dp) { + Arrays.fill(row, -1); + } + + for (int i = 0; i < n; i++) { + dfs(i, i, s); // Odd length + dfs(i, i + 1, s); // Even length + } + + int maxLength = 0; + for (int[] row : dp) { + for (int val : row) { + maxLength = Math.max(maxLength, val); + } + } + + return maxLength; + } + + private int dfs(int i, int j, String s) { + if (i < 0 || j == s.length()) { + return 0; + } + if (dp[i][j] != -1) { + return dp[i][j]; + } + + if (s.charAt(i) == s.charAt(j)) { + int length = (i == j) ? 1 : 2; + dp[i][j] = length + dfs(i - 1, j + 1, s); + } else { + dp[i][j] = Math.max(dfs(i - 1, j, s), dfs(i, j + 1, s)); + } + + return dp[i][j]; + } +} +``` + +```cpp +class Solution { +private: + vector> dp; + +public: + int longestPalindromeSubseq(string s) { + int n = s.size(); + dp.resize(n, vector(n, -1)); + + for (int i = 0; i < n; i++) { + dfs(i, i, s); // Odd length + dfs(i, i + 1, s); // Even length + } + + int maxLength = 0; + for (const auto& row : dp) { + for (int val : row) { + maxLength = max(maxLength, val); + } + } + + return maxLength; + } + +private: + int dfs(int i, int j, const string& s) { + if (i < 0 || j == s.size()) { + return 0; + } + if (dp[i][j] != -1) { + return dp[i][j]; + } + + if (s[i] == s[j]) { + int length = (i == j) ? 1 : 2; + dp[i][j] = length + dfs(i - 1, j + 1, s); + } else { + dp[i][j] = max(dfs(i - 1, j, s), dfs(i, j + 1, s)); + } + + return dp[i][j]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {number} + */ + longestPalindromeSubseq(s) { + const n = s.length; + const dp = Array.from({ length: n }, () => Array(n).fill(-1)); + + const dfs = (i, j) => { + if (i < 0 || j === n) { + return 0; + } + if (dp[i][j] !== -1) { + return dp[i][j]; + } + + if (s[i] === s[j]) { + const length = i === j ? 1 : 2; + dp[i][j] = length + dfs(i - 1, j + 1); + } else { + dp[i][j] = Math.max(dfs(i - 1, j), dfs(i, j + 1)); + } + + return dp[i][j]; + }; + + for (let i = 0; i < n; i++) { + dfs(i, i); // Odd length + dfs(i, i + 1); // Even length + } + + let maxLength = 0; + for (const row of dp) { + for (const val of row) { + maxLength = Math.max(maxLength, val); + } + } + + return maxLength; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n ^ 2)$ + +--- + +## 2. Dynamic Programming (Top-Down Optimized) + +::tabs-start + +```python +class Solution: + def longestPalindromeSubseq(self, s: str) -> int: + cache = {} + + def dfs(i, j): + if i > j: + return 0 + if i == j: + return 1 + if (i, j) in cache: + return cache[(i, j)] + + if s[i] == s[j]: + cache[(i, j)] = dfs(i + 1, j - 1) + 2 + else: + cache[(i, j)] = max(dfs(i + 1, j), dfs(i, j - 1)) + + return cache[(i, j)] + + return dfs(0, len(s) - 1) +``` + +```java +public class Solution { + private int[][] dp; + + public int longestPalindromeSubseq(String s) { + int n = s.length(); + dp = new int[n][n]; + + for (int[] row : dp) { + Arrays.fill(row, -1); + } + + return dfs(0, n - 1, s); + } + + private int dfs(int i, int j, String s) { + if (i > j) { + return 0; + } + if (i == j) { + return 1; + } + if (dp[i][j] != -1) { + return dp[i][j]; + } + + if (s.charAt(i) == s.charAt(j)) { + dp[i][j] = dfs(i + 1, j - 1, s) + 2; + } else { + dp[i][j] = Math.max(dfs(i + 1, j, s), dfs(i, j - 1, s)); + } + + return dp[i][j]; + } +} +``` + +```cpp +class Solution { +private: + vector> dp; + +public: + int longestPalindromeSubseq(string s) { + int n = s.size(); + dp.resize(n, vector(n, -1)); + return dfs(0, n - 1, s); + } + +private: + int dfs(int i, int j, const string& s) { + if (i > j) { + return 0; + } + if (i == j) { + return 1; + } + if (dp[i][j] != -1) { + return dp[i][j]; + } + + if (s[i] == s[j]) { + dp[i][j] = dfs(i + 1, j - 1, s) + 2; + } else { + dp[i][j] = max(dfs(i + 1, j, s), dfs(i, j - 1, s)); + } + + return dp[i][j]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {number} + */ + longestPalindromeSubseq(s) { + const n = s.length; + const dp = Array.from({ length: n }, () => Array(n).fill(-1)); + + const dfs = (i, j) => { + if (i > j) { + return 0; + } + if (i === j) { + return 1; + } + if (dp[i][j] !== -1) { + return dp[i][j]; + } + + if (s[i] === s[j]) { + dp[i][j] = dfs(i + 1, j - 1) + 2; + } else { + dp[i][j] = Math.max(dfs(i + 1, j), dfs(i, j - 1)); + } + + return dp[i][j]; + }; + + return dfs(0, n - 1); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n ^ 2)$ + +--- + +## 3. Dynamic Programming (Using LCS Idea) + +::tabs-start + +```python +class Solution: + def longestPalindromeSubseq(self, s: str) -> int: + return self.longestCommonSubsequence(s, s[::-1]) + + def longestCommonSubsequence(self, s1: str, s2: str) -> int: + N, M = len(s1), len(s2) + dp = [[0] * (M + 1) for _ in range(N + 1)] + + for i in range(N): + for j in range(M): + if s1[i] == s2[j]: + dp[i + 1][j + 1] = 1 + dp[i][j] + else: + dp[i + 1][j + 1] = max(dp[i + 1][j], dp[i][j + 1]) + + return dp[N][M] +``` + +```java +public class Solution { + public int longestPalindromeSubseq(String s) { + return longestCommonSubsequence(s, new StringBuilder(s).reverse().toString()); + } + + public int longestCommonSubsequence(String s1, String s2) { + int N = s1.length(), M = s2.length(); + int[][] dp = new int[N + 1][M + 1]; + + for (int i = 0; i < N; i++) { + for (int j = 0; j < M; j++) { + if (s1.charAt(i) == s2.charAt(j)) { + dp[i + 1][j + 1] = 1 + dp[i][j]; + } else { + dp[i + 1][j + 1] = Math.max(dp[i + 1][j], dp[i][j + 1]); + } + } + } + + return dp[N][M]; + } +} +``` + +```cpp +class Solution { +public: + int longestPalindromeSubseq(string s) { + string reversedS = s; + reverse(reversedS.begin(), reversedS.end()); + return longestCommonSubsequence(s, reversedS); + } + + int longestCommonSubsequence(const string& s1, const string& s2) { + int N = s1.size(), M = s2.size(); + vector> dp(N + 1, vector(M + 1, 0)); + + for (int i = 0; i < N; i++) { + for (int j = 0; j < M; j++) { + if (s1[i] == s2[j]) { + dp[i + 1][j + 1] = 1 + dp[i][j]; + } else { + dp[i + 1][j + 1] = max(dp[i + 1][j], dp[i][j + 1]); + } + } + } + + return dp[N][M]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {number} + */ + longestPalindromeSubseq(s) { + return this.longestCommonSubsequence(s, s.split('').reverse().join('')); + } + + /** + * @param {string} s1 + * @param {string} s2 + * @return {number} + */ + longestCommonSubsequence(s1, s2) { + const N = s1.length, M = s2.length; + const dp = Array.from({ length: N + 1 }, () => Array(M + 1).fill(0)); + + for (let i = 0; i < N; i++) { + for (let j = 0; j < M; j++) { + if (s1[i] === s2[j]) { + dp[i + 1][j + 1] = 1 + dp[i][j]; + } else { + dp[i + 1][j + 1] = Math.max(dp[i + 1][j], dp[i][j + 1]); + } + } + } + + return dp[N][M]; + } +} +``` + +::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 longestPalindromeSubseq(self, s: str) -> int: + n = len(s) + dp = [0] * n + + for i in range(n - 1, -1, -1): + dp[i] = 1 + prev = 0 + for j in range(i + 1, n): + temp = dp[j] + + if s[i] == s[j]: + dp[j] = prev + 2 + else: + dp[j] = max(dp[j], dp[j - 1]) + + prev = temp + + return dp[n - 1] +``` + +```java +public class Solution { + public int longestPalindromeSubseq(String s) { + int n = s.length(); + int[] dp = new int[n]; + + for (int i = n - 1; i >= 0; i--) { + dp[i] = 1; + int prev = 0; + for (int j = i + 1; j < n; j++) { + int temp = dp[j]; + + if (s.charAt(i) == s.charAt(j)) { + dp[j] = prev + 2; + } else { + dp[j] = Math.max(dp[j], dp[j - 1]); + } + prev = temp; + } + } + + return dp[n - 1]; + } +} +``` + +```cpp +class Solution { +public: + int longestPalindromeSubseq(string s) { + int n = s.size(); + vector dp(n, 0); + + for (int i = n - 1; i >= 0; i--) { + dp[i] = 1; + int prev = 0; + for (int j = i + 1; j < n; j++) { + int temp = dp[j]; + + if (s[i] == s[j]) { + dp[j] = prev + 2; + } else { + dp[j] = max(dp[j], dp[j - 1]); + } + + prev = temp; + } + } + + return dp[n - 1]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {number} + */ + longestPalindromeSubseq(s) { + const n = s.length; + const dp = new Array(n).fill(0); + + for (let i = n - 1; i >= 0; i--) { + dp[i] = 1; + let prev = 0; + for (let j = i + 1; j < n; j++) { + const temp = dp[j]; + + if (s[i] === s[j]) { + dp[j] = prev + 2; + } else { + dp[j] = Math.max(dp[j], dp[j - 1]); + } + + prev = temp; + } + } + + return dp[n - 1]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n)$ \ No newline at end of file diff --git a/articles/longest-string-chain.md b/articles/longest-string-chain.md new file mode 100644 index 000000000..b033bad4a --- /dev/null +++ b/articles/longest-string-chain.md @@ -0,0 +1,435 @@ +## 1. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def longestStrChain(self, words: List[str]) -> int: + words.sort(key=lambda w: -len(w)) + word_index = {} # map word to index + for i, w in enumerate(words): + word_index[w] = i + + dp = {} # index of word -> length of longest chain + def dfs(i): + if i in dp: + return dp[i] + res = 1 + for j in range(len(words[i])): + w = words[i] + pred = w[:j] + w[j+1:] + if pred in word_index: + res = max(res, 1 + dfs(word_index[pred])) + dp[i] = res + return res + + for i in range(len(words)): + dfs(i) + return max(dp.values()) +``` + +```java +public class Solution { + public int longestStrChain(String[] words) { + Arrays.sort(words, (a, b) -> Integer.compare(b.length(), a.length())); + Map wordIndex = new HashMap<>(); + for (int i = 0; i < words.length; i++) { + wordIndex.put(words[i], i); + } + + int[] dp = new int[words.length]; + Arrays.fill(dp, -1); + + int maxChain = 1; + for (int i = 0; i < words.length; i++) { + maxChain = Math.max(maxChain, dfs(i, words, wordIndex, dp)); + } + return maxChain; + } + + private int dfs(int i, String[] words, Map wordIndex, int[] dp) { + if (dp[i] != -1) { + return dp[i]; + } + + int res = 1; + String w = words[i]; + for (int j = 0; j < w.length(); j++) { + String pred = w.substring(0, j) + w.substring(j + 1); + if (wordIndex.containsKey(pred)) { + res = Math.max(res, 1 + dfs(wordIndex.get(pred), words, wordIndex, dp)); + } + } + dp[i] = res; + return res; + } +} +``` + +```cpp +class Solution { +public: + int longestStrChain(vector& words) { + sort(words.begin(), words.end(), [](const string& a, const string& b) { + return b.length() < a.length(); + }); + + unordered_map wordIndex; + for (int i = 0; i < words.size(); i++) { + wordIndex[words[i]] = i; + } + + vector dp(words.size(), -1); + int maxChain = 1; + for (int i = 0; i < words.size(); i++) { + maxChain = max(maxChain, dfs(i, words, wordIndex, dp)); + } + return maxChain; + } + +private: + int dfs(int i, vector& words, unordered_map& wordIndex, vector& dp) { + if (dp[i] != -1) { + return dp[i]; + } + + int res = 1; + string w = words[i]; + for (int j = 0; j < w.length(); j++) { + string pred = w.substr(0, j) + w.substr(j + 1); + if (wordIndex.find(pred) != wordIndex.end()) { + res = max(res, 1 + dfs(wordIndex[pred], words, wordIndex, dp)); + } + } + dp[i] = res; + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} words + * @return {number} + */ + longestStrChain(words) { + words.sort((a, b) => b.length - a.length); + const wordIndex = new Map(); + for (let i = 0; i < words.length; i++) { + wordIndex.set(words[i], i); + } + + const dp = new Array(words.length).fill(-1); + + const dfs = (i) => { + if (dp[i] !== -1) { + return dp[i]; + } + + let res = 1; + const w = words[i]; + for (let j = 0; j < w.length; j++) { + const pred = w.slice(0, j) + w.slice(j + 1); + if (wordIndex.has(pred)) { + res = Math.max(res, 1 + dfs(wordIndex.get(pred))); + } + } + dp[i] = res; + return res; + }; + + let maxChain = 1; + for (let i = 0; i < words.length; i++) { + maxChain = Math.max(maxChain, dfs(i)); + } + return maxChain; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * m ^ 2)$ +* Space complexity: $O(n * m)$ + +> Where $n$ is the number of words and $m$ is the average length of each word. + +--- + +## 2. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def longestStrChain(self, words: List[str]) -> int: + def isPred(w1, w2): + i = 0 + for c in w2: + if i == len(w1): + return True + if w1[i] == c: + i += 1 + return i == len(w1) + + words.sort(key=len) + n = len(words) + dp = [1] * n + + for i in range(1, n): + for j in range(i - 1, -1, -1): + if len(words[j]) + 1 < len(words[i]): + break + if len(words[j]) + 1 > len(words[i]) or not isPred(words[j], words[i]): + continue + dp[i] = max(dp[i], 1 + dp[j]) + + return max(dp) +``` + +```java +public class Solution { + public int longestStrChain(String[] words) { + Arrays.sort(words, Comparator.comparingInt(String::length)); + int n = words.length; + int[] dp = new int[n]; + Arrays.fill(dp, 1); + + for (int i = 1; i < n; i++) { + for (int j = i - 1; j >= 0; j--) { + if (words[j].length() + 1 < words[i].length()) { + break; + } + if (words[j].length() + 1 > words[i].length() || !isPred(words[j], words[i])) { + continue; + } + dp[i] = Math.max(dp[i], 1 + dp[j]); + } + } + + int maxChain = 0; + for (int chain : dp) { + maxChain = Math.max(maxChain, chain); + } + return maxChain; + } + + private boolean isPred(String w1, String w2) { + int i = 0; + for (char c : w2.toCharArray()) { + if (i == w1.length()) { + return true; + } + if (w1.charAt(i) == c) { + i++; + } + } + return i == w1.length(); + } +} +``` + +```cpp +class Solution { +public: + int longestStrChain(vector& words) { + sort(words.begin(), words.end(), [](const string& a, const string& b) { + return a.length() < b.length(); + }); + + int n = words.size(); + vector dp(n, 1); + + for (int i = 1; i < n; i++) { + for (int j = i - 1; j >= 0; j--) { + if (words[j].length() + 1 < words[i].length()) { + break; + } + if (words[j].length() + 1 > words[i].length() || !isPred(words[j], words[i])) { + continue; + } + dp[i] = max(dp[i], 1 + dp[j]); + } + } + + return *max_element(dp.begin(), dp.end()); + } + +private: + bool isPred(const string& w1, const string& w2) { + int i = 0; + for (char c : w2) { + if (i == w1.length()) { + return true; + } + if (w1[i] == c) { + i++; + } + } + return i == w1.length(); + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} words + * @return {number} + */ + longestStrChain(words) { + words.sort((a, b) => a.length - b.length); + const n = words.length; + const dp = new Array(n).fill(1); + + const isPred = (w1, w2) => { + let i = 0; + for (const c of w2) { + if (i === w1.length) { + return true; + } + if (w1[i] === c) { + i++; + } + } + return i === w1.length; + }; + + for (let i = 1; i < n; i++) { + for (let j = i - 1; j >= 0; j--) { + if (words[j].length + 1 < words[i].length) { + break; + } + if (words[j].length + 1 > words[i].length || !isPred(words[j], words[i])) { + continue; + } + dp[i] = Math.max(dp[i], 1 + dp[j]); + } + } + + return Math.max(...dp); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2 * m)$ +* Space complexity: $O(n)$ + +> Where $n$ is the number of words and $m$ is the average length of each word. + +--- + +## 3. Dynamic Programming (Bottom-Up Optimized) + +::tabs-start + +```python +class Solution: + def longestStrChain(self, words: List[str]) -> int: + words.sort(key=len) + dp = {} + res = 0 + + for word in words: + dp[word] = 1 + for i in range(len(word)): + pred = word[:i] + word[i+1:] + if pred in dp: + dp[word] = max(dp[word], dp[pred] + 1) + res = max(res, dp[word]) + + return res +``` + +```java +public class Solution { + public int longestStrChain(String[] words) { + Arrays.sort(words, Comparator.comparingInt(String::length)); + Map dp = new HashMap<>(); + int res = 0; + + for (String word : words) { + dp.put(word, 1); + for (int i = 0; i < word.length(); i++) { + String pred = word.substring(0, i) + word.substring(i + 1); + if (dp.containsKey(pred)) { + dp.put(word, Math.max(dp.get(word), dp.get(pred) + 1)); + } + } + res = Math.max(res, dp.get(word)); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int longestStrChain(vector& words) { + sort(words.begin(), words.end(), [](const string& a, const string& b) { + return a.length() < b.length(); + }); + + unordered_map dp; + int res = 0; + + for (const string& word : words) { + dp[word] = 1; + for (int i = 0; i < word.length(); i++) { + string pred = word.substr(0, i) + word.substr(i + 1); + if (dp.find(pred) != dp.end()) { + dp[word] = max(dp[word], dp[pred] + 1); + } + } + res = max(res, dp[word]); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} words + * @return {number} + */ + longestStrChain(words) { + words.sort((a, b) => a.length - b.length); + const dp = new Map(); + let res = 0; + + for (const word of words) { + dp.set(word, 1); + for (let i = 0; i < word.length; i++) { + const pred = word.slice(0, i) + word.slice(i + 1); + if (dp.has(pred)) { + dp.set(word, Math.max(dp.get(word), dp.get(pred) + 1)); + } + } + res = Math.max(res, dp.get(word)); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * m ^ 2)$ +* Space complexity: $O(n * m)$ + +> Where $n$ is the number of words and $m$ is the average length of each word. \ No newline at end of file diff --git a/articles/maximal-square.md b/articles/maximal-square.md new file mode 100644 index 000000000..ab7d2fce0 --- /dev/null +++ b/articles/maximal-square.md @@ -0,0 +1,560 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def maximalSquare(self, matrix: List[List[str]]) -> int: + m, n = len(matrix), len(matrix[0]) + res = 0 + + for r in range(m): + for c in range(n): + if matrix[r][c] == "0": + continue + k = 1 + while True: + if r + k > m or c + k > n: + break + flag = True + + for i in range(r, r + k): + if matrix[i][c + k - 1] == "0": + flag = False + break + for j in range(c, c + k): + if matrix[r + k - 1][j] == "0": + flag = False + break + + if not flag: + break + res = max(res, k * k) + k += 1 + + return res +``` + +```java +public class Solution { + public int maximalSquare(char[][] matrix) { + int m = matrix.length, n = matrix[0].length; + int res = 0; + + for (int r = 0; r < m; r++) { + for (int c = 0; c < n; c++) { + if (matrix[r][c] == '0') { + continue; + } + int k = 1; + while (true) { + if (r + k > m || c + k > n) { + break; + } + boolean flag = true; + + for (int i = r; i < r + k; i++) { + if (matrix[i][c + k - 1] == '0') { + flag = false; + break; + } + } + for (int j = c; j < c + k; j++) { + if (matrix[r + k - 1][j] == '0') { + flag = false; + break; + } + } + + if (!flag) { + break; + } + res = Math.max(res, k * k); + k++; + } + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int maximalSquare(vector>& matrix) { + int m = matrix.size(), n = matrix[0].size(); + int res = 0; + + for (int r = 0; r < m; r++) { + for (int c = 0; c < n; c++) { + if (matrix[r][c] == '0') { + continue; + } + int k = 1; + while (true) { + if (r + k > m || c + k > n) { + break; + } + bool flag = true; + + for (int i = r; i < r + k; i++) { + if (matrix[i][c + k - 1] == '0') { + flag = false; + break; + } + } + for (int j = c; j < c + k; j++) { + if (matrix[r + k - 1][j] == '0') { + flag = false; + break; + } + } + + if (!flag) { + break; + } + res = max(res, k * k); + k++; + } + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {character[][]} matrix + * @return {number} + */ + maximalSquare(matrix) { + const m = matrix.length, n = matrix[0].length; + let res = 0; + + for (let r = 0; r < m; r++) { + for (let c = 0; c < n; c++) { + if (matrix[r][c] === "0") { + continue; + } + let k = 1; + while (true) { + if (r + k > m || c + k > n) { + break; + } + let flag = true; + + for (let i = r; i < r + k; i++) { + if (matrix[i][c + k - 1] === "0") { + flag = false; + break; + } + } + for (let j = c; j < c + k; j++) { + if (matrix[r + k - 1][j] === "0") { + flag = false; + break; + } + } + + if (!flag) { + break; + } + res = Math.max(res, k * k); + k++; + } + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O((m * n) ^ 2)$ +* Space complexity: $O(1)$ + +> Where $m$ is the number of rows and $n$ is the number columns. + +--- + +## 2. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def maximalSquare(self, matrix: List[List[str]]) -> int: + ROWS, COLS = len(matrix), len(matrix[0]) + cache = {} + + def dfs(r, c): + if r >= ROWS or c >= COLS: + return 0 + if (r, c) not in cache: + down = dfs(r + 1, c) + right = dfs(r, c + 1) + diag = dfs(r + 1, c + 1) + cache[(r, c)] = 0 + if matrix[r][c] == "1": + cache[(r, c)] = 1 + min(down, right, diag) + return cache[(r, c)] + + dfs(0, 0) + return max(cache.values()) ** 2 +``` + +```java +public class Solution { + private int[][] dp; + + public int maximalSquare(char[][] matrix) { + int ROWS = matrix.length, COLS = matrix[0].length; + dp = new int[ROWS][COLS]; + for (int i = 0; i < ROWS; i++) { + for (int j = 0; j < COLS; j++) { + dp[i][j] = -1; + } + } + + dfs(0, 0, matrix); + int maxSquare = 0; + for (int i = 0; i < ROWS; i++) { + for (int j = 0; j < COLS; j++) { + maxSquare = Math.max(maxSquare, dp[i][j]); + } + } + return maxSquare * maxSquare; + } + + private int dfs(int r, int c, char[][] matrix) { + if (r >= matrix.length || c >= matrix[0].length) { + return 0; + } + if (dp[r][c] != -1) { + return dp[r][c]; + } + int down = dfs(r + 1, c, matrix); + int right = dfs(r, c + 1, matrix); + int diag = dfs(r + 1, c + 1, matrix); + dp[r][c] = 0; + if (matrix[r][c] == '1') { + dp[r][c] = 1 + Math.min(down, Math.min(right, diag)); + } + return dp[r][c]; + } +} +``` + +```cpp +class Solution { +private: + vector> dp; + +public: + int maximalSquare(vector>& matrix) { + int ROWS = matrix.size(), COLS = matrix[0].size(); + dp = vector>(ROWS, vector(COLS, -1)); + + dfs(0, 0, matrix); + int maxSquare = 0; + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + maxSquare = max(maxSquare, dp[r][c]); + } + } + return maxSquare * maxSquare; + } + + int dfs(int r, int c, vector>& matrix) { + if (r >= matrix.size() || c >= matrix[0].size()) { + return 0; + } + if (dp[r][c] != -1) { + return dp[r][c]; + } + int down = dfs(r + 1, c, matrix); + int right = dfs(r, c + 1, matrix); + int diag = dfs(r + 1, c + 1, matrix); + dp[r][c] = 0; + if (matrix[r][c] == '1') { + dp[r][c] = 1 + min(down, min(right, diag)); + } + return dp[r][c]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {character[][]} matrix + * @return {number} + */ + maximalSquare(matrix) { + const ROWS = matrix.length, COLS = matrix[0].length; + const dp = Array.from({ length: ROWS }, () => Array(COLS).fill(-1)); + + const dfs = (r, c) => { + if (r >= ROWS || c >= COLS) { + return 0; + } + if (dp[r][c] !== -1) { + return dp[r][c]; + } + const down = dfs(r + 1, c); + const right = dfs(r, c + 1); + const diag = dfs(r + 1, c + 1); + dp[r][c] = 0; + if (matrix[r][c] === "1") { + dp[r][c] = 1 + Math.min(down, Math.min(right, diag)); + } + return dp[r][c]; + }; + + dfs(0, 0); + let maxSquare = 0; + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + maxSquare = Math.max(maxSquare, dp[r][c]); + } + } + return maxSquare * maxSquare; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * n)$ +* Space complexity: $O(m * n)$ + +> Where $m$ is the number of rows and $n$ is the number columns. + +--- + +## 3. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def maximalSquare(self, matrix: List[List[str]]) -> int: + m, n = len(matrix), len(matrix[0]) + dp = [[0] * (n + 1) for _ in range(m + 1)] + max_square = 0 + + for r in range(m - 1, -1, -1): + for c in range(n - 1, -1, -1): + if matrix[r][c] == "1": + dp[r][c] = 1 + min(dp[r + 1][c], dp[r][c + 1], dp[r + 1][c + 1]) + max_square = max(max_square, dp[r][c]) + + return max_square * max_square +``` + +```java +public class Solution { + public int maximalSquare(char[][] matrix) { + int m = matrix.length, n = matrix[0].length; + int[][] dp = new int[m + 1][n + 1]; + int maxSquare = 0; + + for (int r = m - 1; r >= 0; r--) { + for (int c = n - 1; c >= 0; c--) { + if (matrix[r][c] == '1') { + dp[r][c] = 1 + Math.min(dp[r + 1][c], Math.min(dp[r][c + 1], dp[r + 1][c + 1])); + maxSquare = Math.max(maxSquare, dp[r][c]); + } + } + } + + return maxSquare * maxSquare; + } +} +``` + +```cpp +class Solution { +public: + int maximalSquare(vector>& matrix) { + int m = matrix.size(), n = matrix[0].size(); + vector> dp(m + 1, vector(n + 1, 0)); + int maxSquare = 0; + + for (int r = m - 1; r >= 0; r--) { + for (int c = n - 1; c >= 0; c--) { + if (matrix[r][c] == '1') { + dp[r][c] = 1 + min({dp[r + 1][c], dp[r][c + 1], dp[r + 1][c + 1]}); + maxSquare = max(maxSquare, dp[r][c]); + } + } + } + + return maxSquare * maxSquare; + } +}; +``` + +```javascript +class Solution { + /** + * @param {character[][]} matrix + * @return {number} + */ + maximalSquare(matrix) { + const m = matrix.length, n = matrix[0].length; + const dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0)); + let maxSquare = 0; + + for (let r = m - 1; r >= 0; r--) { + for (let c = n - 1; c >= 0; c--) { + if (matrix[r][c] === "1") { + dp[r][c] = 1 + Math.min(dp[r + 1][c], dp[r][c + 1], dp[r + 1][c + 1]); + maxSquare = Math.max(maxSquare, dp[r][c]); + } + } + } + + return maxSquare * maxSquare; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * n)$ +* Space complexity: $O(m * n)$ + +> Where $m$ is the number of rows and $n$ is the number columns. + +--- + +## 4. Dynamic Programming (Space Optimized) + +::tabs-start + +```python +class Solution: + def maximalSquare(self, matrix: List[List[str]]) -> int: + m, n = len(matrix), len(matrix[0]) + dp = [0] * (n + 1) + max_square = 0 + + for r in range(m - 1, -1, -1): + prev = 0 + for c in range(n - 1, -1, -1): + temp = dp[c] + if matrix[r][c] == "1": + dp[c] = 1 + min(dp[c], dp[c + 1], prev) + max_square = max(max_square, dp[c]) + else: + dp[c] = 0 + prev = temp + + return max_square * max_square +``` + +```java +public class Solution { + public int maximalSquare(char[][] matrix) { + int m = matrix.length, n = matrix[0].length; + int[] dp = new int[n + 1]; + int maxSquare = 0; + + for (int r = m - 1; r >= 0; r--) { + int prev = 0; + for (int c = n - 1; c >= 0; c--) { + int temp = dp[c]; + if (matrix[r][c] == '1') { + dp[c] = 1 + Math.min(dp[c], Math.min(dp[c + 1], prev)); + maxSquare = Math.max(maxSquare, dp[c]); + } else { + dp[c] = 0; + } + prev = temp; + } + } + + return maxSquare * maxSquare; + } +} +``` + +```cpp +class Solution { +public: + int maximalSquare(vector>& matrix) { + int m = matrix.size(), n = matrix[0].size(); + vector dp(n + 1, 0); + int maxSquare = 0; + + for (int r = m - 1; r >= 0; r--) { + int prev = 0; + for (int c = n - 1; c >= 0; c--) { + int temp = dp[c]; + if (matrix[r][c] == '1') { + dp[c] = 1 + min({dp[c], dp[c + 1], prev}); + maxSquare = max(maxSquare, dp[c]); + } else { + dp[c] = 0; + } + prev = temp; + } + } + + return maxSquare * maxSquare; + } +}; +``` + +```javascript +class Solution { + /** + * @param {character[][]} matrix + * @return {number} + */ + maximalSquare(matrix) { + const m = matrix.length, n = matrix[0].length; + const dp = new Array(n + 1).fill(0); + let maxSquare = 0; + let prev = 0; + + for (let r = m - 1; r >= 0; r--) { + for (let c = n - 1; c >= 0; c--) { + const temp = dp[c]; + if (matrix[r][c] === "1") { + dp[c] = 1 + Math.min(dp[c], dp[c + 1], prev); + maxSquare = Math.max(maxSquare, dp[c]); + } else { + dp[c] = 0; + } + prev = temp; + } + } + + return maxSquare * maxSquare; + } +} +``` + +::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 columns. \ No newline at end of file diff --git a/articles/maximum-alternating-subsequence-sum.md b/articles/maximum-alternating-subsequence-sum.md new file mode 100644 index 000000000..0f296306c --- /dev/null +++ b/articles/maximum-alternating-subsequence-sum.md @@ -0,0 +1,351 @@ +## 1. Recursion + +::tabs-start + +```python +class Solution: + def maxAlternatingSum(self, nums: List[int]) -> int: + def dfs(i, even): + if i == len(nums): + return 0 + total = nums[i] if even else -nums[i] + return max(total + dfs(i + 1, not even), dfs(i + 1, even)) + + return dfs(0, True) +``` + +```java +public class Solution { + public long maxAlternatingSum(int[] nums) { + return dfs(nums, 0, true); + } + + private long dfs(int[] nums, int i, boolean even) { + if (i == nums.length) { + return 0; + } + long total = even ? nums[i] : -nums[i]; + return Math.max(total + dfs(nums, i + 1, !even), dfs(nums, i + 1, even)); + } +} +``` + +```cpp +class Solution { +public: + long long maxAlternatingSum(vector& nums) { + return dfs(nums, 0, true); + } + +private: + long long dfs(vector& nums, int i, bool even) { + if (i == nums.size()) { + return 0; + } + long long total = even ? nums[i] : -nums[i]; + return max(total + dfs(nums, i + 1, !even), dfs(nums, i + 1, even)); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + maxAlternatingSum(nums) { + const dfs = (i, even) => { + if (i === nums.length) { + return 0; + } + + const total = even ? nums[i] : -nums[i]; + return Math.max(total + dfs(i + 1, !even), dfs(i + 1, even)); + }; + + return dfs(0, true); + } +} +``` + +::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 maxAlternatingSum(self, nums: List[int]) -> int: + dp = {} + + def dfs(i, even): + if i == len(nums): + return 0 + if (i, even) in dp: + return dp[(i, even)] + + total = nums[i] if even else -nums[i] + dp[(i, even)] = max(total + dfs(i + 1, not even), dfs(i + 1, even)) + return dp[(i, even)] + + return dfs(0, True) +``` + +```java +public class Solution { + private long dp[][]; + + public long maxAlternatingSum(int[] nums) { + int n = nums.length; + dp = new long[n][2]; + for (int i = 0; i < n; i++) { + dp[i][0] = -1; + dp[i][1] = -1; + } + return dfs(nums, 0, 1); + } + + private long dfs(int[] nums, int i, int even) { + if (i == nums.length) { + return 0; + } + if (dp[i][even] != -1) { + return dp[i][even]; + } + + long total = even == 1 ? nums[i] : -nums[i]; + dp[i][even] = Math.max(total + dfs(nums, i + 1, 1 - even), dfs(nums, i + 1, even)); + return dp[i][even]; + } +} +``` + +```cpp +class Solution { + vector> dp; + +public: + long long maxAlternatingSum(vector& nums) { + dp.assign(nums.size(), vector(2, -1)); + return dfs(nums, 0, true); + } + +private: + long long dfs(vector& nums, int i, bool even) { + if (i == nums.size()) { + return 0; + } + if (dp[i][even] != -1) { + return dp[i][even]; + } + long long total = even ? nums[i] : -nums[i]; + dp[i][even] = max(total + dfs(nums, i + 1, !even), dfs(nums, i + 1, even)); + return dp[i][even]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + maxAlternatingSum(nums) { + const n = nums.length; + const dp = Array.from({ length: n }, () => Array(2).fill(-1)); + + const dfs = (i, even) => { + if (i === n) { + return 0; + } + if (dp[i][even] !== -1) { + return dp[i][even]; + } + + const total = even === 1 ? nums[i] : -nums[i]; + dp[i][even] = Math.max(total + dfs(i + 1, 1 - even), dfs(i + 1, even)); + return dp[i][even]; + }; + + 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 maxAlternatingSum(self, nums: List[int]) -> int: + n = len(nums) + dp = [[0] * 2 for _ in range(n + 1)] # dp[i][0] -> odd, dp[i][1] -> even + + for i in range(n - 1, -1, -1): + dp[i][1] = max(nums[i] + dp[i + 1][0], dp[i + 1][1]) # even + dp[i][0] = max(-nums[i] + dp[i + 1][1], dp[i + 1][0]) # odd + + return dp[0][1] +``` + +```java +public class Solution { + public long maxAlternatingSum(int[] nums) { + int n = nums.length; + long[][] dp = new long[n + 1][2]; // dp[i][0] -> odd, dp[i][1] -> even + + for (int i = n - 1; i >= 0; i--) { + dp[i][1] = Math.max(nums[i] + dp[i + 1][0], dp[i + 1][1]); // even + dp[i][0] = Math.max(-nums[i] + dp[i + 1][1], dp[i + 1][0]); // odd + } + + return dp[0][1]; + } +} +``` + +```cpp +class Solution { +public: + long long maxAlternatingSum(vector& nums) { + int n = nums.size(); + vector> dp(n + 1, vector(2, 0)); // dp[i][0] -> odd, dp[i][1] -> even + + for (int i = n - 1; i >= 0; i--) { + dp[i][1] = max(nums[i] + dp[i + 1][0], dp[i + 1][1]); // even + dp[i][0] = max(-nums[i] + dp[i + 1][1], dp[i + 1][0]); // odd + } + + return dp[0][1]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + maxAlternatingSum(nums) { + const n = nums.length; + const dp = Array.from({ length: n + 1 }, () => [0, 0]); // dp[i][0] -> odd, dp[i][1] -> even + + for (let i = n - 1; i >= 0; i--) { + dp[i][1] = Math.max(nums[i] + dp[i + 1][0], dp[i + 1][1]); // even + dp[i][0] = Math.max(-nums[i] + dp[i + 1][1], dp[i + 1][0]); // odd + } + + return dp[0][1]; // Result starts with even index + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 4. Dynamic Programming (Space Optimized) + +::tabs-start + +```python +class Solution: + def maxAlternatingSum(self, nums: List[int]) -> int: + sumEven = sumOdd = 0 + + for i in range(len(nums) - 1, -1, -1): + tmpEven = max(sumOdd + nums[i], sumEven) + tmpOdd = max(sumEven - nums[i], sumOdd) + sumEven, sumOdd = tmpEven, tmpOdd + + return sumEven +``` + +```java +public class Solution { + public long maxAlternatingSum(int[] nums) { + long sumEven = 0, sumOdd = 0; + + for (int i = nums.length - 1; i >= 0; i--) { + long tmpEven = Math.max(nums[i] + sumOdd, sumEven); + long tmpOdd = Math.max(-nums[i] + sumEven, sumOdd); + sumEven = tmpEven; + sumOdd = tmpOdd; + } + + return sumEven; + } +} +``` + +```cpp +class Solution { +public: + long long maxAlternatingSum(vector& nums) { + long long sumEven = 0, sumOdd = 0; + + for (int i = nums.size() - 1; i >= 0; i--) { + long long tmpEven = max(nums[i] + sumOdd, sumEven); + long long tmpOdd = max(-nums[i] + sumEven, sumOdd); + sumEven = tmpEven; + sumOdd = tmpOdd; + } + + return sumEven; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + maxAlternatingSum(nums) { + let sumEven = 0, sumOdd = 0; + + for (let i = nums.length - 1; i >= 0; i--) { + let tmpEven = Math.max(nums[i] + sumOdd, sumEven); + let tmpOdd = Math.max(-nums[i] + sumEven, sumOdd); + sumEven = tmpEven; + sumOdd = tmpOdd; + } + + return sumEven; + } +} +``` + +::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-path-sum.md b/articles/minimum-path-sum.md new file mode 100644 index 000000000..37968cf67 --- /dev/null +++ b/articles/minimum-path-sum.md @@ -0,0 +1,395 @@ +## 1. Recursion + +::tabs-start + +```python +class Solution: + def minPathSum(self, grid: List[List[int]]) -> int: + def dfs(r, c): + if r == len(grid) - 1 and c == len(grid[0]) - 1: + return grid[r][c] + if r == len(grid) or c == len(grid[0]): + return float('inf') + return grid[r][c] + min(dfs(r + 1, c), dfs(r, c + 1)) + + return dfs(0, 0) +``` + +```java +public class Solution { + public int minPathSum(int[][] grid) { + return dfs(0, 0, grid); + } + + public int dfs(int r, int c, int[][] grid) { + if (r == grid.length - 1 && c == grid[0].length - 1) { + return grid[r][c]; + } + if (r == grid.length || c == grid[0].length) { + return Integer.MAX_VALUE; + } + return grid[r][c] + Math.min(dfs(r + 1, c, grid), dfs(r, c + 1, grid)); + } +} +``` + +```cpp +class Solution { +public: + int minPathSum(vector>& grid) { + return dfs(0, 0, grid); + } + + int dfs(int r, int c, vector>& grid) { + if (r == grid.size() - 1 && c == grid[0].size() - 1) { + return grid[r][c]; + } + if (r == grid.size() || c == grid[0].size()) { + return INT_MAX; + } + return grid[r][c] + min(dfs(r + 1, c, grid), dfs(r, c + 1, grid)); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + minPathSum(grid) { + const dfs = (r, c) => { + if (r === grid.length - 1 && c === grid[0].length - 1) { + return grid[r][c]; + } + if (r === grid.length || c === grid[0].length) { + return Infinity; + } + return grid[r][c] + Math.min(dfs(r + 1, c), dfs(r, c + 1)); + }; + + return dfs(0, 0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(2 ^ {m + n})$ +* Space complexity: $O(m + n)$ for recursion stack. + +> Where $m$ is the number of rows and $n$ is the number of columns. + +--- + +## 2. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def minPathSum(self, grid: List[List[int]]) -> int: + m, n = len(grid), len(grid[0]) + dp = [[-1] * n for _ in range(m)] + + def dfs(r, c): + if r == m - 1 and c == n - 1: + return grid[r][c] + if r == m or c == n: + return float('inf') + if dp[r][c] != -1: + return dp[r][c] + + dp[r][c] = grid[r][c] + min(dfs(r + 1, c), dfs(r, c + 1)) + return dp[r][c] + + return dfs(0, 0) +``` + +```java +public class Solution { + private int[][] dp; + + public int minPathSum(int[][] grid) { + int m = grid.length, n = grid[0].length; + dp = new int[m][n]; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + dp[i][j] = -1; + } + } + return dfs(0, 0, grid); + } + + public int dfs(int r, int c, int[][] grid) { + if (r == grid.length - 1 && c == grid[0].length - 1) { + return grid[r][c]; + } + if (r == grid.length || c == grid[0].length) { + return Integer.MAX_VALUE; + } + if (dp[r][c] != -1) { + return dp[r][c]; + } + + dp[r][c] = grid[r][c] + Math.min(dfs(r + 1, c, grid), dfs(r, c + 1, grid)); + return dp[r][c]; + } +} +``` + +```cpp +class Solution { +private: + vector> dp; + +public: + int minPathSum(vector>& grid) { + int m = grid.size(), n = grid[0].size(); + dp = vector>(m, vector(n, -1)); + return dfs(0, 0, grid); + } + + int dfs(int r, int c, vector>& grid) { + if (r == grid.size() - 1 && c == grid[0].size() - 1) { + return grid[r][c]; + } + if (r == grid.size() || c == grid[0].size()) { + return INT_MAX; + } + if (dp[r][c] != -1) { + return dp[r][c]; + } + + dp[r][c] = grid[r][c] + min(dfs(r + 1, c, grid), dfs(r, c + 1, grid)); + return dp[r][c]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + minPathSum(grid) { + const m = grid.length, n = grid[0].length; + const dp = Array.from({ length: m }, () => Array(n).fill(-1)); + + const dfs = (r, c) => { + if (r === m - 1 && c === n - 1) { + return grid[r][c]; + } + if (r === m || c === n) { + return Infinity; + } + if (dp[r][c] !== -1) { + return dp[r][c]; + } + + dp[r][c] = grid[r][c] + Math.min(dfs(r + 1, c), dfs(r, c + 1)); + return dp[r][c]; + }; + + return dfs(0, 0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * n)$ +* Space complexity: $O(m * n)$ + +> Where $m$ is the number of rows and $n$ is the number of columns. + +--- + +## 3. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def minPathSum(self, grid: List[List[int]]) -> int: + ROWS, COLS = len(grid), len(grid[0]) + dp = [[float("inf")] * (COLS + 1) for _ in range(ROWS + 1)] + dp[ROWS - 1][COLS] = 0 + + for r in range(ROWS - 1, -1, -1): + for c in range(COLS - 1, -1, -1): + dp[r][c] = grid[r][c] + min(dp[r + 1][c], dp[r][c + 1]) + + return dp[0][0] +``` + +```java +public class Solution { + public int minPathSum(int[][] grid) { + int ROWS = grid.length, COLS = grid[0].length; + int[][] dp = new int[ROWS + 1][COLS + 1]; + + for (int r = 0; r <= ROWS; r++) { + for (int c = 0; c <= COLS; c++) { + dp[r][c] = Integer.MAX_VALUE; + } + } + dp[ROWS - 1][COLS] = 0; + + for (int r = ROWS - 1; r >= 0; r--) { + for (int c = COLS - 1; c >= 0; c--) { + dp[r][c] = grid[r][c] + Math.min(dp[r + 1][c], dp[r][c + 1]); + } + } + + return dp[0][0]; + } +} +``` + +```cpp +class Solution { +public: + int minPathSum(vector>& grid) { + int ROWS = grid.size(), COLS = grid[0].size(); + vector> dp(ROWS + 1, vector(COLS + 1, INT_MAX)); + dp[ROWS - 1][COLS] = 0; + + for (int r = ROWS - 1; r >= 0; r--) { + for (int c = COLS - 1; c >= 0; c--) { + dp[r][c] = grid[r][c] + min(dp[r + 1][c], dp[r][c + 1]); + } + } + + return dp[0][0]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + minPathSum(grid) { + const ROWS = grid.length, COLS = grid[0].length; + const dp = Array.from({ length: ROWS + 1 }, () => Array(COLS + 1).fill(Infinity)); + dp[ROWS - 1][COLS] = 0; + + for (let r = ROWS - 1; r >= 0; r--) { + for (let c = COLS - 1; c >= 0; c--) { + dp[r][c] = grid[r][c] + Math.min(dp[r + 1][c], dp[r][c + 1]); + } + } + + return dp[0][0]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * n)$ +* Space complexity: $O(m * n)$ + +> Where $m$ is the number of rows and $n$ is the number of columns. + +--- + +## 4. Dynamic Programming (Space Optimized) + +::tabs-start + +```python +class Solution: + def minPathSum(self, grid: List[List[int]]) -> int: + ROWS, COLS = len(grid), len(grid[0]) + dp = [float("inf")] * (COLS + 1) + dp[COLS - 1] = 0 + + for r in range(ROWS - 1, -1, -1): + for c in range(COLS - 1, -1, -1): + dp[c] = grid[r][c] + min(dp[c], dp[c + 1]) + + return dp[0] +``` + +```java +public class Solution { + public int minPathSum(int[][] grid) { + int ROWS = grid.length, COLS = grid[0].length; + int[] dp = new int[COLS + 1]; + for (int c = 0; c <= COLS; c++) { + dp[c] = Integer.MAX_VALUE; + } + dp[COLS - 1] = 0; + + for (int r = ROWS - 1; r >= 0; r--) { + for (int c = COLS - 1; c >= 0; c--) { + dp[c] = grid[r][c] + Math.min(dp[c], dp[c + 1]); + } + } + + return dp[0]; + } +} +``` + +```cpp +class Solution { +public: + int minPathSum(vector>& grid) { + int ROWS = grid.size(), COLS = grid[0].size(); + vector dp(COLS + 1, INT_MAX); + dp[COLS - 1] = 0; + + for (int r = ROWS - 1; r >= 0; r--) { + for (int c = COLS - 1; c >= 0; c--) { + dp[c] = grid[r][c] + min(dp[c], dp[c + 1]); + } + } + + return dp[0]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + minPathSum(grid) { + const ROWS = grid.length, COLS = grid[0].length; + const dp = new Array(COLS + 1).fill(Infinity); + dp[COLS - 1] = 0; + + for (let r = ROWS - 1; r >= 0; r--) { + for (let c = COLS - 1; c >= 0; c--) { + dp[c] = grid[r][c] + Math.min(dp[c], dp[c + 1]); + } + } + + return dp[0]; + } +} +``` + +::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/n-th-tribonacci-number.md b/articles/n-th-tribonacci-number.md new file mode 100644 index 000000000..bf04e98f7 --- /dev/null +++ b/articles/n-th-tribonacci-number.md @@ -0,0 +1,301 @@ +## 1. Recursion + +::tabs-start + +```python +class Solution: + def tribonacci(self, n: int) -> int: + if n <= 2: + return 1 if n != 0 else 0 + return self.tribonacci(n - 1) + self.tribonacci(n - 2) + self.tribonacci(n - 3) +``` + +```java +public class Solution { + public int tribonacci(int n) { + if (n <= 2) { + return n == 0 ? 0 : 1; + } + return tribonacci(n - 1) + tribonacci(n - 2) + tribonacci(n - 3); + } +} +``` + +```cpp +class Solution { +public: + int tribonacci(int n) { + if (n <= 2) { + return n == 0 ? 0 : 1; + } + return tribonacci(n - 1) + tribonacci(n - 2) + tribonacci(n - 3); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + tribonacci(n) { + if (n <= 2) { + return n === 0 ? 0 : 1; + } + return this.tribonacci(n - 1) + this.tribonacci(n - 2) + this.tribonacci(n - 3); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(3 ^ n)$ +* Space complexity: $O(n)$ + +--- + +## 2. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def __init__(self): + self.dp = {} + + def tribonacci(self, n: int) -> int: + if n <= 2: + return 1 if n != 0 else 0 + if n in self.dp: + return self.dp[n] + + self.dp[n] = self.tribonacci(n - 1) + self.tribonacci(n - 2) + self.tribonacci(n - 3) + return self.dp[n] +``` + +```java +public class Solution { + private HashMap dp = new HashMap<>(); + + public int tribonacci(int n) { + if (n <= 2) { + return n == 0 ? 0 : 1; + } + if (dp.containsKey(n)) { + return dp.get(n); + } + + dp.put(n, tribonacci(n - 1) + tribonacci(n - 2) + tribonacci(n - 3)); + return dp.get(n); + } +} +``` + +```cpp +class Solution { + unordered_map dp; + +public: + int tribonacci(int n) { + if (n <= 2) { + return n == 0 ? 0 : 1; + } + if (dp.count(n)) return dp[n]; + + dp[n] = tribonacci(n - 1) + tribonacci(n - 2) + tribonacci(n - 3); + return dp[n]; + } +}; +``` + +```javascript +class Solution { + /** + * @constructor + */ + constructor() { + this.dp = new Map(); + } + + /** + * @param {number} n + * @return {number} + */ + tribonacci(n) { + if (n <= 2) { + return n === 0 ? 0 : 1; + } + if (this.dp.has(n)) { + return this.dp.get(n); + } + const result = this.tribonacci(n - 1) + this.tribonacci(n - 2) + this.tribonacci(n - 3); + this.dp.set(n, result); + return result; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 3. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def tribonacci(self, n: int) -> int: + if n <= 2: + return 1 if n != 0 else 0 + + dp = [0] * (n + 1) + dp[1] = dp[2] = 1 + for i in range(3, n + 1): + dp[i] = dp[i - 1] + dp[i - 2] + dp[i - 3] + return dp[n] +``` + +```java +public class Solution { + public int tribonacci(int n) { + if (n <= 2) { + return n == 0 ? 0 : 1; + } + + int[] dp = new int[n + 1]; + 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]; + } +} +``` + +```cpp +class Solution { +public: + int tribonacci(int n) { + if (n <= 2) { + return n == 0 ? 0 : 1; + } + + vector dp(n + 1, 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]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + tribonacci(n) { + if (n <= 2) { + return n === 0 ? 0 : 1; + } + + const dp = new Array(n + 1).fill(0); + dp[1] = dp[2] = 1; + for (let i = 3; i <= n; i++) { + dp[i] = dp[i - 1] + dp[i - 2] + dp[i - 3]; + } + return dp[n]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 4. Dynamic Programming (Space Optimized) + +::tabs-start + +```python +class Solution: + def tribonacci(self, n: int) -> int: + t = [0, 1, 1] + + if n < 3: + return t[n] + + for i in range(3, n + 1): + t[i % 3] = sum(t) + return t[n % 3] +``` + +```java +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]; + } +} +``` + +```cpp +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]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + tribonacci(n) { + const t = [0, 1, 1] + if (n < 3) return t[n]; + + for (let i = 3; i <= n; ++i) { + t[i % 3] = t[0] + t[1] + t[2]; + } + return t[n % 3]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ \ No newline at end of file diff --git a/articles/new-21-game.md b/articles/new-21-game.md new file mode 100644 index 000000000..e65fcd1da --- /dev/null +++ b/articles/new-21-game.md @@ -0,0 +1,485 @@ +## 1. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def new21Game(self, n: int, k: int, maxPts: int) -> float: + cache = {} + + def dfs(score): + if score >= k: + return 1 if score <= n else 0 + if score in cache: + return cache[score] + + prob = 0 + for i in range(1, maxPts + 1): + prob += dfs(score + i) + + cache[score] = prob / maxPts + return cache[score] + + return dfs(0) +``` + +```java +public class Solution { + private double[] dp; + + public double new21Game(int n, int k, int maxPts) { + dp = new double[k]; + for (int i = 0; i < dp.length; i++) dp[i] = -1.0; + return dfs(0, n, k, maxPts); + } + + private double dfs(int score, int n, int k, int maxPts) { + if (score >= k) { + return score <= n ? 1.0 : 0.0; + } + if (dp[score] != -1.0) { + return dp[score]; + } + + double prob = 0; + for (int i = 1; i <= maxPts; i++) { + prob += dfs(score + i, n, k, maxPts); + } + + dp[score] = prob / maxPts; + return dp[score]; + } +} +``` + +```cpp +class Solution { +private: + vector dp; + +public: + double new21Game(int n, int k, int maxPts) { + dp.resize(k, -1.0); + return dfs(0, n, k, maxPts); + } + +private: + double dfs(int score, int n, int k, int maxPts) { + if (score >= k) { + return score <= n ? 1.0 : 0.0; + } + if (dp[score] != -1.0) { + return dp[score]; + } + + double prob = 0; + for (int i = 1; i <= maxPts; i++) { + prob += dfs(score + i, n, k, maxPts); + } + + dp[score] = prob / maxPts; + return dp[score]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number} k + * @param {number} maxPts + * @return {number} + */ + new21Game(n, k, maxPts) { + const dp = new Array(k).fill(-1); + + const dfs = (score) => { + if (score >= k) { + return score <= n ? 1 : 0; + } + if (dp[score] !== -1) { + return dp[score]; + } + + let prob = 0; + for (let i = 1; i <= maxPts; i++) { + prob += dfs(score + i); + } + + dp[score] = prob / maxPts; + return dp[score]; + }; + + return dfs(0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(k * m)$ +* Space complexity: $O(k)$ + +> Where $k$ is the threshold score, $m$ is the maximum points per draw and $n$ is the upper bound on score. + +--- + +## 2. Dynamic Programming (Top-Down Optimized) + +::tabs-start + +```python +class Solution: + def new21Game(self, n: int, k: int, maxPts: int) -> float: + cache = {} + + def dfs(score): + if score == k - 1: + return min(n - k + 1, maxPts) / maxPts + if score > n: + return 0 + if score >= k: + return 1.0 + + if score in cache: + return cache[score] + + cache[score] = dfs(score + 1) + cache[score] -= (dfs(score + 1 + maxPts) - dfs(score + 1)) / maxPts + return cache[score] + + return dfs(0) +``` + +```java +public class Solution { + private double[] dp; + + public double new21Game(int n, int k, int maxPts) { + dp = new double[k + maxPts]; + for (int i = 0; i < dp.length; i++) dp[i] = -1.0; + return dfs(0, n, k, maxPts); + } + + private double dfs(int score, int n, int k, int maxPts) { + if (score == k - 1) { + return Math.min(n - k + 1, maxPts) / (double) maxPts; + } + if (score > n) { + return 0.0; + } + if (score >= k) { + return 1.0; + } + if (dp[score] != -1.0) { + return dp[score]; + } + + dp[score] = dfs(score + 1, n, k, maxPts); + dp[score] -= (dfs(score + 1 + maxPts, n, k, maxPts) - dfs(score + 1, n, k, maxPts)) / maxPts; + return dp[score]; + } +} +``` + +```cpp +class Solution { +private: + vector dp; + +public: + double new21Game(int n, int k, int maxPts) { + dp.resize(k + maxPts, -1.0); + return dfs(0, n, k, maxPts); + } + +private: + double dfs(int score, int n, int k, int maxPts) { + if (score == k - 1) { + return min(n - k + 1, maxPts) / (double)maxPts; + } + if (score > n) { + return 0.0; + } + if (score >= k) { + return 1.0; + } + if (dp[score] != -1.0) { + return dp[score]; + } + + dp[score] = dfs(score + 1, n, k, maxPts); + dp[score] -= (dfs(score + 1 + maxPts, n, k, maxPts) - dfs(score + 1, n, k, maxPts)) / maxPts; + return dp[score]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number} k + * @param {number} maxPts + * @return {number} + */ + new21Game(n, k, maxPts) { + const dp = new Array(k + maxPts).fill(-1); + + const dfs = (score) => { + if (score === k - 1) { + return Math.min(n - k + 1, maxPts) / maxPts; + } + if (score > n) { + return 0; + } + if (score >= k) { + return 1.0; + } + if (dp[score] !== -1) { + return dp[score]; + } + + dp[score] = dfs(score + 1); + dp[score] -= (dfs(score + 1 + maxPts) - dfs(score + 1)) / maxPts; + return dp[score]; + }; + + return dfs(0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(k + m)$ +* Space complexity: $O(n)$ + +> Where $k$ is the threshold score, $m$ is the maximum points per draw and $n$ is the upper bound on score. + +--- + +## 3. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def new21Game(self, n: int, k: int, maxPts: int) -> float: + dp = [0] * (n + 1) + dp[0] = 1.0 + + for score in range(1, n + 1): + for draw in range(1, maxPts + 1): + if score - draw >= 0 and score - draw < k: + dp[score] += dp[score - draw] / maxPts + + return sum(dp[k:n + 1]) +``` + +```java +public class Solution { + public double new21Game(int n, int k, int maxPts) { + double[] dp = new double[n + 1]; + dp[0] = 1.0; + + for (int score = 1; score <= n; score++) { + for (int draw = 1; draw <= maxPts; draw++) { + if (score - draw >= 0 && score - draw < k) { + dp[score] += dp[score - draw] / maxPts; + } + } + } + + double result = 0.0; + for (int i = k; i <= n; i++) { + result += dp[i]; + } + + return result; + } +} +``` + +```cpp +class Solution { +public: + double new21Game(int n, int k, int maxPts) { + vector dp(n + 1, 0.0); + dp[0] = 1.0; + + for (int score = 1; score <= n; score++) { + for (int draw = 1; draw <= maxPts; draw++) { + if (score - draw >= 0 && score - draw < k) { + dp[score] += dp[score - draw] / maxPts; + } + } + } + + double result = 0.0; + for (int i = k; i <= n; i++) { + result += dp[i]; + } + + return result; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number} k + * @param {number} maxPts + * @return {number} + */ + new21Game(n, k, maxPts) { + const dp = new Array(n + 1).fill(0); + dp[0] = 1.0; + + for (let score = 1; score <= n; score++) { + for (let draw = 1; draw <= maxPts; draw++) { + if (score - draw >= 0 && score - draw < k) { + dp[score] += dp[score - draw] / maxPts; + } + } + } + + let result = 0.0; + for (let i = k; i <= n; i++) { + result += dp[i]; + } + + return result; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * m)$ +* Space complexity: $O(n)$ + +> Where $k$ is the threshold score, $m$ is the maximum points per draw and $n$ is the upper bound on score. + +--- + +## 4. Dynamic Programming (Sliding Window) + +::tabs-start + +```python +class Solution: + def new21Game(self, n: int, k: int, maxPts: int) -> float: + if k == 0: + return 1.0 + + windowSum = 0 + for i in range(k, k + maxPts): + windowSum += 1 if i <= n else 0 + + dp = {} + for i in range(k - 1, -1, -1): + dp[i] = windowSum / maxPts + remove = 0 + if i + maxPts <= n: + remove = dp.get(i + maxPts, 1) + windowSum += dp[i] - remove + return dp[0] +``` + +```java +class Solution { + public double new21Game(int n, int k, int maxPts) { + if (k == 0) { + return 1.0; + } + double windowSum = 0.0; + for (int i = k; i < k + maxPts; i++) { + windowSum += (i <= n) ? 1.0 : 0.0; + } + HashMap dp = new HashMap<>(); + for (int i = k - 1; i >= 0; i--) { + dp.put(i, windowSum / maxPts); + double remove = 0.0; + if (i + maxPts <= n) { + remove = dp.getOrDefault(i + maxPts, 1.0); + } + windowSum += dp.get(i) - remove; + } + return dp.get(0); + } +} +``` + +```cpp +class Solution { +public: + double new21Game(int n, int k, int maxPts) { + if (k == 0) { + return 1.0; + } + double windowSum = 0.0; + for (int i = k; i < k + maxPts; i++) { + windowSum += (i <= n) ? 1.0 : 0.0; + } + unordered_map dp; + for (int i = k - 1; i >= 0; i--) { + dp[i] = windowSum / maxPts; + double remove = 0.0; + if (i + maxPts <= n) { + remove = (dp.find(i + maxPts) != dp.end()) ? dp[i + maxPts] : 1.0; + } + windowSum += dp[i] - remove; + } + return dp[0]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number} k + * @param {number} maxPts + * @return {number} + */ + new21Game(n, k, maxPts) { + if (k === 0) { + return 1.0; + } + let windowSum = 0.0; + for (let i = k; i < k + maxPts; i++) { + windowSum += (i <= n) ? 1.0 : 0.0; + } + let dp = {}; + for (let i = k - 1; i >= 0; i--) { + dp[i] = windowSum / maxPts; + let remove = 0.0; + if (i + maxPts <= n) { + remove = (dp[i + maxPts] !== undefined) ? dp[i + maxPts] : 1.0; + } + windowSum += dp[i] - remove; + } + return dp[0]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(k + m)$ +* Space complexity: $O(n)$ + +> Where $k$ is the threshold score, $m$ is the maximum points per draw and $n$ is the upper bound on score. \ No newline at end of file diff --git a/articles/number-of-longest-increasing-subsequence.md b/articles/number-of-longest-increasing-subsequence.md new file mode 100644 index 000000000..f11ef6599 --- /dev/null +++ b/articles/number-of-longest-increasing-subsequence.md @@ -0,0 +1,699 @@ +## 1. Recursion + +::tabs-start + +```python +class Solution: + def findNumberOfLIS(self, nums: List[int]) -> int: + LIS = 0 + res = 0 + + def dfs(i, length): + nonlocal LIS, res + if LIS < length: + LIS = length + res = 1 + elif LIS == length: + res += 1 + + for j in range(i + 1, len(nums)): + if nums[j] <= nums[i]: + continue + dfs(j, length + 1) + + for i in range(len(nums)): + dfs(i, 1) + return res +``` + +```java +public class Solution { + private int LIS = 0; + private int res = 0; + + public int findNumberOfLIS(int[] nums) { + for (int i = 0; i < nums.length; i++) { + dfs(nums, i, 1); + } + return res; + } + + private void dfs(int[] nums, int i, int length) { + if (LIS < length) { + LIS = length; + res = 1; + } else if (LIS == length) { + res++; + } + + for (int j = i + 1; j < nums.length; j++) { + if (nums[j] <= nums[i]) { + continue; + } + dfs(nums, j, length + 1); + } + } +} +``` + +```cpp +class Solution { + int LIS = 0; + int res = 0; + + void dfs(vector& nums, int i, int length) { + if (LIS < length) { + LIS = length; + res = 1; + } else if (LIS == length) { + res++; + } + + for (int j = i + 1; j < nums.size(); j++) { + if (nums[j] <= nums[i]) { + continue; + } + dfs(nums, j, length + 1); + } + } + +public: + int findNumberOfLIS(vector& nums) { + for (int i = 0; i < nums.size(); i++) { + dfs(nums, i, 1); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + findNumberOfLIS(nums) { + let LIS = 0; + let res = 0; + + const dfs = (i, length) => { + if (LIS < length) { + LIS = length; + res = 1; + } else if (LIS === length) { + res++; + } + + for (let j = i + 1; j < nums.length; j++) { + if (nums[j] <= nums[i]) continue; + dfs(j, length + 1); + } + }; + + for (let i = 0; i < nums.length; i++) { + dfs(i, 1); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ n)$ +* Space complexity: $O(n)$ + +--- + +## 2. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def findNumberOfLIS(self, nums: List[int]) -> int: + dp = {} + + def dfs(i): + if i in dp: + return + + maxLen = maxCnt = 1 + for j in range(i + 1, len(nums)): + if nums[j] > nums[i]: + dfs(j) + length, count = dp[j] + if 1 + length > maxLen: + maxLen = length + 1 + maxCnt = count + elif 1 + length == maxLen: + maxCnt += count + dp[i] = (maxLen, maxCnt) + + lenLIS = res = 0 + for i in range(len(nums)): + dfs(i) + maxLen, maxCnt = dp[i] + if maxLen > lenLIS: + lenLIS = maxLen + res = maxCnt + elif maxLen == lenLIS: + res += maxCnt + + return res +``` + +```java +public class Solution { + private int[][] dp; + + public int findNumberOfLIS(int[] nums) { + int n = nums.length; + dp = new int[n][2]; // dp[i][0] = maxLen, dp[i][1] = maxCnt + + for (int i = 0; i < n; i++) { + dp[i][0] = dp[i][1] = -1; + } + + int lenLIS = 0, res = 0; + for (int i = 0; i < n; i++) { + dfs(nums, i); + int[] result = dp[i]; + if (result[0] > lenLIS) { + lenLIS = result[0]; + res = result[1]; + } else if (result[0] == lenLIS) { + res += result[1]; + } + } + return res; + } + + private void dfs(int[] nums, int i) { + if (dp[i][0] != -1) return; + + int maxLen = 1, maxCnt = 1; + for (int j = i + 1; j < nums.length; j++) { + if (nums[j] > nums[i]) { + dfs(nums, j); + int[] next = dp[j]; + if (1 + next[0] > maxLen) { + maxLen = 1 + next[0]; + maxCnt = next[1]; + } else if (1 + next[0] == maxLen) { + maxCnt += next[1]; + } + } + } + + dp[i] = new int[]{maxLen, maxCnt}; + } +} +``` + +```cpp +class Solution { +private: + vector> dp; + + void dfs(vector& nums, int i) { + if (dp[i][0] != -1) return; + + int maxLen = 1, maxCnt = 1; + for (int j = i + 1; j < nums.size(); j++) { + if (nums[j] > nums[i]) { + dfs(nums, j); + int length = dp[j][0]; + int count = dp[j][1]; + if (1 + length > maxLen) { + maxLen = 1 + length; + maxCnt = count; + } else if (1 + length == maxLen) { + maxCnt += count; + } + } + } + dp[i] = {maxLen, maxCnt}; + } + +public: + int findNumberOfLIS(vector& nums) { + int n = nums.size(); + dp.assign(n, vector(2, -1)); + + int lenLIS = 0, res = 0; + for (int i = 0; i < n; i++) { + dfs(nums, i); + int maxLen = dp[i][0]; + int maxCnt = dp[i][1]; + if (maxLen > lenLIS) { + lenLIS = maxLen; + res = maxCnt; + } else if (maxLen == lenLIS) { + res += maxCnt; + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + findNumberOfLIS(nums) { + const dp = new Map(); + + const dfs = (i) => { + if (dp.has(i)) return; + + let maxLen = 1, maxCnt = 1; + for (let j = i + 1; j < nums.length; j++) { + if (nums[j] > nums[i]) { + dfs(j); + const [length, count] = dp.get(j); + if (1 + length > maxLen) { + maxLen = 1 + length; + maxCnt = count; + } else if (1 + length === maxLen) { + maxCnt += count; + } + } + } + dp.set(i, [maxLen, maxCnt]); + }; + + let lenLIS = 0, res = 0; + for (let i = 0; i < nums.length; i++) { + dfs(i); + const [maxLen, maxCnt] = dp.get(i); + if (maxLen > lenLIS) { + lenLIS = maxLen; + res = maxCnt; + } else if (maxLen === lenLIS) { + res += maxCnt; + } + } + 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 findNumberOfLIS(self, nums: List[int]) -> int: + n = len(nums) + dp = [[0, 0] for _ in range(n)] + lenLIS, res = 0, 0 + + for i in range(n - 1, -1, -1): + maxLen, maxCnt = 1, 1 + for j in range(i + 1, n): + if nums[j] > nums[i]: + length, count = dp[j] + if length + 1 > maxLen: + maxLen, maxCnt = length + 1, count + elif length + 1 == maxLen: + maxCnt += count + + if maxLen > lenLIS: + lenLIS, res = maxLen, maxCnt + elif maxLen == lenLIS: + res += maxCnt + dp[i] = [maxLen, maxCnt] + + return res +``` + +```java +public class Solution { + public int findNumberOfLIS(int[] nums) { + int n = nums.length; + int[][] dp = new int[n][2]; + int lenLIS = 0, res = 0; + + for (int i = n - 1; i >= 0; i--) { + int maxLen = 1, maxCnt = 1; + for (int j = i + 1; j < n; j++) { + if (nums[j] > nums[i]) { + int length = dp[j][0]; + int count = dp[j][1]; + if (length + 1 > maxLen) { + maxLen = length + 1; + maxCnt = count; + } else if (length + 1 == maxLen) { + maxCnt += count; + } + } + } + + if (maxLen > lenLIS) { + lenLIS = maxLen; + res = maxCnt; + } else if (maxLen == lenLIS) { + res += maxCnt; + } + dp[i][0] = maxLen; + dp[i][1] = maxCnt; + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int findNumberOfLIS(vector& nums) { + int n = nums.size(); + vector> dp(n, vector(2, 0)); + int lenLIS = 0, res = 0; + + for (int i = n - 1; i >= 0; i--) { + int maxLen = 1, maxCnt = 1; + for (int j = i + 1; j < n; j++) { + if (nums[j] > nums[i]) { + int length = dp[j][0]; + int count = dp[j][1]; + if (length + 1 > maxLen) { + maxLen = length + 1; + maxCnt = count; + } else if (length + 1 == maxLen) { + maxCnt += count; + } + } + } + + if (maxLen > lenLIS) { + lenLIS = maxLen; + res = maxCnt; + } else if (maxLen == lenLIS) { + res += maxCnt; + } + dp[i][0] = maxLen; + dp[i][1] = maxCnt; + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + findNumberOfLIS(nums) { + const n = nums.length; + const dp = Array.from({ length: n }, () => [0, 0]); + let lenLIS = 0, res = 0; + + for (let i = n - 1; i >= 0; i--) { + let maxLen = 1, maxCnt = 1; + for (let j = i + 1; j < n; j++) { + if (nums[j] > nums[i]) { + const [length, count] = dp[j]; + if (length + 1 > maxLen) { + maxLen = length + 1; + maxCnt = count; + } else if (length + 1 === maxLen) { + maxCnt += count; + } + } + } + + if (maxLen > lenLIS) { + lenLIS = maxLen; + res = maxCnt; + } else if (maxLen === lenLIS) { + res += maxCnt; + } + dp[i] = [maxLen, maxCnt]; + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n)$ + +--- + +## 4. Dynamic Programming (Binary Search + Prefix Sum) + +::tabs-start + +```python +class Solution: + def findNumberOfLIS(self, nums: List[int]) -> int: + n = len(nums) + dp = [[[0, 0], [nums[0], 1]]] + + def bs1(num): + l, r = 0, len(dp) - 1 + j = len(dp) - 1 + while l <= r: + mid = (l + r) // 2 + if dp[mid][-1][0] < num: + l = mid + 1 + else: + j = mid + r = mid - 1 + return j + + def bs2(i, num): + if i < 0: + return 1 + l, r = 1, len(dp[i]) - 1 + j = 0 + while l <= r: + mid = (l + r) // 2 + if dp[i][mid][0] >= num: + j = mid + l = mid + 1 + else: + r = mid - 1 + return dp[i][-1][1] - dp[i][j][1] + + LIS = 1 + for i in range(1, n): + num = nums[i] + if num > dp[-1][-1][0]: + count = bs2(LIS - 1, num) + dp.append([[0, 0], [num, count]]) + LIS += 1 + else: + j = bs1(num) + count = bs2(j - 1, num) + dp[j].append([num, dp[j][-1][1] + count]) + + return dp[-1][-1][1] +``` + +```java +public class Solution { + public int findNumberOfLIS(int[] nums) { + int n = nums.length; + List> dp = new ArrayList<>(); + List first = new ArrayList<>(); + first.add(new int[]{0, 0}); + first.add(new int[]{nums[0], 1}); + dp.add(first); + + int LIS = 1; + + for (int i = 1; i < n; i++) { + int num = nums[i]; + if (num > dp.get(dp.size() - 1).get(dp.get(dp.size() - 1).size() - 1)[0]) { + int count = bs2(dp, LIS - 1, num); + List newList = new ArrayList<>(); + newList.add(new int[]{0, 0}); + newList.add(new int[]{num, count}); + dp.add(newList); + LIS++; + } else { + int j = bs1(dp, num); + int count = bs2(dp, j - 1, num); + List list = dp.get(j); + int[] last = list.get(list.size() - 1); + list.add(new int[]{num, last[1] + count}); + } + } + + return dp.get(dp.size() - 1).get(dp.get(dp.size() - 1).size() - 1)[1]; + } + + private int bs1(List> dp, int num) { + int l = 0, r = dp.size() - 1, j = dp.size() - 1; + while (l <= r) { + int mid = (l + r) / 2; + if (dp.get(mid).get(dp.get(mid).size() - 1)[0] < num) { + l = mid + 1; + } else { + j = mid; + r = mid - 1; + } + } + return j; + } + + private int bs2(List> dp, int i, int num) { + if (i < 0) return 1; + int l = 1, r = dp.get(i).size() - 1, j = 0; + while (l <= r) { + int mid = (l + r) / 2; + if (dp.get(i).get(mid)[0] >= num) { + j = mid; + l = mid + 1; + } else { + r = mid - 1; + } + } + return dp.get(i).get(dp.get(i).size() - 1)[1] - dp.get(i).get(j)[1]; + } +} +``` + +```cpp +class Solution { +public: + int findNumberOfLIS(vector& nums) { + vector>> dp = {{{0, 0}, {nums[0], 1}}}; + int LIS = 1; + + for (int i = 1; i < nums.size(); i++) { + int num = nums[i]; + if (num > dp.back().back().first) { + int count = bs2(dp, LIS - 1, num); + dp.push_back({{0, 0}, {num, count}}); + LIS++; + } else { + int j = bs1(dp, num); + int count = bs2(dp, j - 1, num); + dp[j].push_back({num, dp[j].back().second + count}); + } + } + + return dp.back().back().second; + } + +private: + int bs1(vector>>& dp, int num) { + int l = 0, r = dp.size() - 1, j = dp.size() - 1; + while (l <= r) { + int mid = (l + r) / 2; + if (dp[mid].back().first < num) { + l = mid + 1; + } else { + j = mid; + r = mid - 1; + } + } + return j; + } + + int bs2(vector>>& dp, int i, int num) { + if (i < 0) return 1; + int l = 1, r = dp[i].size() - 1, j = 0; + while (l <= r) { + int mid = (l + r) / 2; + if (dp[i][mid].first >= num) { + j = mid; + l = mid + 1; + } else { + r = mid - 1; + } + } + return dp[i].back().second - dp[i][j].second; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + findNumberOfLIS(nums) { + const dp = [[[0, 0], [nums[0], 1]]]; + let LIS = 1; + + const bs1 = (num) => { + let l = 0, r = dp.length - 1, j = dp.length - 1; + while (l <= r) { + const mid = Math.floor((l + r) / 2); + if (dp[mid][dp[mid].length - 1][0] < num) { + l = mid + 1; + } else { + j = mid; + r = mid - 1; + } + } + return j; + }; + + const bs2 = (i, num) => { + if (i < 0) return 1; + let l = 1, r = dp[i].length - 1, j = 0; + while (l <= r) { + const mid = Math.floor((l + r) / 2); + if (dp[i][mid][0] >= num) { + j = mid; + l = mid + 1; + } else { + r = mid - 1; + } + } + return dp[i][dp[i].length - 1][1] - dp[i][j][1]; + }; + + for (let i = 1; i < nums.length; i++) { + const num = nums[i]; + if (num > dp[dp.length - 1][dp[dp.length - 1].length - 1][0]) { + const count = bs2(LIS - 1, num); + dp.push([[0, 0], [num, count]]); + LIS++; + } else { + const j = bs1(num); + const count = bs2(j - 1, num); + dp[j].push([num, dp[j][dp[j].length - 1][1] + count]); + } + } + + return dp[dp.length - 1][dp[dp.length - 1].length - 1][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/ones-and-zeroes.md b/articles/ones-and-zeroes.md new file mode 100644 index 000000000..4d3e53b4d --- /dev/null +++ b/articles/ones-and-zeroes.md @@ -0,0 +1,531 @@ +## 1. Recursion + +::tabs-start + +```python +class Solution: + def findMaxForm(self, strs: List[str], m: int, n: int) -> int: + arr = [[0] * 2 for _ in range(len(strs))] + for i, s in enumerate(strs): + for c in s: + arr[i][ord(c) - ord('0')] += 1 + + def dfs(i, m, n): + if i == len(strs): + return 0 + + res = dfs(i + 1, m, n) + if m >= arr[i][0] and n >= arr[i][1]: + res = max(res, 1 + dfs(i + 1, m - arr[i][0], n - arr[i][1])) + return res + + return dfs(0, m, n) +``` + +```java +public class Solution { + public int findMaxForm(String[] strs, int m, int n) { + int[][] arr = new int[strs.length][2]; + for (int i = 0; i < strs.length; i++) { + for (char c : strs[i].toCharArray()) { + arr[i][c - '0']++; + } + } + + return dfs(0, m, n, arr); + } + + private int dfs(int i, int m, int n, int[][] arr) { + if (i == arr.length) { + return 0; + } + + int res = dfs(i + 1, m, n, arr); + if (m >= arr[i][0] && n >= arr[i][1]) { + res = Math.max(res, 1 + dfs(i + 1, m - arr[i][0], n - arr[i][1], arr)); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int findMaxForm(vector& strs, int m, int n) { + vector> arr(strs.size(), vector(2)); + for (int i = 0; i < strs.size(); i++) { + for (char c : strs[i]) { + arr[i][c - '0']++; + } + } + return dfs(0, m, n, arr); + } + +private: + int dfs(int i, int m, int n, vector>& arr) { + if (i == arr.size()) { + return 0; + } + + int res = dfs(i + 1, m, n, arr); + if (m >= arr[i][0] && n >= arr[i][1]) { + res = max(res, 1 + dfs(i + 1, m - arr[i][0], n - arr[i][1], arr)); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} strs + * @param {number} m + * @param {number} n + * @return {number} + */ + findMaxForm(strs, m, n) { + const arr = Array.from({ length: strs.length }, () => [0, 0]); + for (let i = 0; i < strs.length; i++) { + for (const c of strs[i]) { + arr[i][c - "0"]++; + } + } + + const dfs = (i, m, n) => { + if (i === strs.length) { + return 0; + } + + let res = dfs(i + 1, m, n); + if (m >= arr[i][0] && n >= arr[i][1]) { + res = Math.max(res, 1 + dfs(i + 1, m - arr[i][0], n - arr[i][1])); + } + return res; + }; + + return dfs(0, m, n); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(2 ^ N)$ +* Space complexity: $O(N)$ for recursion stack. + +> Where $N$ represents the number of binary strings, and $m$ and $n$ are the maximum allowable counts of zeros and ones, respectively. + +--- + +## 2. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def findMaxForm(self, strs: List[str], m: int, n: int) -> int: + arr = [[0] * 2 for _ in range(len(strs))] + for i, s in enumerate(strs): + for c in s: + arr[i][ord(c) - ord('0')] += 1 + + dp = {} + + def dfs(i, m, n): + if i == len(strs): + return 0 + if m == 0 and n == 0: + return 0 + if (i, m, n) in dp: + return dp[(i, m, n)] + + res = dfs(i + 1, m, n) + if m >= arr[i][0] and n >= arr[i][1]: + res = max(res, 1 + dfs(i + 1, m - arr[i][0], n - arr[i][1])) + dp[(i, m, n)] = res + return res + + return dfs(0, m, n) +``` + +```java +public class Solution { + private int[][][] dp; + private int[][] arr; + + public int findMaxForm(String[] strs, int m, int n) { + arr = new int[strs.length][2]; + for (int i = 0; i < strs.length; i++) { + for (char c : strs[i].toCharArray()) { + arr[i][c - '0']++; + } + } + + dp = new int[strs.length][m + 1][n + 1]; + for (int i = 0; i < strs.length; i++) { + for (int j = 0; j <= m; j++) { + for (int k = 0; k <= n; k++) { + dp[i][j][k] = -1; + } + } + } + + return dfs(0, m, n); + } + + private int dfs(int i, int m, int n) { + if (i == arr.length) { + return 0; + } + if (m == 0 && n == 0) { + return 0; + } + if (dp[i][m][n] != -1) { + return dp[i][m][n]; + } + + int res = dfs(i + 1, m, n); + if (m >= arr[i][0] && n >= arr[i][1]) { + res = Math.max(res, 1 + dfs(i + 1, m - arr[i][0], n - arr[i][1])); + } + dp[i][m][n] = res; + return res; + } +} +``` + +```cpp +class Solution { +private: + vector>> dp; + vector> arr; + +public: + int findMaxForm(vector& strs, int m, int n) { + arr = vector>(strs.size(), vector(2)); + for (int i = 0; i < strs.size(); i++) { + for (char c : strs[i]) { + arr[i][c - '0']++; + } + } + + dp = vector>>(strs.size(), vector>(m + 1, vector(n + 1, -1))); + return dfs(0, m, n); + } + +private: + int dfs(int i, int m, int n) { + if (i == arr.size()) { + return 0; + } + if (m == 0 && n == 0) { + return 0; + } + if (dp[i][m][n] != -1) { + return dp[i][m][n]; + } + + int res = dfs(i + 1, m, n); + if (m >= arr[i][0] && n >= arr[i][1]) { + res = max(res, 1 + dfs(i + 1, m - arr[i][0], n - arr[i][1])); + } + dp[i][m][n] = res; + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} strs + * @param {number} m + * @param {number} n + * @return {number} + */ + findMaxForm(strs, m, n) { + const arr = Array.from({ length: strs.length }, () => [0, 0]); + for (let i = 0; i < strs.length; i++) { + for (const c of strs[i]) { + arr[i][c - "0"]++; + } + } + + const dp = Array.from({ length: strs.length }, () => + Array.from({ length: m + 1 }, () => Array(n + 1).fill(-1)) + ); + + const dfs = (i, m, n) => { + if (i === strs.length) return 0; + if (m === 0 && n === 0) return 0; + if (dp[i][m][n] !== -1) return dp[i][m][n]; + + let res = dfs(i + 1, m, n); + if (m >= arr[i][0] && n >= arr[i][1]) { + res = Math.max(res, 1 + dfs(i + 1, m - arr[i][0], n - arr[i][1])); + } + dp[i][m][n] = res; + return res; + }; + + return dfs(0, m, n); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * n * N)$ +* Space complexity: $O(m * n * N)$ + +> Where $N$ represents the number of binary strings, and $m$ and $n$ are the maximum allowable counts of zeros and ones, respectively. + +--- + +## 3. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def findMaxForm(self, strs: List[str], m: int, n: int) -> int: + arr = [[0] * 2 for _ in range(len(strs))] + for i, s in enumerate(strs): + for c in s: + arr[i][ord(c) - ord('0')] += 1 + + dp = [[[0] * (n + 1) for _ in range(m + 1)] for _ in range(len(strs) + 1)] + + for i in range(1, len(strs) + 1): + for j in range(m + 1): + for k in range(n + 1): + dp[i][j][k] = dp[i - 1][j][k] + if j >= arr[i - 1][0] and k >= arr[i - 1][1]: + dp[i][j][k] = max(dp[i][j][k], 1 + dp[i - 1][j - arr[i - 1][0]][k - arr[i - 1][1]]) + + return dp[len(strs)][m][n] +``` + +```java +public class Solution { + public int findMaxForm(String[] strs, int m, int n) { + int[][] arr = new int[strs.length][2]; + for (int i = 0; i < strs.length; i++) { + for (char c : strs[i].toCharArray()) { + arr[i][c - '0']++; + } + } + + int[][][] dp = new int[strs.length + 1][m + 1][n + 1]; + + for (int i = 1; i <= strs.length; i++) { + for (int j = 0; j <= m; j++) { + for (int k = 0; k <= n; k++) { + dp[i][j][k] = dp[i - 1][j][k]; + if (j >= arr[i - 1][0] && k >= arr[i - 1][1]) { + dp[i][j][k] = Math.max(dp[i][j][k], 1 + dp[i - 1][j - arr[i - 1][0]][k - arr[i - 1][1]]); + } + } + } + } + + return dp[strs.length][m][n]; + } +} +``` + +```cpp +class Solution { +public: + int findMaxForm(vector& strs, int m, int n) { + vector> arr(strs.size(), vector(2)); + for (int i = 0; i < strs.size(); i++) { + for (char c : strs[i]) { + arr[i][c - '0']++; + } + } + + vector>> dp(strs.size() + 1, vector>(m + 1, vector(n + 1, 0))); + + for (int i = 1; i <= strs.size(); i++) { + for (int j = 0; j <= m; j++) { + for (int k = 0; k <= n; k++) { + dp[i][j][k] = dp[i - 1][j][k]; + if (j >= arr[i - 1][0] && k >= arr[i - 1][1]) { + dp[i][j][k] = max(dp[i][j][k], 1 + dp[i - 1][j - arr[i - 1][0]][k - arr[i - 1][1]]); + } + } + } + } + + return dp[strs.size()][m][n]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} strs + * @param {number} m + * @param {number} n + * @return {number} + */ + findMaxForm(strs, m, n) { + const arr = strs.map(s => { + const zeros = s.split('').filter(c => c === '0').length; + const ones = s.length - zeros; + return [zeros, ones]; + }); + + const dp = Array.from({ length: strs.length + 1 }, () => + Array.from({ length: m + 1 }, () => Array(n + 1).fill(0)) + ); + + for (let i = 1; i <= strs.length; i++) { + for (let j = 0; j <= m; j++) { + for (let k = 0; k <= n; k++) { + dp[i][j][k] = dp[i - 1][j][k]; + if (j >= arr[i - 1][0] && k >= arr[i - 1][1]) { + dp[i][j][k] = Math.max(dp[i][j][k], 1 + dp[i - 1][j - arr[i - 1][0]][k - arr[i - 1][1]]); + } + } + } + } + + return dp[strs.length][m][n]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * n * N)$ +* Space complexity: $O(m * n * N)$ + +> Where $N$ represents the number of binary strings, and $m$ and $n$ are the maximum allowable counts of zeros and ones, respectively. + +--- + +## 4. Dynamic Programming (Space Optimized) + +::tabs-start + +```python +class Solution: + def findMaxForm(self, strs: List[str], m: int, n: int) -> int: + arr = [[0, 0] for _ in range(len(strs))] + for i, s in enumerate(strs): + for c in s: + arr[i][ord(c) - ord('0')] += 1 + + dp = [[0] * (n + 1) for _ in range(m + 1)] + + for zeros, ones in arr: + for j in range(m, zeros - 1, -1): + for k in range(n, ones - 1, -1): + dp[j][k] = max(dp[j][k], 1 + dp[j - zeros][k - ones]) + + return dp[m][n] +``` + +```java +public class Solution { + public int findMaxForm(String[] strs, int m, int n) { + int[][] arr = new int[strs.length][2]; + for (int i = 0; i < strs.length; i++) { + for (char c : strs[i].toCharArray()) { + arr[i][c - '0']++; + } + } + + int[][] dp = new int[m + 1][n + 1]; + + for (int[] pair : arr) { + int zeros = pair[0], ones = pair[1]; + for (int j = m; j >= zeros; j--) { + for (int k = n; k >= ones; k--) { + dp[j][k] = Math.max(dp[j][k], 1 + dp[j - zeros][k - ones]); + } + } + } + + return dp[m][n]; + } +} +``` + +```cpp +class Solution { +public: + int findMaxForm(vector& strs, int m, int n) { + vector> arr(strs.size(), vector(2)); + for (int i = 0; i < strs.size(); i++) { + for (char c : strs[i]) { + arr[i][c - '0']++; + } + } + + vector> dp(m + 1, vector(n + 1, 0)); + + for (const auto& pair : arr) { + int zeros = pair[0], ones = pair[1]; + for (int j = m; j >= zeros; j--) { + for (int k = n; k >= ones; k--) { + dp[j][k] = max(dp[j][k], 1 + dp[j - zeros][k - ones]); + } + } + } + + return dp[m][n]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} strs + * @param {number} m + * @param {number} n + * @return {number} + */ + findMaxForm(strs, m, n) { + const arr = Array.from({ length: strs.length }, () => [0, 0]); + for (let i = 0; i < strs.length; i++) { + for (const c of strs[i]) { + arr[i][c - "0"]++; + } + } + + const dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0)); + + for (const [zeros, ones] of arr) { + for (let j = m; j >= zeros; j--) { + for (let k = n; k >= ones; k--) { + dp[j][k] = Math.max(dp[j][k], 1 + dp[j - zeros][k - ones]); + } + } + } + + return dp[m][n]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * n * N)$ +* Space complexity: $O(m * n + N)$ + +> Where $N$ represents the number of binary strings, and $m$ and $n$ are the maximum allowable counts of zeros and ones, respectively. \ No newline at end of file diff --git a/articles/solving-questions-with-brainpower.md b/articles/solving-questions-with-brainpower.md new file mode 100644 index 000000000..248ec63b3 --- /dev/null +++ b/articles/solving-questions-with-brainpower.md @@ -0,0 +1,233 @@ +## 1. Recursion + +::tabs-start + +```python +class Solution: + def mostPoints(self, questions: List[List[int]]) -> int: + def dfs(i): + if i >= len(questions): + return 0 + return max(dfs(i + 1), questions[i][0] + dfs(i + 1 + questions[i][1])) + return dfs(0) +``` + +```java +public class Solution { + public long mostPoints(int[][] questions) { + return dfs(0, questions); + } + + private long dfs(int i, int[][] questions) { + if (i >= questions.length) return 0; + return Math.max(dfs(i + 1, questions), questions[i][0] + dfs(i + 1 + questions[i][1], questions)); + } +} +``` + +```cpp +class Solution { +public: + long long mostPoints(vector>& questions) { + return dfs(0, questions); + } + +private: + long long dfs(int i, vector>& questions) { + if (i >= questions.size()) return 0; + return max(dfs(i + 1, questions), questions[i][0] + dfs(i + 1 + questions[i][1], questions)); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} questions + * @return {number} + */ + mostPoints(questions) { + const dfs = (i) => { + if (i >= questions.length) return 0; + return Math.max(dfs(i + 1), questions[i][0] + dfs(i + 1 + questions[i][1])); + }; + return dfs(0); + } +} +``` + +::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 mostPoints(self, questions: List[List[int]]) -> int: + dp = {} + def dfs(i): + if i >= len(questions): + return 0 + if i in dp: + return dp[i] + dp[i] = max(dfs(i + 1), questions[i][0] + dfs(i + 1 + questions[i][1])) + return dp[i] + return dfs(0) +``` + +```java +public class Solution { + private long[] dp; + + public long mostPoints(int[][] questions) { + dp = new long[questions.length]; + return dfs(0, questions); + } + + private long dfs(int i, int[][] questions) { + if (i >= questions.length) return 0; + if (dp[i] != 0) return dp[i]; + dp[i] = Math.max(dfs(i + 1, questions), questions[i][0] + dfs(i + 1 + questions[i][1], questions)); + return dp[i]; + } +} + +``` + +```cpp +class Solution { + vector dp; + +public: + long long mostPoints(vector>& questions) { + dp.assign(questions.size(), 0); + return dfs(0, questions); + } + +private: + long long dfs(int i, vector>& questions) { + if (i >= questions.size()) return 0; + if (dp[i] != 0) return dp[i]; + dp[i] = max(dfs(i + 1, questions), questions[i][0] + dfs(i + 1 + questions[i][1], questions)); + return dp[i]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} questions + * @return {number} + */ + mostPoints(questions) { + const dp = new Array(questions.length).fill(-1); + + const dfs = (i) => { + if (i >= questions.length) return 0; + if (dp[i] !== -1) return dp[i]; + dp[i] = Math.max(dfs(i + 1), questions[i][0] + dfs(i + 1 + questions[i][1])); + return dp[i]; + }; + + return dfs(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 mostPoints(self, questions: List[List[int]]) -> int: + dp = {} + + for i in range(len(questions) - 1, -1, -1): + dp[i] = max( + questions[i][0] + dp.get(i + 1 + questions[i][1], 0), + dp.get(i + 1, 0) + ) + return dp.get(0) +``` + +```java +public class Solution { + public long mostPoints(int[][] questions) { + int n = questions.length; + long[] dp = new long[n + 1]; + + for (int i = n - 1; i >= 0; i--) { + dp[i] = Math.max( + questions[i][0] + (i + 1 + questions[i][1] < n ? dp[i + 1 + questions[i][1]] : 0), + dp[i + 1] + ); + } + return dp[0]; + } +} +``` + +```cpp +class Solution { +public: + long long mostPoints(vector>& questions) { + int n = questions.size(); + vector dp(n + 1, 0); + + for (int i = n - 1; i >= 0; i--) { + dp[i] = max( + (long long)questions[i][0] + (i + 1 + questions[i][1] < n ? dp[i + 1 + questions[i][1]] : 0), + dp[i + 1] + ); + } + return dp[0]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} questions + * @return {number} + */ + mostPoints(questions) { + const n = questions.length; + const dp = new Array(n + 1).fill(0); + + for (let i = n - 1; i >= 0; i--) { + dp[i] = Math.max( + questions[i][0] + (i + 1 + questions[i][1] < n ? dp[i + 1 + questions[i][1]] : 0), + dp[i + 1] + ); + } + return dp[0]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ \ No newline at end of file diff --git a/articles/stickers-to-spell-word.md b/articles/stickers-to-spell-word.md new file mode 100644 index 000000000..2abbe91a7 --- /dev/null +++ b/articles/stickers-to-spell-word.md @@ -0,0 +1,580 @@ +## 1. Dynamic Programming (Top-Down) - I + +::tabs-start + +```python +class Solution: + def minStickers(self, stickers: List[str], target: str) -> int: + stickCount = [] + for s in stickers: + stickCount.append({}) + for c in s: + stickCount[-1][c] = 1 + stickCount[-1].get(c, 0) + + dp = {} + + def dfs(t, stick): + if t in dp: + return dp[t] + res = 1 if stick else 0 + remainT = "" + for c in t: + if c in stick and stick[c] > 0: + stick[c] -= 1 + else: + remainT += c + if remainT: + used = float("inf") + for s in stickCount: + if remainT[0] not in s: + continue + used = min(used, dfs(remainT, s.copy())) + dp[remainT] = used + res += used + return res + + res = dfs(target, {}) + return res if res != float("inf") else -1 +``` + +```java +public class Solution { + private List> stickCount; + private Map dp; + + public int minStickers(String[] stickers, String target) { + stickCount = new ArrayList<>(); + dp = new HashMap<>(); + + for (String s : stickers) { + Map countMap = new HashMap<>(); + for (char c : s.toCharArray()) { + countMap.put(c, countMap.getOrDefault(c, 0) + 1); + } + stickCount.add(countMap); + } + + int res = dfs(target, new HashMap<>()); + return res == Integer.MAX_VALUE ? -1 : res; + } + + private int dfs(String t, Map stick) { + if (t.isEmpty()) return 0; + if (dp.containsKey(t)) return dp.get(t); + + int res = stick.isEmpty() ? 0 : 1; + StringBuilder remainT = new StringBuilder(); + + for (char c : t.toCharArray()) { + if (stick.containsKey(c) && stick.get(c) > 0) { + stick.put(c, stick.get(c) - 1); + } else { + remainT.append(c); + } + } + + if (remainT.length() > 0) { + int used = Integer.MAX_VALUE; + for (Map s : stickCount) { + if (!s.containsKey(remainT.charAt(0))) continue; + int curr = dfs(remainT.toString(), new HashMap<>(s)); + if (curr != Integer.MAX_VALUE) { + used = Math.min(used, curr); + } + } + dp.put(remainT.toString(), used); + if (used != Integer.MAX_VALUE && res != Integer.MAX_VALUE) { + res += used; + } else { + res = Integer.MAX_VALUE; + } + } + + return res; + } +} +``` + +```cpp +class Solution { + vector> stickCount; + unordered_map dp; + +public: + int minStickers(vector& stickers, string target) { + stickCount.clear(); + dp.clear(); + + for (const string& s : stickers) { + unordered_map countMap; + for (char c : s) { + countMap[c]++; + } + stickCount.push_back(countMap); + } + + int res = dfs(target, unordered_map()); + return res == INT_MAX ? -1 : res; + } + +private: + int dfs(const string& t, unordered_map stick) { + if (t.empty()) return 0; + if (dp.count(t)) return dp[t]; + + int res = stick.empty() ? 0 : 1; + string remainT; + + for (char c : t) { + if (stick.count(c) && stick[c] > 0) { + stick[c]--; + } else { + remainT += c; + } + } + + if (!remainT.empty()) { + int used = INT_MAX; + for (const auto& s : stickCount) { + if (!s.count(remainT[0])) continue; + int curr = dfs(remainT, unordered_map(s)); + if (curr != INT_MAX) { + used = min(used, curr); + } + } + dp[remainT] = used; + if (used != INT_MAX && res != INT_MAX) { + res += used; + } else { + res = INT_MAX; + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} stickers + * @param {string} target + * @return {number} + */ + minStickers(stickers, target) { + const stickCount = []; + const dp = new Map(); + + for (const s of stickers) { + const countMap = new Map(); + for (const c of s) { + countMap.set(c, (countMap.get(c) || 0) + 1); + } + stickCount.push(countMap); + } + + const dfs = (t, stick) => { + if (t === '') return 0; + if (dp.has(t)) return dp.get(t); + + let res = stick.size === 0 ? 0 : 1; + let remainT = ''; + + for (const c of t) { + if (stick.has(c) && stick.get(c) > 0) { + stick.set(c, stick.get(c) - 1); + } else { + remainT += c; + } + } + + if (remainT.length > 0) { + let used = Infinity; + for (const s of stickCount) { + if (!s.has(remainT[0])) continue; + const newStick = new Map(s); + const curr = dfs(remainT, newStick); + used = Math.min(used, curr); + } + dp.set(remainT, used); + if (used !== Infinity && res !== Infinity) { + res += used; + } else { + res = Infinity; + } + } + + return res; + }; + + const res = dfs(target, new Map()); + return res === Infinity ? -1 : res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * k *2 ^ n)$ +* Space complexity: $O(m * k + 2 ^ n)$ + +> Where $n$ is the length of the target string, $m$ is the number of stickers and $k$ is the average length of each sticker. + +--- + +## 2. Dynamic Programming (Top-Down) - II + +::tabs-start + +```python +class Solution: + def minStickers(self, stickers: List[str], target: str) -> int: + tmp = [c for c in target] + target = ''.join(sorted(tmp)) + stickCount = [] + for s in stickers: + stickCount.append(Counter(s)) + + dp = {} + dp[""] = 0 + + def dfs(t): + if t in dp: + return dp[t] + + tarMp = Counter(t) + res = float("inf") + for s in stickCount: + if t[0] not in s: + continue + remainT = [] + for c in tarMp: + if tarMp[c] > s[c]: + remainT.extend([c] * (tarMp[c] - s[c])) + + remainT = ''.join(sorted(remainT)) + res = min(res, 1 + dfs(remainT)) + + dp[t] = res + return res + + ans = dfs(target) + return -1 if ans == float("inf") else ans +``` + +```java +public class Solution { + private Map dp = new HashMap<>(); + private List> stickCount = new ArrayList<>(); + + public int minStickers(String[] stickers, String target) { + dp.put("", 0); + for (String s : stickers) { + Map counter = new HashMap<>(); + for (char c : s.toCharArray()) { + counter.put(c, counter.getOrDefault(c, 0) + 1); + } + stickCount.add(counter); + } + char[] targetArray = target.toCharArray(); + Arrays.sort(targetArray); + target = new String(targetArray); + + int ans = dfs(target); + return ans == Integer.MAX_VALUE ? -1 : ans; + } + + private int dfs(String t) { + if (dp.containsKey(t)) { + return dp.get(t); + } + + Map tarMp = new HashMap<>(); + for (char c : t.toCharArray()) { + tarMp.put(c, tarMp.getOrDefault(c, 0) + 1); + } + + int res = Integer.MAX_VALUE; + for (Map s : stickCount) { + if (!s.containsKey(t.charAt(0))) { + continue; + } + + StringBuilder remainT = new StringBuilder(); + for (Map.Entry entry : tarMp.entrySet()) { + char c = entry.getKey(); + int need = entry.getValue() - s.getOrDefault(c, 0); + for (int i = 0; i < Math.max(0, need); i++) { + remainT.append(c); + } + } + char[] remainArray = remainT.toString().toCharArray(); + Arrays.sort(remainArray); + int cur = dfs(new String(remainArray)); + if (cur == Integer.MAX_VALUE) cur--; + res = Math.min(res, 1 + cur); + } + + dp.put(t, res); + return res; + } +} +``` + +```cpp +class Solution { +private: + unordered_map dp; + vector> stickCount; + +public: + int minStickers(vector& stickers, string target) { + dp[""] = 0; + for (const string& s : stickers) { + unordered_map counter; + for (char c : s) { + counter[c]++; + } + stickCount.push_back(counter); + } + + sort(target.begin(), target.end()); + int ans = dfs(target); + return ans == INT_MAX ? -1 : ans; + } + + int dfs(const string& t) { + if (dp.find(t) != dp.end()) { + return dp[t]; + } + + unordered_map tarMp; + for (char c : t) { + tarMp[c]++; + } + + int res = INT_MAX; + for (auto& s : stickCount) { + if (s.find(t[0]) == s.end()) { + continue; + } + + string remainT; + for (const auto& [c, count] : tarMp) { + int need = count - (s.count(c) ? s.at(c) : 0); + remainT.append(max(0, need), c); + } + + sort(remainT.begin(), remainT.end()); + int cur = dfs(remainT); + if (cur == INT_MAX) cur--; + res = min(res, 1 + cur); + } + + dp[t] = res; + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} stickers + * @param {string} target + * @return {number} + */ + minStickers(stickers, target) { + const dp = { "": 0 }; + const stickCount = stickers.map((s) => { + const counter = {}; + for (const c of s) { + counter[c] = (counter[c] || 0) + 1; + } + return counter; + }); + + const dfs = (t) => { + if (dp[t] !== undefined) return dp[t]; + + const tarMp = {}; + for (const c of t) { + tarMp[c] = (tarMp[c] || 0) + 1; + } + + let res = Infinity; + for (const s of stickCount) { + if (!s[t[0]]) continue; + + let remainT = []; + for (const [c, count] of Object.entries(tarMp)) { + let need = count - (s[c] || 0); + while (need > 0) { + remainT.push(c); + need--; + } + } + + remainT = remainT.sort().join(""); + res = Math.min(res, 1 + dfs(remainT)); + } + + dp[t] = res; + return res; + }; + + const ans = dfs(target.split("").sort().join("")); + return ans === Infinity ? -1 : ans; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * k *2 ^ n)$ +* Space complexity: $O(m * k + 2 ^ n)$ + +> Where $n$ is the length of the target string, $m$ is the number of stickers and $k$ is the average length of each sticker. + +--- + +## 3. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def minStickers(self, stickers: List[str], target: str) -> int: + n = len(target) + N = 1 << n + dp = [-1] * N + dp[0] = 0 + + for t in range(N): + if dp[t] == -1: + continue + for s in stickers: + nextT = t + for c in s: + for i in range(n): + if target[i] == c and not ((nextT >> i) & 1): + nextT |= 1 << i + break + if dp[nextT] == -1 or dp[nextT] > dp[t] + 1: + dp[nextT] = dp[t] + 1 + return dp[N - 1] +``` + +```java +public class Solution { + public int minStickers(String[] stickers, String target) { + int n = target.length(); + int N = 1 << n; + int[] dp = new int[N]; + Arrays.fill(dp, -1); + dp[0] = 0; + + for (int t = 0; t < N; t++) { + if (dp[t] == -1) continue; + for (String s : stickers) { + int nextT = t; + for (char c : s.toCharArray()) { + for (int i = 0; i < n; i++) { + if (target.charAt(i) == c && ((nextT >> i) & 1) == 0) { + nextT |= 1 << i; + break; + } + } + } + if (dp[nextT] == -1 || dp[nextT] > dp[t] + 1) { + dp[nextT] = dp[t] + 1; + } + } + } + + return dp[N - 1]; + } +} +``` + +```cpp +class Solution { +public: + int minStickers(vector& stickers, string target) { + int n = target.length(); + int N = 1 << n; + vector dp(N, -1); + dp[0] = 0; + + for (int t = 0; t < N; t++) { + if (dp[t] == -1) continue; + for (string& s : stickers) { + int nextT = t; + for (char c : s) { + for (int i = 0; i < n; i++) { + if (target[i] == c && ((nextT >> i) & 1) == 0) { + nextT |= 1 << i; + break; + } + } + } + if (dp[nextT] == -1 || dp[nextT] > dp[t] + 1) { + dp[nextT] = dp[t] + 1; + } + } + } + + return dp[N - 1]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} stickers + * @param {string} target + * @return {number} + */ + minStickers(stickers, target) { + const n = target.length; + const N = 1 << n; + const dp = Array(N).fill(-1); + dp[0] = 0; + + for (let t = 0; t < N; t++) { + if (dp[t] === -1) continue; + for (let s of stickers) { + let nextT = t; + for (let c of s) { + for (let i = 0; i < n; i++) { + if (target[i] === c && ((nextT >> i) & 1) === 0) { + nextT |= 1 << i; + break; + } + } + } + if (dp[nextT] === -1 || dp[nextT] > dp[t] + 1) { + dp[nextT] = dp[t] + 1; + } + } + } + + return dp[N - 1]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * m * k *2 ^ n)$ +* Space complexity: $O(2 ^ n)$ + +> Where $n$ is the length of the target string, $m$ is the number of stickers and $k$ is the average length of each sticker. \ No newline at end of file diff --git a/articles/stone-game.md b/articles/stone-game.md new file mode 100644 index 000000000..54e5043c1 --- /dev/null +++ b/articles/stone-game.md @@ -0,0 +1,525 @@ +## 1. Recursion + +::tabs-start + +```python +class Solution: + def stoneGame(self, piles: List[int]) -> bool: + def dfs(l, r): + if l > r: + return 0 + even = (r - l) % 2 == 0 + left = piles[l] if even else 0 + right = piles[r] if even else 0 + return max(dfs(l + 1, r) + left, dfs(l, r - 1) + right) + + total = sum(piles) + alice_score = dfs(0, len(piles) - 1) + return alice_score > total - alice_score +``` + +```java +public class Solution { + public boolean stoneGame(int[] piles) { + int total = 0; + for (int pile : piles) { + total += pile; + } + + int aliceScore = dfs(0, piles.length - 1, piles); + return aliceScore > total - aliceScore; + } + + private int dfs(int l, int r, int[] piles) { + if (l > r) { + return 0; + } + boolean even = (r - l) % 2 == 0; + int left = even ? piles[l] : 0; + int right = even ? piles[r] : 0; + return Math.max(dfs(l + 1, r, piles) + left, dfs(l, r - 1, piles) + right); + } +} +``` + +```cpp +class Solution { +public: + bool stoneGame(vector& piles) { + int total = accumulate(piles.begin(), piles.end(), 0); + int aliceScore = dfs(0, piles.size() - 1, piles); + return aliceScore > total - aliceScore; + } + +private: + int dfs(int l, int r, const vector& piles) { + if (l > r) { + return 0; + } + bool even = (r - l) % 2 == 0; + int left = even ? piles[l] : 0; + int right = even ? piles[r] : 0; + return max(dfs(l + 1, r, piles) + left, dfs(l, r - 1, piles) + right); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} piles + * @return {boolean} + */ + stoneGame(piles) { + const total = piles.reduce((a, b) => a + b, 0); + + const dfs = (l, r) => { + if (l > r) { + return 0; + } + const even = (r - l) % 2 === 0; + const left = even ? piles[l] : 0; + const right = even ? piles[r] : 0; + return Math.max(dfs(l + 1, r) + left, dfs(l, r - 1) + right); + }; + + const aliceScore = dfs(0, piles.length - 1); + return aliceScore > total - aliceScore; + } +} +``` + +::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 stoneGame(self, piles: List[int]) -> bool: + dp = {} + + def dfs(l, r): + if l > r: + return 0 + if (l, r) in dp: + return dp[(l, r)] + even = (r - l) % 2 == 0 + left = piles[l] if even else 0 + right = piles[r] if even else 0 + dp[(l, r)] = max(dfs(l + 1, r) + left, dfs(l, r - 1) + right) + return dp[(l, r)] + + total = sum(piles) + alice_score = dfs(0, len(piles) - 1) + return alice_score > total - alice_score +``` + +```java +public class Solution { + private int[][] dp; + + public boolean stoneGame(int[] piles) { + int n = piles.length; + dp = new int[n][n]; + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + dp[i][j] = -1; + } + } + + int total = 0; + for (int pile : piles) { + total += pile; + } + + int aliceScore = dfs(0, n - 1, piles); + return aliceScore > total - aliceScore; + } + + private int dfs(int l, int r, int[] piles) { + if (l > r) { + return 0; + } + if (dp[l][r] != -1) { + return dp[l][r]; + } + boolean even = (r - l) % 2 == 0; + int left = even ? piles[l] : 0; + int right = even ? piles[r] : 0; + dp[l][r] = Math.max(dfs(l + 1, r, piles) + left, dfs(l, r - 1, piles) + right); + return dp[l][r]; + } +} +``` + +```cpp +class Solution { +private: + vector> dp; + +public: + bool stoneGame(vector& piles) { + int n = piles.size(); + dp = vector>(n, vector(n, -1)); + int total = accumulate(piles.begin(), piles.end(), 0); + int aliceScore = dfs(0, n - 1, piles); + return aliceScore > total - aliceScore; + } + +private: + int dfs(int l, int r, const vector& piles) { + if (l > r) { + return 0; + } + if (dp[l][r] != -1) { + return dp[l][r]; + } + bool even = (r - l) % 2 == 0; + int left = even ? piles[l] : 0; + int right = even ? piles[r] : 0; + dp[l][r] = max(dfs(l + 1, r, piles) + left, dfs(l, r - 1, piles) + right); + return dp[l][r]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} piles + * @return {boolean} + */ + stoneGame(piles) { + const n = piles.length; + const dp = Array.from({ length: n }, () => Array(n).fill(-1)); + + const dfs = (l, r) => { + if (l > r) { + return 0; + } + if (dp[l][r] !== -1) { + return dp[l][r]; + } + const even = (r - l) % 2 === 0; + const left = even ? piles[l] : 0; + const right = even ? piles[r] : 0; + dp[l][r] = Math.max(dfs(l + 1, r) + left, dfs(l, r - 1) + right); + return dp[l][r]; + }; + + const total = piles.reduce((a, b) => a + b, 0); + const aliceScore = dfs(0, n - 1); + return aliceScore > total - aliceScore; + } +} +``` + +::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 stoneGame(self, piles: List[int]) -> bool: + n = len(piles) + dp = [[0] * n for _ in range(n)] + + for l in range(n - 1, -1, -1): + for r in range(l, n): + even = (r - l) % 2 == 0 + left = piles[l] if even else 0 + right = piles[r] if even else 0 + if l == r: + dp[l][r] = left + else: + dp[l][r] = max(dp[l + 1][r] + left, dp[l][r - 1] + right) + + total = sum(piles) + alice_score = dp[0][n - 1] + return alice_score > total - alice_score +``` + +```java +public class Solution { + public boolean stoneGame(int[] piles) { + int n = piles.length; + int[][] dp = new int[n][n]; + + for (int l = n - 1; l >= 0; l--) { + for (int r = l; r < n; r++) { + boolean even = (r - l) % 2 == 0; + int left = even ? piles[l] : 0; + int right = even ? piles[r] : 0; + if (l == r) { + dp[l][r] = left; + } else { + dp[l][r] = Math.max(dp[l + 1][r] + left, dp[l][r - 1] + right); + } + } + } + + int total = 0; + for (int pile : piles) { + total += pile; + } + + int aliceScore = dp[0][n - 1]; + return aliceScore > total - aliceScore; + } +} +``` + +```cpp +class Solution { +public: + bool stoneGame(vector& piles) { + int n = piles.size(); + vector> dp(n, vector(n, 0)); + + for (int l = n - 1; l >= 0; l--) { + for (int r = l; r < n; r++) { + bool even = (r - l) % 2 == 0; + int left = even ? piles[l] : 0; + int right = even ? piles[r] : 0; + if (l == r) { + dp[l][r] = left; + } else { + dp[l][r] = max(dp[l + 1][r] + left, dp[l][r - 1] + right); + } + } + } + + int total = accumulate(piles.begin(), piles.end(), 0); + int aliceScore = dp[0][n - 1]; + return aliceScore > total - aliceScore; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} piles + * @return {boolean} + */ + stoneGame(piles) { + const n = piles.length; + const dp = Array.from({ length: n }, () => Array(n).fill(0)); + + for (let l = n - 1; l >= 0; l--) { + for (let r = l; r < n; r++) { + const even = (r - l) % 2 === 0; + const left = even ? piles[l] : 0; + const right = even ? piles[r] : 0; + if (l === r) { + dp[l][r] = left; + } else { + dp[l][r] = Math.max(dp[l + 1][r] + left, dp[l][r - 1] + right); + } + } + } + + const total = piles.reduce((a, b) => a + b, 0); + const aliceScore = dp[0][n - 1]; + return aliceScore > total - aliceScore; + } +} +``` + +::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 stoneGame(self, piles: List[int]) -> bool: + n = len(piles) + dp = [0] * n + + for l in reversed(range(n)): + for r in range(l, n): + even = ((r - l) % 2 == 0) + left = piles[l] if even else 0 + right = piles[r] if even else 0 + + if l == r: + dp[r] = left + else: + dp[r] = max(dp[r] + left, dp[r - 1] + right) + + total = sum(piles) + alice_score = dp[n - 1] + return alice_score > (total - alice_score) +``` + +```java +public class Solution { + public boolean stoneGame(int[] piles) { + int n = piles.length; + int[] dp = new int[n]; + + for (int l = n - 1; l >= 0; l--) { + for (int r = l; r < n; r++) { + boolean even = (r - l) % 2 == 0; + int left = even ? piles[l] : 0; + int right = even ? piles[r] : 0; + + if (l == r) { + dp[r] = left; + } else { + dp[r] = Math.max(dp[r] + left, dp[r - 1] + right); + } + } + } + + int total = 0; + for (int pile : piles) { + total += pile; + } + + int aliceScore = dp[n - 1]; + return aliceScore > (total - aliceScore); + } +} +``` + +```cpp +class Solution { +public: + bool stoneGame(vector& piles) { + int n = piles.size(); + vector dp(n, 0); + + for (int l = n - 1; l >= 0; l--) { + for (int r = l; r < n; r++) { + bool even = (r - l) % 2 == 0; + int left = even ? piles[l] : 0; + int right = even ? piles[r] : 0; + + if (l == r) { + dp[r] = left; + } else { + dp[r] = max(dp[r] + left, dp[r - 1] + right); + } + } + } + + int total = accumulate(piles.begin(), piles.end(), 0); + int aliceScore = dp[n - 1]; + return aliceScore > (total - aliceScore); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} piles + * @return {boolean} + */ + stoneGame(piles) { + const n = piles.length; + const dp = new Array(n).fill(0); + + for (let l = n - 1; l >= 0; l--) { + for (let r = l; r < n; r++) { + const even = (r - l) % 2 === 0; + const left = even ? piles[l] : 0; + const right = even ? piles[r] : 0; + + if (l === r) { + dp[r] = left; + } else { + dp[r] = Math.max(dp[r] + left, dp[r - 1] + right); + } + } + } + + const total = piles.reduce((a, b) => a + b, 0); + const aliceScore = dp[n - 1]; + return aliceScore > (total - aliceScore); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n)$ + +--- + +## 5. Return TRUE + +::tabs-start + +```python +class Solution: + def stoneGame(self, piles: List[int]) -> bool: + return True +``` + +```java +public class Solution { + public boolean stoneGame(int[] piles) { + return true; + } +} +``` + +```cpp +class Solution { +public: + bool stoneGame(vector& piles) { + return true; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} piles + * @return {boolean} + */ + stoneGame(piles) { + return true; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(1)$ +* Space complexity: $O(1)$ \ No newline at end of file diff --git a/articles/uncrossed-lines.md b/articles/uncrossed-lines.md new file mode 100644 index 000000000..a08442f64 --- /dev/null +++ b/articles/uncrossed-lines.md @@ -0,0 +1,560 @@ +## 1. Recursion + +::tabs-start + +```python +class Solution: + def maxUncrossedLines(self, nums1: List[int], nums2: List[int]) -> int: + def dfs(i, j): + if i == len(nums1) or j == len(nums2): + return 0 + + if nums1[i] == nums2[j]: + return 1 + dfs(i + 1, j + 1) + return max(dfs(i, j + 1), dfs(i + 1, j)) + + return dfs(0, 0) +``` + +```java +public class Solution { + public int maxUncrossedLines(int[] nums1, int[] nums2) { + int n1 = nums1.length, n2 = nums2.length; + + return dfs(nums1, nums2, 0, 0); + } + + private int dfs(int[] nums1, int[] nums2, int i, int j) { + if (i == nums1.length || j == nums2.length) return 0; + + if (nums1[i] == nums2[j]) { + return 1 + dfs(nums1, nums2, i + 1, j + 1); + } + return Math.max(dfs(nums1, nums2, i, j + 1), dfs(nums1, nums2, i + 1, j)); + } +} +``` + +```cpp +class Solution { +public: + int dfs(vector& nums1, vector& nums2, int i, int j) { + if (i == nums1.size() || j == nums2.size()) return 0; + + if (nums1[i] == nums2[j]) { + return 1 + dfs(nums1, nums2, i + 1, j + 1); + } + return max(dfs(nums1, nums2, i, j + 1), dfs(nums1, nums2, i + 1, j)); + } + + int maxUncrossedLines(vector& nums1, vector& nums2) { + return dfs(nums1, nums2, 0, 0); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @return {number} + */ + maxUncrossedLines(nums1, nums2) { + const dfs = (i, j) => { + if (i === nums1.length || j === nums2.length) { + return 0; + } + if (nums1[i] === nums2[j]) { + return 1 + dfs(i + 1, j + 1); + } + return Math.max(dfs(i, j + 1), dfs(i + 1, j)); + }; + + return dfs(0, 0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(2 ^ {n + m})$ +* Space complexity: $O(n + m)$ for recursion stack. + +> Where $n$ and $m$ are the sizes of the arrays $nums1$ and $nums2$ respectively. + +--- + +## 2. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def maxUncrossedLines(self, nums1: List[int], nums2: List[int]) -> int: + dp = {} + + def dfs(i, j): + if i == len(nums1) or j == len(nums2): + return 0 + + if (i, j) in dp: + return dp[(i, j)] + + if nums1[i] == nums2[j]: + dp[(i, j)] = 1 + dfs(i + 1, j + 1) + else: + dp[(i, j)] = max(dfs(i, j + 1), dfs(i + 1, j)) + + return dp[(i, j)] + + return dfs(0, 0) +``` + +```java +public class Solution { + public int maxUncrossedLines(int[] nums1, int[] nums2) { + int n = nums1.length, m = nums2.length; + int[][] dp = new int[n][m]; + + for (int[] row : dp) { + Arrays.fill(row, -1); + } + + return dfs(0, 0, nums1, nums2, dp); + } + + private int dfs(int i, int j, int[] nums1, int[] nums2, int[][] dp) { + if (i == nums1.length || j == nums2.length) { + return 0; + } + + if (dp[i][j] != -1) { + return dp[i][j]; + } + + if (nums1[i] == nums2[j]) { + dp[i][j] = 1 + dfs(i + 1, j + 1, nums1, nums2, dp); + } else { + dp[i][j] = Math.max(dfs(i, j + 1, nums1, nums2, dp), dfs(i + 1, j, nums1, nums2, dp)); + } + + return dp[i][j]; + } +} +``` + +```cpp +class Solution { +public: + int maxUncrossedLines(vector& nums1, vector& nums2) { + int n = nums1.size(), m = nums2.size(); + vector> dp(n, vector(m, -1)); + + return dfs(0, 0, nums1, nums2, dp); + } + +private: + int dfs(int i, int j, vector& nums1, vector& nums2, vector>& dp) { + if (i == nums1.size() || j == nums2.size()) { + return 0; + } + + if (dp[i][j] != -1) { + return dp[i][j]; + } + + if (nums1[i] == nums2[j]) { + dp[i][j] = 1 + dfs(i + 1, j + 1, nums1, nums2, dp); + } else { + dp[i][j] = max(dfs(i, j + 1, nums1, nums2, dp), dfs(i + 1, j, nums1, nums2, dp)); + } + + return dp[i][j]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @return {number} + */ + maxUncrossedLines(nums1, nums2) { + const n = nums1.length, m = nums2.length; + const dp = Array.from({ length: n }, () => Array(m).fill(-1)); + + const dfs = (i, j) => { + if (i === n || j === m) { + return 0; + } + + if (dp[i][j] !== -1) { + return dp[i][j]; + } + + if (nums1[i] === nums2[j]) { + dp[i][j] = 1 + dfs(i + 1, j + 1); + } else { + dp[i][j] = Math.max(dfs(i, j + 1), dfs(i + 1, j)); + } + + return dp[i][j]; + }; + + return dfs(0, 0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * m)$ +* Space complexity: $O(n * m)$ + +> Where $n$ and $m$ are the sizes of the arrays $nums1$ and $nums2$ respectively. + +--- + +## 3. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def maxUncrossedLines(self, nums1: List[int], nums2: List[int]) -> int: + n, m = len(nums1), len(nums2) + dp = [[0] * (m + 1) for _ in range(n + 1)] + + for i in range(n): + for j in range(m): + if nums1[i] == nums2[j]: + dp[i + 1][j + 1] = 1 + dp[i][j] + else: + dp[i + 1][j + 1] = max(dp[i][j + 1], dp[i + 1][j]) + + return dp[n][m] +``` + +```java +public class Solution { + public int maxUncrossedLines(int[] nums1, int[] nums2) { + int n = nums1.length, m = nums2.length; + int[][] dp = new int[n + 1][m + 1]; + + for (int i = 0; i < n; i++) { + for (int j = 0; j < m; j++) { + if (nums1[i] == nums2[j]) { + dp[i + 1][j + 1] = 1 + dp[i][j]; + } else { + dp[i + 1][j + 1] = Math.max(dp[i][j + 1], dp[i + 1][j]); + } + } + } + + return dp[n][m]; + } +} +``` + +```cpp +class Solution { +public: + int maxUncrossedLines(vector& nums1, vector& nums2) { + int n = nums1.size(), m = nums2.size(); + vector> dp(n + 1, vector(m + 1, 0)); + + for (int i = 0; i < n; i++) { + for (int j = 0; j < m; j++) { + if (nums1[i] == nums2[j]) { + dp[i + 1][j + 1] = 1 + dp[i][j]; + } else { + dp[i + 1][j + 1] = max(dp[i][j + 1], dp[i + 1][j]); + } + } + } + + return dp[n][m]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @return {number} + */ + maxUncrossedLines(nums1, nums2) { + const n = nums1.length, m = nums2.length; + const dp = Array.from({ length: n + 1 }, () => Array(m + 1).fill(0)); + + for (let i = 0; i < n; i++) { + for (let j = 0; j < m; j++) { + if (nums1[i] === nums2[j]) { + dp[i + 1][j + 1] = 1 + dp[i][j]; + } else { + dp[i + 1][j + 1] = Math.max(dp[i][j + 1], dp[i + 1][j]); + } + } + } + + return dp[n][m]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * m)$ +* Space complexity: $O(n * m)$ + +> Where $n$ and $m$ are the sizes of the arrays $nums1$ and $nums2$ respectively. + +--- + +## 4. Dynamic Programming (Space Optimized) + +::tabs-start + +```python +class Solution: + def maxUncrossedLines(self, nums1: List[int], nums2: List[int]) -> int: + prev = [0] * (len(nums2) + 1) + + for i in range(len(nums1)): + dp = [0] * (len(nums2) + 1) + for j in range(len(nums2)): + if nums1[i] == nums2[j]: + dp[j + 1] = 1 + prev[j] + else: + dp[j + 1] = max(dp[j], prev[j + 1]) + prev = dp + + return prev[len(nums2)] +``` + +```java +public class Solution { + public int maxUncrossedLines(int[] nums1, int[] nums2) { + int[] prev = new int[nums2.length + 1]; + + for (int i = 0; i < nums1.length; i++) { + int[] dp = new int[nums2.length + 1]; + for (int j = 0; j < nums2.length; j++) { + if (nums1[i] == nums2[j]) { + dp[j + 1] = 1 + prev[j]; + } else { + dp[j + 1] = Math.max(dp[j], prev[j + 1]); + } + } + prev = dp; + } + + return prev[nums2.length]; + } +} +``` + +```cpp +class Solution { +public: + int maxUncrossedLines(vector& nums1, vector& nums2) { + vector prev(nums2.size() + 1, 0); + + for (int i = 0; i < nums1.size(); i++) { + vector dp(nums2.size() + 1, 0); + for (int j = 0; j < nums2.size(); j++) { + if (nums1[i] == nums2[j]) { + dp[j + 1] = 1 + prev[j]; + } else { + dp[j + 1] = max(dp[j], prev[j + 1]); + } + } + prev = dp; + } + + return prev[nums2.size()]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @return {number} + */ + maxUncrossedLines(nums1, nums2) { + let prev = new Array(nums2.length + 1).fill(0); + + for (let i = 0; i < nums1.length; i++) { + const dp = new Array(nums2.length + 1).fill(0); + for (let j = 0; j < nums2.length; j++) { + if (nums1[i] === nums2[j]) { + dp[j + 1] = 1 + prev[j]; + } else { + dp[j + 1] = Math.max(dp[j], prev[j + 1]); + } + } + prev = dp; + } + + return prev[nums2.length]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * m)$ +* Space complexity: $O(m)$ + +> Where $n$ and $m$ are the sizes of the arrays $nums1$ and $nums2$ respectively. + +--- + +## 5. Dynamic Programming (Optimal) + +::tabs-start + +```python +class Solution: + def maxUncrossedLines(self, nums1: List[int], nums2: List[int]) -> int: + n, m = len(nums1), len(nums2) + if m > n: + n, m = m, n + nums1, nums2 = nums2, nums1 + + dp = [0] * (m + 1) + + for i in range(n): + prev = 0 + for j in range(m): + temp = dp[j + 1] + if nums1[i] == nums2[j]: + dp[j + 1] = 1 + prev + else: + dp[j + 1] = max(dp[j + 1], dp[j]) + prev = temp + + return dp[m] +``` + +```java +public class Solution { + public int maxUncrossedLines(int[] nums1, int[] nums2) { + int n = nums1.length, m = nums2.length; + if (m > n) { + int[] tempArr = nums1; + nums1 = nums2; + nums2 = tempArr; + int temp = n; + n = m; + m = temp; + } + + int[] dp = new int[m + 1]; + + for (int i = 0; i < n; i++) { + int prev = 0; + for (int j = 0; j < m; j++) { + int temp = dp[j + 1]; + if (nums1[i] == nums2[j]) { + dp[j + 1] = 1 + prev; + } else { + dp[j + 1] = Math.max(dp[j + 1], dp[j]); + } + prev = temp; + } + } + + return dp[m]; + } +} +``` + +```cpp +class Solution { +public: + int maxUncrossedLines(vector& nums1, vector& nums2) { + int n = nums1.size(), m = nums2.size(); + if (m > n) { + swap(nums1, nums2); + swap(n, m); + } + + vector dp(m + 1, 0); + + for (int i = 0; i < n; i++) { + int prev = 0; + for (int j = 0; j < m; j++) { + int temp = dp[j + 1]; + if (nums1[i] == nums2[j]) { + dp[j + 1] = 1 + prev; + } else { + dp[j + 1] = max(dp[j + 1], dp[j]); + } + prev = temp; + } + } + + return dp[m]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @return {number} + */ + maxUncrossedLines(nums1, nums2) { + let n = nums1.length, m = nums2.length; + if (m > n) { + [nums1, nums2] = [nums2, nums1]; + [n, m] = [m, n]; + } + + const dp = Array(m + 1).fill(0); + + for (let i = 0; i < n; i++) { + let prev = 0; + for (let j = 0; j < m; j++) { + const temp = dp[j + 1]; + if (nums1[i] === nums2[j]) { + dp[j + 1] = 1 + prev; + } else { + dp[j + 1] = Math.max(dp[j + 1], dp[j]); + } + prev = temp; + } + } + + return dp[m]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * m)$ +* Space complexity: $O(min(n, m))$ + +> Where $n$ and $m$ are the sizes of the arrays $nums1$ and $nums2$ respectively. \ No newline at end of file diff --git a/articles/unique-paths-ii.md b/articles/unique-paths-ii.md new file mode 100644 index 000000000..35178ff44 --- /dev/null +++ b/articles/unique-paths-ii.md @@ -0,0 +1,481 @@ +## 1. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def uniquePathsWithObstacles(self, grid: List[List[int]]) -> int: + M, N = len(grid), len(grid[0]) + dp = {(M - 1, N - 1): 1} + + def dfs(r, c): + if r == M or c == N or grid[r][c]: + return 0 + if (r, c) in dp: + return dp[(r, c)] + dp[(r, c)] = dfs(r + 1, c) + dfs(r, c + 1) + return dp[(r, c)] + + return dfs(0, 0) +``` + +```java +public class Solution { + private int[][] dp; + + public int uniquePathsWithObstacles(int[][] grid) { + int M = grid.length, N = grid[0].length; + dp = new int[M][N]; + for (int i = 0; i < M; i++) { + for (int j = 0; j < N; j++) { + dp[i][j] = -1; + } + } + return dfs(0, 0, grid, M, N); + } + + private int dfs(int r, int c, int[][] grid, int M, int N) { + if (r == M || c == N || grid[r][c] == 1) { + return 0; + } + if (r == M - 1 && c == N - 1) { + return 1; + } + if (dp[r][c] != -1) { + return dp[r][c]; + } + dp[r][c] = dfs(r + 1, c, grid, M, N) + dfs(r, c + 1, grid, M, N); + return dp[r][c]; + } +} +``` + +```cpp +class Solution { +private: + vector> dp; + +public: + int uniquePathsWithObstacles(vector>& grid) { + int M = grid.size(), N = grid[0].size(); + dp.resize(M, vector(N, -1)); + return dfs(0, 0, grid, M, N); + } + +private: + int dfs(int r, int c, vector>& grid, int M, int N) { + if (r == M || c == N || grid[r][c] == 1) { + return 0; + } + if (r == M - 1 && c == N - 1) { + return 1; + } + if (dp[r][c] != -1) { + return dp[r][c]; + } + dp[r][c] = dfs(r + 1, c, grid, M, N) + dfs(r, c + 1, grid, M, N); + return dp[r][c]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + uniquePathsWithObstacles(grid) { + const M = grid.length, N = grid[0].length; + const dp = Array.from({ length: M }, () => Array(N).fill(-1)); + + const dfs = (r, c) => { + if (r === M || c === N || grid[r][c] === 1) { + return 0; + } + if (r === M - 1 && c === N - 1) { + return 1; + } + if (dp[r][c] !== -1) { + return dp[r][c]; + } + dp[r][c] = dfs(r + 1, c) + dfs(r, c + 1); + return dp[r][c]; + }; + + return dfs(0, 0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * n)$ +* Space complexity: $O(m * n)$ + +> Where $m$ is the number of rows and $n$ is the number of columns. + +--- + +## 2. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def uniquePathsWithObstacles(self, grid: List[List[int]]) -> int: + M, N = len(grid), len(grid[0]) + if grid[0][0] == 1 or grid[M - 1][N - 1] == 1: + return 0 + dp = [[0] * (N + 1) for _ in range(M + 1)] + + + dp[M - 1][N - 1] = 1 + + for r in range(M - 1, -1, -1): + for c in range(N - 1, -1, -1): + if grid[r][c] == 1: + dp[r][c] = 0 + else: + dp[r][c] += dp[r + 1][c] + dp[r][c] += dp[r][c + 1] + + return dp[0][0] +``` + +```java +public class Solution { + public int uniquePathsWithObstacles(int[][] grid) { + int M = grid.length, N = grid[0].length; + if (grid[0][0] == 1 || grid[M - 1][N - 1] == 1) { + return 0; + } + + int[][] dp = new int[M + 1][N + 1]; + dp[M - 1][N - 1] = 1; + + for (int r = M - 1; r >= 0; r--) { + for (int c = N - 1; c >= 0; c--) { + if (grid[r][c] == 1) { + dp[r][c] = 0; + } else { + dp[r][c] += dp[r + 1][c]; + dp[r][c] += dp[r][c + 1]; + } + } + } + + return dp[0][0]; + } +} +``` + +```cpp +class Solution { +public: + int uniquePathsWithObstacles(vector>& grid) { + int M = grid.size(), N = grid[0].size(); + if (grid[0][0] == 1 || grid[M - 1][N - 1] == 1) { + return 0; + } + + vector> dp(M + 1, vector(N + 1, 0)); + dp[M - 1][N - 1] = 1; + + for (int r = M - 1; r >= 0; r--) { + for (int c = N - 1; c >= 0; c--) { + if (grid[r][c] == 1) { + dp[r][c] = 0; + } else { + dp[r][c] += dp[r + 1][c]; + dp[r][c] += dp[r][c + 1]; + } + } + } + + return dp[0][0]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + uniquePathsWithObstacles(grid) { + const M = grid.length, N = grid[0].length; + if (grid[0][0] === 1 || grid[M - 1][N - 1] === 1) { + return 0; + } + + const dp = Array.from({ length: M + 1 }, () => Array(N + 1).fill(0)); + dp[M - 1][N - 1] = 1; + + for (let r = M - 1; r >= 0; r--) { + for (let c = N - 1; c >= 0; c--) { + if (grid[r][c] === 1) { + dp[r][c] = 0; + } else { + dp[r][c] += dp[r + 1][c]; + dp[r][c] += dp[r][c + 1]; + } + } + } + + return dp[0][0]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * n)$ +* Space complexity: $O(m * n)$ + +> Where $m$ is the number of rows and $n$ is the number of columns. + +--- + +## 3. Dynamic Programming (Space Optimized) + +::tabs-start + +```python +class Solution: + def uniquePathsWithObstacles(self, grid: List[List[int]]) -> int: + M, N = len(grid), len(grid[0]) + dp = [0] * (N + 1) + dp[N - 1] = 1 + + for r in range(M - 1, -1, -1): + for c in range(N - 1, -1, -1): + if grid[r][c]: + dp[c] = 0 + else: + dp[c] += dp[c + 1] + + return dp[0] +``` + +```java +public class Solution { + public int uniquePathsWithObstacles(int[][] grid) { + int M = grid.length, N = grid[0].length; + int[] dp = new int[N + 1]; + dp[N - 1] = 1; + + for (int r = M - 1; r >= 0; r--) { + for (int c = N - 1; c >= 0; c--) { + if (grid[r][c] == 1) { + dp[c] = 0; + } else { + dp[c] += dp[c + 1]; + } + } + } + + return dp[0]; + } +} +``` + +```cpp +class Solution { +public: + int uniquePathsWithObstacles(vector>& grid) { + int M = grid.size(), N = grid[0].size(); + vector dp(N + 1, 0); + dp[N - 1] = 1; + + for (int r = M - 1; r >= 0; r--) { + for (int c = N - 1; c >= 0; c--) { + if (grid[r][c] == 1) { + dp[c] = 0; + } else { + dp[c] += dp[c + 1]; + } + } + } + + return dp[0]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + uniquePathsWithObstacles(grid) { + const M = grid.length, N = grid[0].length; + const dp = new Array(N + 1).fill(0); + dp[N - 1] = 1; + + for (let r = M - 1; r >= 0; r--) { + for (let c = N - 1; c >= 0; c--) { + if (grid[r][c] === 1) { + dp[c] = 0; + } else { + dp[c] += dp[c + 1]; + } + } + } + + return dp[0]; + } +} +``` + +::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. + +--- + +## 4. Dynamic Programming (In-Place) + +::tabs-start + +```python +class Solution: + def uniquePathsWithObstacles(self, grid: List[List[int]]) -> int: + M, N = len(grid), len(grid[0]) + if grid[0][0] == 1 or grid[M - 1][N - 1] == 1: + return 0 + + grid[M - 1][N - 1] = 1 + + for r in range(M - 1, -1, -1): + for c in range(N - 1, -1, -1): + if r == M - 1 and c == N - 1: + continue + + if grid[r][c] == 1: + grid[r][c] = 0 + else: + down = grid[r + 1][c] if r + 1 < M else 0 + right = grid[r][c + 1] if c + 1 < N else 0 + grid[r][c] = down + right + + return grid[0][0] +``` + +```java +public class Solution { + public int uniquePathsWithObstacles(int[][] grid) { + int M = grid.length, N = grid[0].length; + if (grid[0][0] == 1 || grid[M - 1][N - 1] == 1) { + return 0; + } + + grid[M - 1][N - 1] = 1; + + for (int r = M - 1; r >= 0; r--) { + for (int c = N - 1; c >= 0; c--) { + if (r == M - 1 && c == N - 1) { + continue; + } + + if (grid[r][c] == 1) { + grid[r][c] = 0; + } else { + int down = (r + 1 < M) ? grid[r + 1][c] : 0; + int right = (c + 1 < N) ? grid[r][c + 1] : 0; + grid[r][c] = down + right; + } + } + } + + return grid[0][0]; + } +} +``` + +```cpp +class Solution { +public: + int uniquePathsWithObstacles(vector>& grid) { + int M = grid.size(), N = grid[0].size(); + if (grid[0][0] == 1 || grid[M - 1][N - 1] == 1) { + return 0; + } + + grid[M - 1][N - 1] = 1; + + for (int r = M - 1; r >= 0; r--) { + for (int c = N - 1; c >= 0; c--) { + if (r == M - 1 && c == N - 1) { + continue; + } + + if (grid[r][c] == 1) { + grid[r][c] = 0; + } else { + uint down = (r + 1 < M) ? grid[r + 1][c] : 0; + uint right = (c + 1 < N) ? grid[r][c + 1] : 0; + grid[r][c] = down + right; + } + } + } + + return grid[0][0]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + uniquePathsWithObstacles(grid) { + const M = grid.length, N = grid[0].length; + if (grid[0][0] === 1 || grid[M - 1][N - 1] === 1) { + return 0; + } + + grid[M - 1][N - 1] = 1; + + for (let r = M - 1; r >= 0; r--) { + for (let c = N - 1; c >= 0; c--) { + if (r === M - 1 && c === N - 1) { + continue; + } + + if (grid[r][c] === 1) { + grid[r][c] = 0; + } else { + const down = (r + 1 < M) ? grid[r + 1][c] : 0; + const right = (c + 1 < N) ? grid[r][c + 1] : 0; + grid[r][c] = down + right; + } + } + } + + return grid[0][0]; + } +} +``` + +::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 pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy