Skip to content
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

feat: add solutions to lc problems #2031

Merged
merged 1 commit into from
Nov 29, 2023
Merged
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
20 changes: 19 additions & 1 deletion solution/0000-0099/0039.Combination Sum/README_EN.md
Original file line number Diff line number Diff line change
@@ -48,7 +48,25 @@ These are the only two combinations.

## Solutions

DFS.
**Solution 1: Sorting + Pruning + Backtracking (Two Implementations)**

We can first sort the array to facilitate pruning.

Next, we design a function $dfs(i, s)$, which means starting the search from index $i$ with a remaining target value of $s$. Here, $i$ and $s$ are both non-negative integers, the current search path is $t$, and the answer is $ans$.

In the function $dfs(i, s)$, we first check whether $s$ is $0$. If it is, we add the current search path $t$ to the answer $ans$, and then return. If $s \lt candidates[i]$, it means that the elements of the current index and the following indices are all greater than the remaining target value $s$, and the path is invalid, so we return directly. Otherwise, we start the search from index $i$, and the search index range is $j \in [i, n)$, where $n$ is the length of the array $candidates$. During the search, we add the element of the current index to the search path $t$, recursively call the function $dfs(j, s - candidates[j])$, and after the recursion ends, we remove the element of the current index from the search path $t$.

We can also change the implementation logic of the function $dfs(i, s)$ to another form. In the function $dfs(i, s)$, we first check whether $s$ is $0$. If it is, we add the current search path $t$ to the answer $ans$, and then return. If $i \geq n$ or $s \lt candidates[i]$, the path is invalid, so we return directly. Otherwise, we consider two situations, one is not selecting the element of the current index, that is, recursively calling the function $dfs(i + 1, s)$, and the other is selecting the element of the current index, that is, recursively calling the function $dfs(i, s - candidates[i])$.

In the main function, we just need to call the function $dfs(0, target)$ to get the answer.

The time complexity is $O(2^n \times n)$, and the space complexity is $O(n)$. Here, $n$ is the length of the array $candidates$. Due to pruning, the actual time complexity is much less than $O(2^n \times n)$.

Similar problems:

- [40. Combination Sum II](/solution/0000-0099/0040.Combination%20Sum%20II/README_EN.md)
- [77. Combinations](/solution/0000-0099/0077.Combinations/README_EN.md)
- [216. Combination Sum III](/solution/0200-0299/0216.Combination%20Sum%20III/README_EN.md)

<!-- tabs:start -->

20 changes: 19 additions & 1 deletion solution/0000-0099/0040.Combination Sum II/README_EN.md
Original file line number Diff line number Diff line change
@@ -46,7 +46,25 @@

## Solutions

DFS.
**Solution 1: Sorting + Pruning + Backtracking (Two Implementations)**

We can first sort the array to facilitate pruning and skipping duplicate numbers.

Next, we design a function $dfs(i, s)$, which means starting the search from index $i$ with a remaining target value of $s$. Here, $i$ and $s$ are both non-negative integers, the current search path is $t$, and the answer is $ans$.

In the function $dfs(i, s)$, we first check whether $s$ is $0$. If it is, we add the current search path $t$ to the answer $ans$, and then return. If $i \geq n$ or $s \lt candidates[i]$, the path is invalid, so we return directly. Otherwise, we start the search from index $i$, and the search index range is $j \in [i, n)$, where $n$ is the length of the array $candidates$. During the search, if $j \gt i$ and $candidates[j] = candidates[j - 1]$, it means that the current number is the same as the previous number, we can skip the current number because the previous number has been searched. Otherwise, we add the current number to the search path $t$, recursively call the function $dfs(j + 1, s - candidates[j])$, and after the recursion ends, we remove the current number from the search path $t$.

We can also change the implementation logic of the function $dfs(i, s)$ to another form. If we choose the current number, we add the current number to the search path $t$, then recursively call the function $dfs(i + 1, s - candidates[i])$, and after the recursion ends, we remove the current number from the search path $t$. If we do not choose the current number, we can skip all numbers that are the same as the current number, then recursively call the function $dfs(j, s)$, where $j$ is the index of the first number that is different from the current number.

In the main function, we just need to call the function $dfs(0, target)$ to get the answer.

The time complexity is $O(2^n \times n)$, and the space complexity is $O(n)$. Here, $n$ is the length of the array $candidates$. Due to pruning, the actual time complexity is much less than $O(2^n \times n)$.

Similar problems:

- [39. Combination Sum](/solution/0000-0099/0039.Combination%20Sum/README_EN.md)
- [77. Combinations](/solution/0000-0099/0077.Combinations/README_EN.md)
- [216. Combination Sum III](/solution/0200-0299/0216.Combination%20Sum%20III/README_EN.md)

