Skip to content

feat: update solutions to lc problems: No.2189,2920 #3985

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,13 @@ tags:

我们注意到,每一层的卡片数量为 $3 \times k + 2$,并且每一层的卡片数量都不相同。因此,问题可以转化为:整数 $n$ 可以由多少种 $3 \times k + 2$ 的数相加得到。这是一个经典的背包问题,可以使用记忆化搜索解决。

我们设计一个函数 $dfs(n, k)$,表示当前剩余卡片数量为 $n$,且当前层为 $k$ 时,可以构建多少不同的纸牌屋。那么答案就是 $dfs(n, 0)$。
我们设计一个函数 $\text{dfs}(n, k)$,表示当前剩余卡片数量为 $n$,且当前层为 $k$ 时,可以构建多少不同的纸牌屋。那么答案就是 $\text{dfs}(n, 0)$。

函数 $dfs(n, k)$ 的执行逻辑如下:
函数 $\text{dfs}(n, k)$ 的执行逻辑如下:

- 如果 $3 \times k + 2 \gt n$,那么当前层无法放置任何卡片,返回 $0$;
- 如果 $3 \times k + 2 = n$,那么当前层可以放置卡片,放置完毕后,整个纸牌屋已经构建完毕,返回 $1$;
- 否则,我们可以选择不放置卡片,或者放置卡片。如果选择不放置卡片,那么剩余卡片数量不变,层数增加 $1$,即 $dfs(n, k + 1)$;如果选择放置卡片,那么剩余卡片数量减少 $3 \times k + 2$,层数增加 $1$,即 $dfs(n - (3 \times k + 2), k + 1)$。两者相加即为答案。
- 否则,我们可以选择不放置卡片,或者放置卡片。如果选择不放置卡片,那么剩余卡片数量不变,层数增加 $1$,即 $\text{dfs}(n, k + 1)$;如果选择放置卡片,那么剩余卡片数量减少 $3 \times k + 2$,层数增加 $1$,即 $\text{dfs}(n - (3 \times k + 2), k + 1)$。两者相加即为答案。

过程中,我们可以使用记忆化搜索,避免重复计算。