<!-- tabs:start -->

4 changes: 2 additions & 2 deletions solution/0000-0099/0041.First Missing Positive/README.md
Original file line number Diff line number Diff line change
@@ -47,11 +47,11 @@

**方法一:原地交换**

我们假设数组 `nums` 长度为 $n$,那么最小的正整数一定在 $[1, .., n + 1]$ 之间。我们可以遍历数组,将数组中的每个数 $x$ 交换到它应该在的位置上,即 $x$ 应该在的位置为 $x - 1$。如果 $x$ 不在 $[1, n + 1]$ 之间,那么我们就不用管它。
我们假设数组 $nums$ 长度为 $n$,那么最小的正整数一定在 $[1, .., n + 1]$ 之间。我们可以遍历数组,将数组中的每个数 $x$ 交换到它应该在的位置上,即 $x$ 应该在的位置为 $x - 1$。如果 $x$ 不在 $[1, n + 1]$ 之间,那么我们就不用管它。

遍历结束后,我们再遍历数组,如果 $i+1$ 不等于 $nums[i]$,那么 $i+1$ 就是我们要找的最小的正整数。

时间复杂度 $O(n)$,空间复杂度 $O(1)$。
时间复杂度 $O(n)$,其中 $n$ 是数组的长度。空间复杂度 $O(1)$。

<!-- tabs:start -->

8 changes: 8 additions & 0 deletions solution/0000-0099/0041.First Missing Positive/README_EN.md
Original file line number Diff line number Diff line change
@@ -43,6 +43,14 @@

## Solutions

**Solution 1: In-place Swap**

We assume the length of the array $nums$ is $n$, then the smallest positive integer must be in the range $[1, .., n + 1]$. We can traverse the array and swap each number $x$ to its correct position, that is, the position $x - 1$. If $x$ is not in the range $[1, n + 1]$, then we can ignore it.

After the traversal, we traverse the array again. If $i+1$ is not equal to $nums[i]$, then $i+1$ is the smallest positive integer we are looking for.

The time complexity is $O(n)$, where $n$ is the length of the array. The space complexity is $O(1)$.

<!-- tabs:start -->

### **Python3**
2 changes: 1 addition & 1 deletion solution/0000-0099/0042.Trapping Rain Water/README.md
Original file line number Diff line number Diff line change
@@ -43,7 +43,7 @@

**方法一:动态规划**

我们定义 $left[i]$ 表示下标 $i$ 位置及其左边的最高柱子的高度,定义 $right[i]$ 表示下标 $i$ 位置及其右边的最高柱子的高度。那么下标 $i$ 位置能接的雨水量为 $min(left[i], right[i]) - height[i]$。我们遍历数组,计算出 $left[i]$ 和 $right[i]$,最后答案为 $\sum_{i=0}^{n-1} min(left[i], right[i]) - height[i]$。
我们定义 $left[i]$ 表示下标 $i$ 位置及其左边的最高柱子的高度,定义 $right[i]$ 表示下标 $i$ 位置及其右边的最高柱子的高度。那么下标 $i$ 位置能接的雨水量为 $\min(left[i], right[i]) - height[i]$。我们遍历数组,计算出 $left[i]$ 和 $right[i]$,最后答案为 $\sum_{i=0}^{n-1} min(left[i], right[i]) - height[i]$。

时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 为数组的长度。

4 changes: 2 additions & 2 deletions solution/0000-0099/0042.Trapping Rain Water/README_EN.md
Original file line number Diff line number Diff line change
@@ -35,9 +35,9 @@

**Solution 1: Dynamic Programming**

We define $left[i]$ as the height of the highest pillar to the left of and including the position with index $i$, and define $right[i]$ as the height of the highest pillar to the right of and including the position with index $i$. Then the amount of rain water that can be trapped at the position with index $i$ is $min(left[i], right[i]) - height[i]$. We traverse the array, calculate $left[i]$ and $right[i]$, and the answer is $\sum_{i=0}^{n-1} min(left[i], right[i]) - height[i]$.
We define $left[i]$ as the height of the highest bar to the left of and including the position at index $i$, and $right[i]$ as the height of the highest bar to the right of and including the position at index $i$. Therefore, the amount of rainwater that can be trapped at index $i$ is $min(left[i], right[i]) - height[i]$. We traverse the array to calculate $left[i]$ and $right[i]$, and the final answer is $\sum_{i=0}^{n-1} min(left[i], right[i]) - height[i]$.

The time complexity is $O(n)$, and the space complexity is $O(n)$, where $n$ is the length of the array.
The time complexity is $O(n)$, and the space complexity is $O(n)$. Here, $n$ is the length of the array.

<!-- tabs:start -->

8 changes: 4 additions & 4 deletions solution/0000-0099/0043.Multiply Strings/README.md
Original file line number Diff line number Diff line change
@@ -40,20 +40,20 @@

**方法一:数学乘法模拟**

假设 `num1``num2` 的长度分别为 $m$ 和 $n$,则它们的乘积的长度最多为 $m + n$。
假设 $num1$$num2$ 的长度分别为 $m$ 和 $n$,则它们的乘积的长度最多为 $m + n$。

证明如下:

- 如果 `num1``num2` 都取最小值,那么它们的乘积为 ${10}^{m - 1} \times {10}^{n - 1} = {10}^{m + n - 2}$,长度为 $m + n - 1$。
- 如果 `num1``num2` 都取最大值,那么它们的乘积为 $({10}^m - 1) \times ({10}^n - 1) = {10}^{m + n} - {10}^m - {10}^n + 1$,长度为 $m + n$。
- 如果 $num1$$num2$ 都取最小值,那么它们的乘积为 ${10}^{m - 1} \times {10}^{n - 1} = {10}^{m + n - 2}$,长度为 $m + n - 1$。
- 如果 $num1$$num2$ 都取最大值,那么它们的乘积为 $({10}^m - 1) \times ({10}^n - 1) = {10}^{m + n} - {10}^m - {10}^n + 1$,长度为 $m + n$。

因此,我们可以申请一个长度为 $m + n$ 的数组,用于存储乘积的每一位。

从低位到高位,依次计算乘积的每一位,最后将数组转换为字符串即可。

注意判断最高位是否为 $0$,如果是,则去掉。

时间复杂度 $O(m \times n)$,空间复杂度 $O(m + n)$。其中 $m$ 和 $n$ 分别为 `num1``num2` 的长度。
时间复杂度 $O(m \times n)$,空间复杂度 $O(m + n)$。其中 $m$ 和 $n$ 分别为 $num1$$num2$ 的长度。

<!-- tabs:start -->

17 changes: 17 additions & 0 deletions solution/0000-0099/0043.Multiply Strings/README_EN.md
Original file line number Diff line number Diff line change
@@ -27,6 +27,23 @@

## Solutions

**Solution 1: Simulating Mathematical Multiplication**

Assume the lengths of $num1$ and $num2$ are $m$ and $n$ respectively, then the length of their product can be at most $m + n$.

The proof is as follows:

- If $num1$ and $num2$ both take the minimum value, then their product is ${10}^{m - 1} \times {10}^{n - 1} = {10}^{m + n - 2}$, with a length of $m + n - 1$.
- If $num1$ and $num2$ both take the maximum value, then their product is $({10}^m - 1) \times ({10}^n - 1) = {10}^{m + n} - {10}^m - {10}^n + 1$, with a length of $m + n$.

Therefore, we can apply for an array of length $m + n$ to store each digit of the product.

From the least significant digit to the most significant digit, we calculate each digit of the product in turn, and finally convert the array into a string.

Note to check whether the most significant digit is $0$, if it is, remove it.

The time complexity is $O(m \times n)$, and the space complexity is $O(m + n)$. Here, $m$ and $n$ are the lengths of $num1$ and $num2$ respectively.

<!-- tabs:start -->

### **Python3**
4 changes: 2 additions & 2 deletions solution/0000-0099/0044.Wildcard Matching/README.md
Original file line number Diff line number Diff line change
@@ -60,7 +60,7 @@

**方法一:动态规划**

定义状态 $dp[i][j]$ 表示 $s$ 的前 $i$ 个字符和 $p$ 的前 $j$ 个字符是否匹配。
我们定义状态 $dp[i][j]$ 表示 $s$ 的前 $i$ 个字符和 $p$ 的前 $j$ 个字符是否匹配。

状态转移方程如下:

@@ -73,7 +73,7 @@ dp[i-1][j-1] \lor dp[i-1][j] \lor dp[i][j-1] & \text{if } p[j-1]=\text{*} \\
\end{cases}
$$

时间复杂度 $O(m\times n)$,空间复杂度 $O(m\times n)$。
时间复杂度 $O(m \times n)$,空间复杂度 $O(m \times n)$。其中 $m$ 和 $n$ 分别为 $s$ 和 $p$ 的长度

<!-- tabs:start -->