Expand Down Expand Up @@ -141,7 +141,7 @@ public:
int houseOfCards(int n) {
int f[n + 1][n / 3 + 1];
memset(f, -1, sizeof(f));
function<int(int, int)> dfs = [&](int n, int k) -> int {
auto dfs = [&](this auto&& dfs, int n, int k) -> int {
int x = 3 * k + 2;
if (x > n) {
return 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,21 @@ The third house of cards uses 2 cards.

<!-- solution:start -->

### Solution 1
### Solution 1: Memoization Search

We notice that the number of cards in each layer is $3 \times k + 2$, and the number of cards in each layer is different. Therefore, the problem can be transformed into: how many ways can the integer $n$ be expressed as the sum of numbers of the form $3 \times k + 2$. This is a classic knapsack problem that can be solved using memoization search.

We design a function $\text{dfs}(n, k)$, which represents the number of ways to build different houses of cards when the remaining number of cards is $n$ and the current layer is $k$. The answer is $\text{dfs}(n, 0)$.

The execution logic of the function $\text{dfs}(n, k)$ is as follows:

- If $3 \times k + 2 \gt n$, then the current layer cannot place any cards, return $0$;
- If $3 \times k + 2 = n$, then the current layer can place cards, and after placing them, the entire house of cards is completed, return $1$;
- Otherwise, we can choose not to place cards or to place cards. If we choose not to place cards, the remaining number of cards does not change, and the number of layers increases by $1$, i.e., $\text{dfs}(n, k + 1)$. If we choose to place cards, the remaining number of cards decreases by $3 \times k + 2$, and the number of layers increases by $1$, i.e., $\text{dfs}(n - (3 \times k + 2), k + 1)$. The sum of these two cases is the answer.

During the process, we can use memoization to avoid repeated calculations.

The time complexity is $O(n^2)$, and the space complexity is $O(n^2)$. Here, $n$ is the number of cards.

<!-- tabs:start -->

Expand Down Expand Up @@ -127,7 +141,7 @@ public:
int houseOfCards(int n) {
int f[n + 1][n / 3 + 1];
memset(f, -1, sizeof(f));
function<int(int, int)> dfs = [&](int n, int k) -> int {
auto dfs = [&](this auto&& dfs, int n, int k) -> int {
int x = 3 * k + 2;
if (x > n) {
return 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ class Solution {
int houseOfCards(int n) {
int f[n + 1][n / 3 + 1];
memset(f, -1, sizeof(f));
function<int(int, int)> dfs = [&](int n, int k) -> int {
auto dfs = [&](this auto&& dfs, int n, int k) -> int {
int x = 3 * k + 2;
if (x > n) {
return 0;
Expand All @@ -18,4 +18,4 @@ class Solution {
};
return dfs(n, 0);
}
};
};
4 changes: 2 additions & 2 deletions solution/2200-2299/2214.Minimum Health to Beat Game/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,9 @@ tags:

### 方法一:贪心

我们可以贪心地选择在伤害值最大的回合中使用一次护甲技能,假设伤害值最大为 $mx$,那么我们可以免受 $min(mx, armor)$ 的伤害,因此我们需要的最小生命值为 $sum(damage) - min(mx, armor) + 1$。
我们可以贪心地选择在伤害值最大的回合中使用一次护甲技能,假设伤害值最大为 $\textit{mx}$,那么我们可以免受 $\min(\textit{mx}, \textit{armor})$ 的伤害,因此我们需要的最小生命值为 $\sum(\textit{damage}) - \min(\textit{mx}, \textit{armor}) + 1$。

时间复杂度 $O(n)$,其中 $n$ 为数组 `damage` 的长度。空间复杂度 $O(1)$。
时间复杂度 $O(n)$,其中 $n$ 为数组 $\textit{damage}$ 的长度。空间复杂度 $O(1)$。

<!-- tabs:start -->

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,9 @@ Note that you did not use your armor ability.

### Solution 1: Greedy

We can greedily choose to use the armor skill in the round with the maximum damage. Suppose the maximum damage is $mx$, then we can avoid $min(mx, armor)$ damage, so the minimum life value we need is $sum(damage) - min(mx, armor) + 1$.
We can greedily choose to use the armor skill in the round with the highest damage. Suppose the maximum damage is $\textit{mx}$, then we can avoid $\min(\textit{mx}, \textit{armor})$ damage. Therefore, the minimum health required is $\sum(\textit{damage}) - \min(\textit{mx}, \textit{armor}) + 1$.

The time complexity is $O(n)$, where $n$ is the length of the `damage` array. The space complexity is $O(1)$.
The time complexity is $O(n)$, where $n$ is the length of the array $\textit{damage}$. The space complexity is $O(1)$.

<!-- tabs:start -->

Expand Down
30 changes: 3 additions & 27 deletions solution/2200-2299/2243.Calculate Digit Sum of a String/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@ tags:
<strong>输出:</strong>"135"
<strong>解释:</strong>
- 第一轮,将 s 分成:"111"、"112"、"222" 和 "23" 。
接着,计算每一组的数字和:1 + 1 + 1 = 3、1 + 1 + 2 = 4、2 + 2 + 2 = 6 和 2 + 3 = 5 。
接着,计算每一组的数字和:1 + 1 + 1 = 3、1 + 1 + 2 = 4、2 + 2 + 2 = 6 和 2 + 3 = 5 。
&nbsp; 这样,s 在第一轮之后变成 "3" + "4" + "6" + "5" = "3465" 。
- 第二轮,将 s 分成:"346" 和 "5" 。
&nbsp; 接着,计算每一组的数字和:3 + 4 + 6 = 13 、5 = 5 。
&nbsp; 这样,s 在第二轮之后变成 "13" + "5" = "135" 。
&nbsp; 这样,s 在第二轮之后变成 "13" + "5" = "135" 。
现在,s.length &lt;= k ,所以返回 "135" 作为答案。
</pre>

Expand All @@ -53,7 +53,7 @@ tags:
<strong>输出:</strong>"000"
<strong>解释:</strong>
将 "000", "000", and "00".
接着,计算每一组的数字和:0 + 0 + 0 = 0 、0 + 0 + 0 = 0 和 0 + 0 = 0 。
接着,计算每一组的数字和:0 + 0 + 0 = 0 、0 + 0 + 0 = 0 和 0 + 0 = 0 。
s 变为 "0" + "0" + "0" = "000" ,其长度等于 k ,所以返回 "000" 。
</pre>

Expand Down Expand Up @@ -184,28 +184,4 @@ function digitSum(s: string, k: number): string {

<!-- solution:end -->

<!-- solution:start -->

### 方法二

<!-- tabs:start -->

#### Python3

```python
class Solution:
def digitSum(self, s: str, k: int) -> str:
if len(s) <= k:
return s
t = []
while s:
t.append(str(sum(int(v) for v in s[:k])))
s = s[k:]
return self.digitSum(''.join(t), k)
```

<!-- tabs:end -->

<!-- solution:end -->

<!-- problem:end -->
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@ tags:
<pre>
<strong>Input:</strong> s = &quot;11111222223&quot;, k = 3
<strong>Output:</strong> &quot;135&quot;
<strong>Explanation:</strong>
<strong>Explanation:</strong>
- For the first round, we divide s into groups of size 3: &quot;111&quot;, &quot;112&quot;, &quot;222&quot;, and &quot;23&quot;.
​​​​​Then we calculate the digit sum of each group: 1 + 1 + 1 = 3, 1 + 1 + 2 = 4, 2 + 2 + 2 = 6, and 2 + 3 = 5.
​​​​​Then we calculate the digit sum of each group: 1 + 1 + 1 = 3, 1 + 1 + 2 = 4, 2 + 2 + 2 = 6, and 2 + 3 = 5.
&nbsp; So, s becomes &quot;3&quot; + &quot;4&quot; + &quot;6&quot; + &quot;5&quot; = &quot;3465&quot; after the first round.
- For the second round, we divide s into &quot;346&quot; and &quot;5&quot;.
&nbsp; Then we calculate the digit sum of each group: 3 + 4 + 6 = 13, 5 = 5.
&nbsp; So, s becomes &quot;13&quot; + &quot;5&quot; = &quot;135&quot; after second round.
&nbsp; Then we calculate the digit sum of each group: 3 + 4 + 6 = 13, 5 = 5.
&nbsp; So, s becomes &quot;13&quot; + &quot;5&quot; = &quot;135&quot; after second round.
Now, s.length &lt;= k, so we return &quot;135&quot; as the answer.
</pre>

Expand All @@ -52,9 +52,9 @@ Now, s.length &lt;= k, so we return &quot;135&quot; as the answer.
<pre>
<strong>Input:</strong> s = &quot;00000000&quot;, k = 3
<strong>Output:</strong> &quot;000&quot;
<strong>Explanation:</strong>
<strong>Explanation:</strong>
We divide s into &quot;000&quot;, &quot;000&quot;, and &quot;00&quot;.
Then we calculate the digit sum of each group: 0 + 0 + 0 = 0, 0 + 0 + 0 = 0, and 0 + 0 = 0.
Then we calculate the digit sum of each group: 0 + 0 + 0 = 0, 0 + 0 + 0 = 0, and 0 + 0 = 0.
s becomes &quot;0&quot; + &quot;0&quot; + &quot;0&quot; = &quot;000&quot;, whose length is equal to k, so we return &quot;000&quot;.
</pre>

Expand Down Expand Up @@ -180,28 +180,4 @@ function digitSum(s: string, k: number): string {

<!-- solution:end -->

<!-- solution:start -->

### Solution 2

<!-- tabs:start -->

#### Python3

```python
class Solution:
def digitSum(self, s: str, k: int) -> str:
if len(s) <= k:
return s
t = []
while s:
t.append(str(sum(int(v) for v in s[:k])))
s = s[k:]
return self.digitSum(''.join(t), k)
```

<!-- tabs:end -->

<!-- solution:end -->

<!-- problem:end -->

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,13 @@ tags:
<img alt="" src="https://fastly.jsdelivr.net/gh/doocs/leetcode@main/solution/2900-2999/2920.Maximum%20Points%20After%20Collecting%20Coins%20From%20All%20Nodes/images/ex1-copy.png" style="width: 60px; height: 316px; padding: 10px; background: rgb(255, 255, 255); border-radius: 0.5rem;" />
<pre>
<strong>输入:</strong>edges = [[0,1],[1,2],[2,3]], coins = [10,10,3,3], k = 5
<strong>输出:</strong>11
<strong>输出:</strong>11
<strong>解释:</strong>
使用第一种方法收集节点 0 上的所有金币。总积分 = 10 - 5 = 5 。
使用第一种方法收集节点 1 上的所有金币。总积分 = 5 + (10 - 5) = 10 。
使用第二种方法收集节点 2 上的所有金币。所以节点 3 上的金币将会变为 floor(3 / 2) = 1 ,总积分 = 10 + floor(3 / 2) = 11 。
使用第二种方法收集节点 3 上的所有金币。总积分 = 11 + floor(1 / 2) = 11.
可以证明收集所有节点上的金币能获得的最大积分是 11 。
可以证明收集所有节点上的金币能获得的最大积分是 11 。
</pre>

<p><strong class="example">示例 2:</strong></p>
Expand Down Expand Up @@ -93,8 +93,7 @@ tags:

最后,我们返回当前节点使用两种方法中能获得的最大积分。

为了避免重复计算,我们使用记忆化搜索的方法,将 $dfs(i, fa, j)$ 的结果存储到 $f[i][j]$ 中,其中 $f[i][j]$ 表示当前节点为 $i$,父节点为 $fa$,当前节点的金币数需要右移 $j$ 位,所能获得的最大积分。

为了避免重复计算,我们使用记忆化搜索的方法,将 $dfs(i, fa, j)$ 的结果存储到 $f[i][j]$ 中,其中 $f[i][j]$ 表示当前节点为 $i$,父节点为 $fa$,当前节点的金币数需要右移 $j$ 位,所能获得的最大
时间复杂度 $O(n \times \log M)$,空间复杂度 $O(n \times \log M)$。其中 $M$ 表示 $coins[i]$ 的最大值。

<!-- tabs:start -->
Expand Down Expand Up @@ -183,7 +182,7 @@ public:
g[a].emplace_back(b);
g[b].emplace_back(a);
}
function<int(int, int, int)> dfs = [&](int i, int fa, int j) {
auto dfs = [&](this auto&& dfs, int i, int fa, int j) -> int {
if (f[i][j] != -1) {
return f[i][j];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,13 @@ tags:
<img alt="" src="https://fastly.jsdelivr.net/gh/doocs/leetcode@main/solution/2900-2999/2920.Maximum%20Points%20After%20Collecting%20Coins%20From%20All%20Nodes/images/ex1-copy.png" style="width: 60px; height: 316px; padding: 10px; background: rgb(255, 255, 255); border-radius: 0.5rem;" />
<pre>
<strong>Input:</strong> edges = [[0,1],[1,2],[2,3]], coins = [10,10,3,3], k = 5
<strong>Output:</strong> 11
<strong>Explanation:</strong>
<strong>Output:</strong> 11
<strong>Explanation:</strong>
Collect all the coins from node 0 using the first way. Total points = 10 - 5 = 5.
Collect all the coins from node 1 using the first way. Total points = 5 + (10 - 5) = 10.
Collect all the coins from node 2 using the second way so coins left at node 3 will be floor(3 / 2) = 1. Total points = 10 + floor(3 / 2) = 11.
Collect all the coins from node 3 using the second way. Total points = 11 + floor(1 / 2) = 11.
It can be shown that the maximum points we can get after collecting coins from all the nodes is 11.
It can be shown that the maximum points we can get after collecting coins from all the nodes is 11.
</pre>

<p><strong class="example">Example 2:</strong></p>
Expand All @@ -55,7 +55,7 @@ It can be shown that the maximum points we can get after collecting coins from a
<pre>
<strong>Input:</strong> edges = [[0,1],[0,2]], coins = [8,4,4], k = 0
<strong>Output:</strong> 16
<strong>Explanation:</strong>
<strong>Explanation:</strong>
Coins will be collected from all the nodes using the first way. Therefore, total points = (8 - 0) + (4 - 0) + (4 - 0) = 16.
</pre>

Expand Down Expand Up @@ -181,7 +181,7 @@ public:
g[a].emplace_back(b);
g[b].emplace_back(a);
}
function<int(int, int, int)> dfs = [&](int i, int fa, int j) {
auto dfs = [&](this auto&& dfs, int i, int fa, int j) -> int {
if (f[i][j] != -1) {
return f[i][j];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class Solution {
g[a].emplace_back(b);
g[b].emplace_back(a);
}
function<int(int, int, int)> dfs = [&](int i, int fa, int j) {
auto dfs = [&](this auto&& dfs, int i, int fa, int j) -> int {
if (f[i][j] != -1) {
return f[i][j];
}
Expand All @@ -28,4 +28,4 @@ class Solution {
};
return dfs(0, -1, 0);
}
};
};
Loading