17 changes: 17 additions & 0 deletions solution/0000-0099/0044.Wildcard Matching/README_EN.md
Original file line number Diff line number Diff line change
@@ -49,6 +49,23 @@

## Solutions

**Solution 1: Dynamic Programming**

We define the state $dp[i][j]$ to represent whether the first $i$ characters of $s$ match the first $j$ characters of $p$.

The state transition equation is as follows:

$$
dp[i][j]=
\begin{cases}
dp[i-1][j-1] & \text{if } s[i-1]=p[j-1] \text{ or } p[j-1]=\text{?} \\
dp[i-1][j-1] \lor dp[i-1][j] \lor dp[i][j-1] & \text{if } p[j-1]=\text{*} \\
\text{false} & \text{otherwise}
\end{cases}
$$

The time complexity is $O(m \times n)$, and the space complexity is $O(m \times n)$. Here, $m$ and $n$ are the lengths of $s$ and $p$ respectively.

<!-- tabs:start -->

### **Python3**
14 changes: 10 additions & 4 deletions solution/0000-0099/0045.Jump Game II/README_EN.md
Original file line number Diff line number Diff line change
@@ -42,15 +42,21 @@

## Solutions

**Solution 1: Greedy**
**Solution 1: Greedy Algorithm**

We can use a variable $mx$ to record the furthest position that can be reached at the current position, and use a variable $last$ to record the last jump position, and use a variable $ans$ to record the number of jumps.
We can use a variable $mx$ to record the farthest position that can be reached from the current position, a variable $last$ to record the position of the last jump, and a variable $ans$ to record the number of jumps.

Next, we traverse the position $i$ of the array $[0,..n - 2]$, and for each position $i$, we can calculate the furthest position that can be reached at the current position through $i + nums[i]$, and we use $mx$ to record this furthest position, that is, $mx = max(mx, i + nums[i])$. Next, we need to determine whether the current position has reached the boundary of the last jump, that is, $i = last$. If so, we need to jump once, update $last$ to $mx$, and increase the number of jumps $ans$ by $1$.
Next, we traverse each position $i$ in $[0,..n - 2]$. For each position $i$, we can calculate the farthest position that can be reached from the current position through $i + nums[i]$. We use $mx$ to record this farthest position, that is, $mx = max(mx, i + nums[i])$. Then, we check whether the current position has reached the boundary of the last jump, that is, $i = last$. If it has reached, then we need to make a jump, update $last$ to $mx$, and increase the number of jumps $ans$ by $1$.

Finally, we return the number of jumps $ans$.

The time complexity is $O(n)$, where $n$ is the length of the array. The space complexity $O(1)$.
The time complexity is $O(n)$, where $n$ is the length of the array. The space complexity is $O(1)$.

Similar problems:

- [55. Jump Game](/solution/0000-0099/0055.Jump%20Game/README_EN.md)
- [1024. Video Stitching](/solution/1000-1099/1024.Video%20Stitching/README_EN.md)
- [1326. Minimum Number of Taps to Open to Water a Garden](/solution/1300-1399/1326.Minimum%20Number%20of%20Taps%20to%20Open%20to%20Water%20a%20Garden/README_EN.md)

<!-- tabs:start -->

2 changes: 1 addition & 1 deletion solution/0000-0099/0046.Permutations/README.md
Original file line number Diff line number Diff line change
@@ -49,7 +49,7 @@

我们设计一个函数 $dfs(i)$ 表示已经填完了前 $i$ 个位置,现在需要填第 $i+1$ 个位置。枚举所有可能的数,如果这个数没有被填过,就填入这个数,然后继续填下一个位置,直到填完所有的位置。

时间复杂度 $O(n\times n!)$,其中 $n$ 是数组的长度。一共有 $n!$ 个排列,每个排列需要 $O(n)$ 的时间来构造。
时间复杂度 $O(n \times n!)$,其中 $n$ 是数组的长度。一共有 $n!$ 个排列,每个排列需要 $O(n)$ 的时间来构造。

相似题目:

10 changes: 9 additions & 1 deletion solution/0000-0099/0046.Permutations/README_EN.md
Original file line number Diff line number Diff line change
@@ -28,7 +28,15 @@

## Solutions

DFS.
**Solution 1: DFS (Backtracking)**

We design a function $dfs(i)$ to represent that the first $i$ positions have been filled, and now we need to fill the $i+1$ position. We enumerate all possible numbers, if this number has not been filled, we fill in this number, and then continue to fill the next position, until all positions are filled.

The time complexity is $O(n \times n!)$, where $n$ is the length of the array. There are $n!$ permutations in total, and each permutation takes $O(n)$ time to construct.

Similar problems:

- [47. Permutations II](/solution/0000-0099/0047.Permutations%20II/README_EN.md)

<!-- tabs:start -->

17 changes: 16 additions & 1 deletion solution/0000-0099/0047.Permutations II/README_EN.md
Original file line number Diff line number Diff line change
@@ -34,7 +34,22 @@

## Solutions

Sort & DFS.
**Solution 1: Sorting + Backtracking**

We can first sort the array, which allows us to place duplicate numbers together, making it easier for us to remove duplicates.

Next, we design a function $dfs(i)$, indicating that we need to fill in the number at the $i$th position. The specific implementation of the function is as follows:

- If $i = n$, it means we have finished filling in, add the current permutation to the answer array, and then return.
- Otherwise, we enumerate the number $nums[j]$ at the $i$th position, where the range of $j$ is $[0, n - 1]$. We need to ensure that $nums[j]$ has not been used and is different from the number enumerated before, so as to ensure that the current permutation is not repeated. If the conditions are met, we can fill in $nums[j]$, and continue to recursively fill in the next position, that is, call $dfs(i + 1)$. After the recursive call ends, we need to mark $nums[j]$ as unused for later enumeration.

In the main function, we first sort the array, then call $dfs(0)$, that is, start filling from the 0th position, and finally return the answer array.

The time complexity is $O(n \times n!)$, and the space complexity is $O(n)$. Here, $n$ is the length of the array. We need to enumerate $n!$ times, and each enumeration takes $O(n)$ time to judge whether it is repeated. In addition, we need a marker array to mark whether each position has been used, so the space complexity is $O(n)$.

Similar problems:

- [46. Permutations](/solution/0000-0099/0046.Permutations/README_EN.md)

<!-- tabs:start -->

8 changes: 4 additions & 4 deletions solution/0000-0099/0048.Rotate Image/README_EN.md
Original file line number Diff line number Diff line change
@@ -34,13 +34,13 @@

## Solutions

**Solution 1: In-place**
**Solution 1: In-place Rotation**

According to the requirements of the problem, we actually need to rotate $matrix[i][j]$ to $matrix[j][n - i - 1]$.
According to the problem requirements, we actually need to rotate $matrix[i][j]$ to $matrix[j][n - i - 1]$.

We can first flip the matrix upside down, that is, swap $matrix[i][j]$ and $matrix[n - i - 1][j]$, and then flip the matrix along the main diagonal, that is, swap $matrix[i][j]$ and $matrix[j][i]$. This way we can rotate $matrix[i][j]$ to $matrix[j][n - i - 1]$.
We can first flip the matrix upside down, that is, swap $matrix[i][j]$ and $matrix[n - i - 1][j]$, and then flip the matrix along the main diagonal, that is, swap $matrix[i][j]$ and $matrix[j][i]$. This way, we can rotate $matrix[i][j]$ to $matrix[j][n - i - 1]$.

The time complexity is $O(n^2)$, where $n$ is the length of the matrix. And the space complexity is $O(1)$.
The time complexity is $O(n^2)$, where $n$ is the side length of the matrix. The space complexity is $O(1)$.

<!-- tabs:start -->

24 changes: 24 additions & 0 deletions solution/0000-0099/0049.Group Anagrams/README_EN.md
Original file line number Diff line number Diff line change
@@ -30,6 +30,30 @@

## Solutions

**Solution 1: Hash Table**

1. Traverse the string array, sort each string in **character dictionary order** to get a new string.
2. Use the new string as `key` and `[str]` as `value`, and store them in the hash table (`HashMap<String, List<String>>`).
3. When encountering the same `key` during subsequent traversal, add it to the corresponding `value`.

Take `strs = ["eat", "tea", "tan", "ate", "nat", "bat"]` as an example. At the end of the traversal, the state of the hash table is:

| key | value |
| ------- | ----------------------- |
| `"aet"` | `["eat", "tea", "ate"]` |
| `"ant"` | `["tan", "nat"] ` |
| `"abt"` | `["bat"] ` |

Finally, return the `value` list of the hash table.

The time complexity is $O(n\times k\times \log k)$, where $n$ and $k$ are the lengths of the string array and the maximum length of the string, respectively.

**Solution 2: Counting**

We can also change the sorting part in Method 1 to counting, that is, use the characters in each string $s$ and their occurrence times as `key`, and use the string $s$ as `value` to store in the hash table.

The time complexity is $O(n\times (k + C))$, where $n$ and $k$ are the lengths of the string array and the maximum length of the string, respectively, and $C$ is the size of the character set. In this problem, $C = 26$.

<!-- tabs:start -->

### **Python3**
Loading