diff --git a/solution/0000-0099/0039.Combination Sum/README_EN.md b/solution/0000-0099/0039.Combination Sum/README_EN.md index 1926a7f403014..866b695870a0c 100644 --- a/solution/0000-0099/0039.Combination Sum/README_EN.md +++ b/solution/0000-0099/0039.Combination Sum/README_EN.md @@ -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) diff --git a/solution/0000-0099/0040.Combination Sum II/README_EN.md b/solution/0000-0099/0040.Combination Sum II/README_EN.md index 0a5cea1ebca80..f615feabe1e1d 100644 --- a/solution/0000-0099/0040.Combination Sum II/README_EN.md +++ b/solution/0000-0099/0040.Combination Sum II/README_EN.md @@ -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) diff --git a/solution/0000-0099/0041.First Missing Positive/README.md b/solution/0000-0099/0041.First Missing Positive/README.md index 9ba11b4bdabf3..f84e524e46eea 100644 --- a/solution/0000-0099/0041.First Missing Positive/README.md +++ b/solution/0000-0099/0041.First Missing Positive/README.md @@ -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)$。 diff --git a/solution/0000-0099/0041.First Missing Positive/README_EN.md b/solution/0000-0099/0041.First Missing Positive/README_EN.md index 458ee47900ee6..040ec35afebb4 100644 --- a/solution/0000-0099/0041.First Missing Positive/README_EN.md +++ b/solution/0000-0099/0041.First Missing Positive/README_EN.md @@ -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)$. + ### **Python3** diff --git a/solution/0000-0099/0042.Trapping Rain Water/README.md b/solution/0000-0099/0042.Trapping Rain Water/README.md index 03e23d032bf9d..fe21136195d62 100644 --- a/solution/0000-0099/0042.Trapping Rain Water/README.md +++ b/solution/0000-0099/0042.Trapping Rain Water/README.md @@ -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$ 为数组的长度。 diff --git a/solution/0000-0099/0042.Trapping Rain Water/README_EN.md b/solution/0000-0099/0042.Trapping Rain Water/README_EN.md index 42e5c6a7f28e2..6a5914627efe3 100644 --- a/solution/0000-0099/0042.Trapping Rain Water/README_EN.md +++ b/solution/0000-0099/0042.Trapping Rain Water/README_EN.md @@ -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. diff --git a/solution/0000-0099/0043.Multiply Strings/README.md b/solution/0000-0099/0043.Multiply Strings/README.md index 6a4f102863b5d..f9ff69fa14a39 100644 --- a/solution/0000-0099/0043.Multiply Strings/README.md +++ b/solution/0000-0099/0043.Multiply Strings/README.md @@ -40,12 +40,12 @@ **方法一:数学乘法模拟** -假设 `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$ 的数组,用于存储乘积的每一位。 @@ -53,7 +53,7 @@ 注意判断最高位是否为 $0$,如果是,则去掉。 -时间复杂度 $O(m \times n)$,空间复杂度 $O(m + n)$。其中 $m$ 和 $n$ 分别为 `num1` 和 `num2` 的长度。 +时间复杂度 $O(m \times n)$,空间复杂度 $O(m + n)$。其中 $m$ 和 $n$ 分别为 $num1$ 和 $num2$ 的长度。 diff --git a/solution/0000-0099/0043.Multiply Strings/README_EN.md b/solution/0000-0099/0043.Multiply Strings/README_EN.md index c52ec1b3c7a48..258b5e79ff34d 100644 --- a/solution/0000-0099/0043.Multiply Strings/README_EN.md +++ b/solution/0000-0099/0043.Multiply Strings/README_EN.md @@ -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. + ### **Python3** diff --git a/solution/0000-0099/0044.Wildcard Matching/README.md b/solution/0000-0099/0044.Wildcard Matching/README.md index 399a6f373669d..866540027dc1b 100644 --- a/solution/0000-0099/0044.Wildcard Matching/README.md +++ b/solution/0000-0099/0044.Wildcard Matching/README.md @@ -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$ 的长度。 diff --git a/solution/0000-0099/0044.Wildcard Matching/README_EN.md b/solution/0000-0099/0044.Wildcard Matching/README_EN.md index 67652c1e7300f..f9d0d2c245756 100644 --- a/solution/0000-0099/0044.Wildcard Matching/README_EN.md +++ b/solution/0000-0099/0044.Wildcard Matching/README_EN.md @@ -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. + ### **Python3** diff --git a/solution/0000-0099/0045.Jump Game II/README_EN.md b/solution/0000-0099/0045.Jump Game II/README_EN.md index e9667a341473c..6fed81c002d6c 100644 --- a/solution/0000-0099/0045.Jump Game II/README_EN.md +++ b/solution/0000-0099/0045.Jump Game II/README_EN.md @@ -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) diff --git a/solution/0000-0099/0046.Permutations/README.md b/solution/0000-0099/0046.Permutations/README.md index be38bb075a030..3b0d2631888fd 100644 --- a/solution/0000-0099/0046.Permutations/README.md +++ b/solution/0000-0099/0046.Permutations/README.md @@ -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)$ 的时间来构造。 相似题目: diff --git a/solution/0000-0099/0046.Permutations/README_EN.md b/solution/0000-0099/0046.Permutations/README_EN.md index d445a9f5d47af..e7624a7d18deb 100644 --- a/solution/0000-0099/0046.Permutations/README_EN.md +++ b/solution/0000-0099/0046.Permutations/README_EN.md @@ -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) diff --git a/solution/0000-0099/0047.Permutations II/README_EN.md b/solution/0000-0099/0047.Permutations II/README_EN.md index b261ef1a587b3..0fc514335c30c 100644 --- a/solution/0000-0099/0047.Permutations II/README_EN.md +++ b/solution/0000-0099/0047.Permutations II/README_EN.md @@ -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) diff --git a/solution/0000-0099/0048.Rotate Image/README_EN.md b/solution/0000-0099/0048.Rotate Image/README_EN.md index 5cf62d0b5e77f..2bc0408338f94 100644 --- a/solution/0000-0099/0048.Rotate Image/README_EN.md +++ b/solution/0000-0099/0048.Rotate Image/README_EN.md @@ -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)$. diff --git a/solution/0000-0099/0049.Group Anagrams/README_EN.md b/solution/0000-0099/0049.Group Anagrams/README_EN.md index b11ae937f401c..54e7e77bbbd93 100644 --- a/solution/0000-0099/0049.Group Anagrams/README_EN.md +++ b/solution/0000-0099/0049.Group Anagrams/README_EN.md @@ -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>`). +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$. + ### **Python3** diff --git a/solution/0000-0099/0050.Pow(x, n)/README_EN.md b/solution/0000-0099/0050.Pow(x, n)/README_EN.md index 0d4bc3a50f6f0..c26e17253a59e 100644 --- a/solution/0000-0099/0050.Pow(x, n)/README_EN.md +++ b/solution/0000-0099/0050.Pow(x, n)/README_EN.md @@ -42,6 +42,12 @@ ## Solutions +**Solution 1: Mathematics (Fast Powering)** + +The core idea of the fast powering algorithm is to decompose the exponent $n$ into the sum of $1$s on several binary bits, and then transform the $n$th power of $x$ into the product of several powers of $x$. + +The time complexity is $O(\log n)$, and the space complexity is $O(1)$. Here, $n$ is the exponent. + ### **Python3** diff --git a/solution/0000-0099/0051.N-Queens/README_EN.md b/solution/0000-0099/0051.N-Queens/README_EN.md index eb3e9dccaa4dd..f3a24727eeda6 100644 --- a/solution/0000-0099/0051.N-Queens/README_EN.md +++ b/solution/0000-0099/0051.N-Queens/README_EN.md @@ -35,7 +35,19 @@ ## Solutions -DFS. +**Solution 1: DFS (Backtracking)** + +We define three arrays $col$, $dg$, and $udg$ to represent whether there is a queen in the column, the main diagonal, and the anti-diagonal, respectively. If there is a queen at position $(i, j)$, then $col[j]$, $dg[i + j]$, and $udg[n - i + j]$ are all $1$. In addition, we use an array $g$ to record the current state of the chessboard, where all elements in $g$ are initially `'.'`. + +Next, we define a function $dfs(i)$, which represents placing queens starting from the $i$th row. + +In $dfs(i)$, if $i = n$, it means that we have completed the placement of all queens. We put the current $g$ into the answer array and end the recursion. + +Otherwise, we enumerate each column $j$ of the current row. If there is no queen at position $(i, j)$, that is, $col[j]$, $dg[i + j]$, and $udg[n - i + j]$ are all $0$, then we can place a queen, that is, change $g[i][j]$ to `'Q'`, and set $col[j]$, $dg[i + j]$, and $udg[n - i + j]$ to $1$. Then we continue to search the next row, that is, call $dfs(i + 1)$. After the recursion ends, we need to change $g[i][j]$ back to `'.'` and set $col[j]$, $dg[i + j]$, and $udg[n - i + j]$ to $0$. + +In the main function, we call $dfs(0)$ to start recursion, and finally return the answer array. + +The time complexity is $O(n^2 \times n!)$, and the space complexity is $O(n)$. Here, $n$ is the integer given in the problem. diff --git a/solution/0000-0099/0052.N-Queens II/README_EN.md b/solution/0000-0099/0052.N-Queens II/README_EN.md index 6847baca368d1..fe69a8aedc0eb 100644 --- a/solution/0000-0099/0052.N-Queens II/README_EN.md +++ b/solution/0000-0099/0052.N-Queens II/README_EN.md @@ -33,6 +33,20 @@ ## Solutions +**Solution 1: Backtracking** + +We design a function $dfs(i)$, which represents starting the search from the $i$th row, and the results of the search are added to the answer. + +In the $i$th row, we enumerate each column of the $i$th row. If the current column does not conflict with the queens placed before, then we can place a queen, and then continue to search the next row, that is, call $dfs(i + 1)$. + +If a conflict occurs, then we skip the current column and continue to enumerate the next column. + +To determine whether a conflict occurs, we need to use three arrays to record whether a queen has been placed in each column, each positive diagonal, and each negative diagonal, respectively. + +Specifically, we use the $cols$ array to record whether a queen has been placed in each column, the $dg$ array to record whether a queen has been placed in each positive diagonal, and the $udg$ array to record whether a queen has been placed in each negative diagonal. + +The time complexity is $O(n!)$, and the space complexity is $O(n)$. Here, $n$ is the number of queens. + ### **Python3** diff --git a/solution/0000-0099/0053.Maximum Subarray/README_EN.md b/solution/0000-0099/0053.Maximum Subarray/README_EN.md index b5d1738e9c637..947cd995ab9d5 100644 --- a/solution/0000-0099/0053.Maximum Subarray/README_EN.md +++ b/solution/0000-0099/0053.Maximum Subarray/README_EN.md @@ -44,6 +44,26 @@ ## Solutions +**Solution 1: Dynamic Programming** + +We define $f[i]$ to represent the maximum sum of the continuous subarray ending with the element $nums[i]$. Initially, $f[0] = nums[0]$. The final answer we are looking for is $\max_{0 \leq i < n} f[i]$. + +Consider $f[i]$, where $i \geq 1$, its state transition equation is: + +$$ +f[i] = \max \{ f[i - 1] + nums[i], nums[i] \} +$$ + +Which is also: + +$$ +f[i] = \max \{ f[i - 1], 0 \} + nums[i] +$$ + +Since $f[i]$ is only related to $f[i - 1]$, we can use a single variable $f$ to maintain the current value of $f[i]$, and then perform state transition. The answer is $\max_{0 \leq i < n} f$. + +The time complexity is $O(n)$, where $n$ is the length of the array $nums$. We only need to traverse the array once to get the answer. The space complexity is $O(1)$, we only need constant space to store several variables. + ### **Python3** diff --git a/solution/0000-0099/0054.Spiral Matrix/README_EN.md b/solution/0000-0099/0054.Spiral Matrix/README_EN.md index edff9be09fa81..2806b758b8bbf 100644 --- a/solution/0000-0099/0054.Spiral Matrix/README_EN.md +++ b/solution/0000-0099/0054.Spiral Matrix/README_EN.md @@ -35,17 +35,17 @@ **Solution 1: Simulation** -We use $i$ and $j$ to respectively represent the row and column of the current element being visited, and use $k$ to represent the current direction. We use an array or hash table $vis$ to record whether each element has been visited. After each element is visited, it is marked as visited, and then the current direction is moved forward one step. If the forward step goes out of bounds or has been visited, the direction is changed and continued. Move forward until the entire matrix is traversed. +We use $i$ and $j$ to represent the row and column of the current element, use $k$ to represent the current direction, and use an array or hash table $vis$ to record whether each element has been visited. Each time we visit an element, we mark it as visited, then move forward in the current direction. If we find that it is out of bounds or has been visited after moving forward, we change the direction and continue to move forward until the entire matrix is traversed. -The time complexity is $O(m \times n)$ and the space complexity is $O(m \times n)$. Where $m$ and $n$ are the number of rows and columns of the matrix. +The time complexity is $O(m \times n)$, and the space complexity is $O(m \times n)$. Here, $m$ and $n$ are the number of rows and columns of the matrix, respectively. -For the visited elements, we can also add a constant $300$ to their values, so we do not need an extra $vis$ array or hash table to record whether it has been visited, thus reducing the space complexity to $O(1)$. +For visited elements, we can also add a constant $300$ to their values, so we don't need an extra $vis$ array or hash table to record whether they have been visited, thereby reducing the space complexity to $O(1)$. **Solution 2: Layer-by-layer Simulation** -We can also traverse and store the matrix elements from the outside to the inside layer by layer. +We can also traverse and store the matrix elements from the outside to the inside, layer by layer. -The time complexity is $O(m \times n)$, and the space complexity is $O(1)$, where $m$ and $n$ are the number of rows and columns of the matrix. +The time complexity is $O(m \times n)$, and the space complexity is $O(1)$. Here, $m$ and $n$ are the number of rows and columns of the matrix, respectively. diff --git a/solution/0000-0099/0055.Jump Game/README_EN.md b/solution/0000-0099/0055.Jump Game/README_EN.md index 213bfca418d69..1786a52fc8b8a 100644 --- a/solution/0000-0099/0055.Jump Game/README_EN.md +++ b/solution/0000-0099/0055.Jump Game/README_EN.md @@ -37,14 +37,20 @@ **Solution 1: Greedy** -We use a variable $mx$ to maintain the farthest index that can be reached, initially $mx = 0$. +We use a variable $mx$ to maintain the farthest index that can currently be reached, initially $mx = 0$. -We traverse the array from left to right, for each position $i$ we are currently traversing, if $mx \lt i$, it means that the current position cannot be reached, directly return `false`. Otherwise, the farthest position that can be reached from position $i$ by jumping is $i+nums[i]$, we use $i+nums[i]$ to update the value of $mx$, that is $mx = \max(mx, i + nums[i])$. +We traverse the array from left to right. For each position $i$ we traverse, if $mx < i$, it means that the current position cannot be reached, so we directly return `false`. Otherwise, the farthest position that we can reach by jumping from position $i$ is $i+nums[i]$, we use $i+nums[i]$ to update the value of $mx$, that is, $mx = \max(mx, i + nums[i])$. -When the traversal ends, return `true` directly. +At the end of the traversal, we directly return `true`. The time complexity is $O(n)$, where $n$ is the length of the array. The space complexity is $O(1)$. +Similar problems: + +- [45. Jump Game II](/solution/0000-0099/0045.Jump%20Game%20II/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) + ### **Python3** diff --git a/solution/0000-0099/0056.Merge Intervals/README_EN.md b/solution/0000-0099/0056.Merge Intervals/README_EN.md index df785bbbbb8f8..9cf945edfca9e 100644 --- a/solution/0000-0099/0056.Merge Intervals/README_EN.md +++ b/solution/0000-0099/0056.Merge Intervals/README_EN.md @@ -34,6 +34,21 @@ ## Solutions +**Solution 1: Sorting + One-pass Traversal** + +We can sort the intervals in ascending order by the left endpoint, and then traverse the intervals for merging operations. + +The specific merging operation is as follows. + +First, we add the first interval to the answer. Then, we consider each subsequent interval in turn: + +- If the right endpoint of the last interval in the answer array is less than the left endpoint of the current interval, it means that the two intervals will not overlap, so we can directly add the current interval to the end of the answer array; +- Otherwise, it means that the two intervals overlap. We need to use the right endpoint of the current interval to update the right endpoint of the last interval in the answer array, setting it to the larger of the two. + +Finally, we return the answer array. + +The time complexity is $O(n \times \log n)$, and the space complexity is $O(\log n)$. Here, $n$ is the number of intervals. + ### **Python3** diff --git a/solution/0000-0099/0057.Insert Interval/README_EN.md b/solution/0000-0099/0057.Insert Interval/README_EN.md index 6522d7f94b77c..bcf71ea5ad766 100644 --- a/solution/0000-0099/0057.Insert Interval/README_EN.md +++ b/solution/0000-0099/0057.Insert Interval/README_EN.md @@ -40,6 +40,24 @@ ## Solutions +**Solution 1: Sorting + Interval Merging** + +We can first add the new interval `newInterval` to the interval list `intervals`, and then merge according to the regular method of interval merging. + +The time complexity is $O(n \times \log n)$, and the space complexity is $O(n)$. Here, $n$ is the number of intervals. + +**Solution 2: One-pass Traversal** + +We can traverse the interval list `intervals`, let the current interval be `interval`, and there are three situations for each interval: + +- The current interval is on the right side of the new interval, that is, $newInterval[1] < interval[0]$. At this time, if the new interval has not been added, then add the new interval to the answer, and then add the current interval to the answer. +- The current interval is on the left side of the new interval, that is, $interval[1] < newInterval[0]$. At this time, add the current interval to the answer. +- Otherwise, it means that the current interval and the new interval intersect. We take the minimum of the left endpoint of the current interval and the left endpoint of the new interval, and the maximum of the right endpoint of the current interval and the right endpoint of the new interval, as the left and right endpoints of the new interval, and then continue to traverse the interval list. + +After the traversal, if the new interval has not been added, then add the new interval to the answer. + +The time complexity is $O(n)$, where $n$ is the number of intervals. Ignoring the space consumption of the answer array, the space complexity is $O(1)$. + ### **Python3** diff --git a/solution/0000-0099/0058.Length of Last Word/README_EN.md b/solution/0000-0099/0058.Length of Last Word/README_EN.md index b794dda662a0a..c48548d1862cf 100644 --- a/solution/0000-0099/0058.Length of Last Word/README_EN.md +++ b/solution/0000-0099/0058.Length of Last Word/README_EN.md @@ -44,11 +44,11 @@ ## Solutions -**Solution 1: Reverse traversal + two pointers** +**Solution 1: Reverse Traversal + Two Pointers** -We start traversing from the end of the string $s$, finding the last character of the last word, which is not a space, and the subscript is $i$. Then continue to traverse forward to find the first space character, which is the character before the first character of the last word, and mark it as $j$. Then the length of the last word is $i - j$. +We start traversing from the end of the string $s$, find the first character that is not a space, which is the last character of the last word, and mark the index as $i$. Then continue to traverse forward, find the first character that is a space, which is the character before the first character of the last word, and mark it as $j$. Then the length of the last word is $i - j$. -Time complexity $O(n)$, where $n$ is the length of the string $s$. Space complexity $O(1)$. +The time complexity is $O(n)$, where $n$ is the length of the string $s$. The space complexity is $O(1)$. diff --git a/solution/0000-0099/0059.Spiral Matrix II/README_EN.md b/solution/0000-0099/0059.Spiral Matrix II/README_EN.md index bff82b83e2e30..4f5f2b9b66540 100644 --- a/solution/0000-0099/0059.Spiral Matrix II/README_EN.md +++ b/solution/0000-0099/0059.Spiral Matrix II/README_EN.md @@ -30,6 +30,16 @@ ## Solutions +**Solution 1: Simulation** + +Directly simulate the generation process of the spiral matrix. + +Define a two-dimensional array `ans` to store the spiral matrix. Use `i` and `j` to represent the row number and column number of the current position, use `k` to represent the current direction number, and `dirs` to represent the correspondence between the direction number and the direction. + +Starting from `1`, fill in each position of the matrix in turn. After filling in a position each time, calculate the row number and column number of the next position. If the next position is not in the matrix or has been filled, change the direction, and then calculate the row number and column number of the next position. + +The time complexity is $O(n^2)$, where $n$ is the side length of the matrix. Ignoring the output array, the space complexity is $O(1)$. + ### **Python3** diff --git a/solution/0000-0099/0060.Permutation Sequence/README_EN.md b/solution/0000-0099/0060.Permutation Sequence/README_EN.md index 9dcff4135776d..2592152c51554 100644 --- a/solution/0000-0099/0060.Permutation Sequence/README_EN.md +++ b/solution/0000-0099/0060.Permutation Sequence/README_EN.md @@ -40,6 +40,16 @@ ## Solutions +**Solution 1: Enumeration** + +We know that the set $[1,2,..n]$ has a total of $n!$ permutations. If we determine the first digit, the number of permutations that the remaining digits can form is $(n-1)!$. + +Therefore, we enumerate each digit $i$. If $k$ is greater than the number of permutations after the current position is determined, then we can directly subtract this number; otherwise, it means that we have found the number at the current position. + +For each digit $i$, where $0 \leq i < n$, the number of permutations that the remaining digits can form is $(n-i-1)!$, which we denote as $fact$. The numbers used in the process are recorded in `vis`. + +The time complexity is $O(n^2)$, and the space complexity is $O(n)$. + ### **Python3** diff --git a/solution/0000-0099/0061.Rotate List/README_EN.md b/solution/0000-0099/0061.Rotate List/README_EN.md index b871d2029fa2f..d486874542562 100644 --- a/solution/0000-0099/0061.Rotate List/README_EN.md +++ b/solution/0000-0099/0061.Rotate List/README_EN.md @@ -32,6 +32,20 @@ ## Solutions +**Solution 1: Fast and Slow Pointers + Link List Concatenation** + +First, we check whether the number of nodes in the linked list is less than $2$. If so, we directly return $head$. + +Otherwise, we first count the number of nodes $n$ in the linked list, and then take the modulus of $k$ by $n$ to get the effective value of $k$. + +If the effective value of $k$ is $0$, it means that the linked list does not need to be rotated, and we can directly return $head$. + +Otherwise, we use fast and slow pointers, let the fast pointer move $k$ steps first, and then let the fast and slow pointers move together until the fast pointer moves to the end of the linked list. At this time, the next node of the slow pointer is the new head node of the linked list. + +Finally, we concatenate the linked list. + +The time complexity is $O(n)$, where $n$ is the number of nodes in the linked list. The space complexity is $O(1)$. + ### **Python3** diff --git a/solution/0000-0099/0062.Unique Paths/README_EN.md b/solution/0000-0099/0062.Unique Paths/README_EN.md index fa6241575dbe0..7b9e2425a1b14 100644 --- a/solution/0000-0099/0062.Unique Paths/README_EN.md +++ b/solution/0000-0099/0062.Unique Paths/README_EN.md @@ -38,7 +38,29 @@ ## Solutions -Dynamic programming. +**Solution 1: Dynamic Programming** + +We define $f[i][j]$ to represent the number of paths from the top left corner to $(i, j)$, initially $f[0][0] = 1$, and the answer is $f[m - 1][n - 1]$. + +Consider $f[i][j]$: + +- If $i > 0$, then $f[i][j]$ can be reached by taking one step from $f[i - 1][j]$, so $f[i][j] = f[i][j] + f[i - 1][j]$; +- If $j > 0$, then $f[i][j]$ can be reached by taking one step from $f[i][j - 1]$, so $f[i][j] = f[i][j] + f[i][j - 1]$. + +Therefore, we have the following state transition equation: + +$$ +f[i][j] = \begin{cases} +1 & i = 0, j = 0 \\ +f[i - 1][j] + f[i][j - 1] & \text{otherwise} +\end{cases} +$$ + +The final answer is $f[m - 1][n - 1]$. + +The time complexity is $O(m \times n)$, and the space complexity is $O(m \times n)$. Here, $m$ and $n$ are the number of rows and columns of the grid, respectively. + +We notice that $f[i][j]$ is only related to $f[i - 1][j]$ and $f[i][j - 1]$, so we can optimize the first dimension space and only keep the second dimension space, resulting in a time complexity of $O(m \times n)$ and a space complexity of $O(n)$. diff --git a/solution/0000-0099/0063.Unique Paths II/README.md b/solution/0000-0099/0063.Unique Paths II/README.md index 6968dc3d3b84b..33e879199e4ef 100644 --- a/solution/0000-0099/0063.Unique Paths II/README.md +++ b/solution/0000-0099/0063.Unique Paths II/README.md @@ -49,14 +49,18 @@ -动态规划。 +**方法一:动态规划** -假设 `dp[i][j]` 表示到达网格 `(i,j)` 的路径数,先初始化 dp 第一列和第一行的所有值,然后判断。 +我们定义 $dp[i][j]$ 表示到达网格 $(i,j)$ 的路径数。 -- 若 `obstacleGrid[i][j] == 1`,说明路径数为 0,`dp[i][j] = 0`; -- 若 `obstacleGrid[i][j] == 0`,则 `dp[i][j] = dp[i - 1][j] + dp[i][j - 1]`。 +首先初始化 $dp$ 第一列和第一行的所有值,然后遍历其它行和列,有两种情况: -最后返回 `dp[m - 1][n - 1]` 即可。 +- 若 $obstacleGrid[i][j] = 1$,说明路径数为 $0$,那么 $dp[i][j] = 0 ¥; +- 若 ¥ obstacleGrid[i][j] = 0$,则 $dp[i][j] = dp[i - 1][j] + dp[i][j - 1]$。 + +最后返回 $dp[m - 1][n - 1]$ 即可。 + +时间复杂度 $O(m \times n)$,空间复杂度 $O(m \times n)$。其中 $m$ 和 $n$ 分别是网格的行数和列数。 diff --git a/solution/0000-0099/0063.Unique Paths II/README_EN.md b/solution/0000-0099/0063.Unique Paths II/README_EN.md index 6cb6aaeeddac6..12a3dba0d0d47 100644 --- a/solution/0000-0099/0063.Unique Paths II/README_EN.md +++ b/solution/0000-0099/0063.Unique Paths II/README_EN.md @@ -43,7 +43,18 @@ There are two ways to reach the bottom-right corner: ## Solutions -Dynamic programming. +**Solution 1: Dynamic Programming** + +We define $dp[i][j]$ to represent the number of paths to reach the grid $(i,j)$. + +First, initialize all values in the first column and first row of $dp$, then traverse other rows and columns, there are two cases: + +- If $obstacleGrid[i][j] = 1$, it means the number of paths is $0$, so $dp[i][j] = 0$; +- If $obstacleGrid[i][j] = 0$, then $dp[i][j] = dp[i - 1][j] + dp[i][j - 1]$. + +Finally, return $dp[m - 1][n - 1]$. + +The time complexity is $O(m \times n)$, and the space complexity is $O(m \times n)$. Here, $m$ and $n$ are the number of rows and columns of the grid, respectively. diff --git a/solution/0000-0099/0064.Minimum Path Sum/README_EN.md b/solution/0000-0099/0064.Minimum Path Sum/README_EN.md index 6a69677eb87db..6b5ce492fd4b7 100644 --- a/solution/0000-0099/0064.Minimum Path Sum/README_EN.md +++ b/solution/0000-0099/0064.Minimum Path Sum/README_EN.md @@ -36,7 +36,19 @@ ## Solutions -Dynamic programming. +**Solution 1: Dynamic Programming** + +We define $f[i][j]$ to represent the minimum path sum from the top left corner to $(i, j)$. Initially, $f[0][0] = grid[0][0]$, and the answer is $f[m - 1][n - 1]$. + +Consider $f[i][j]$: + +- If $j = 0$, then $f[i][j] = f[i - 1][j] + grid[i][j]$; +- If $i = 0$, then $f[i][j] = f[i][j - 1] + grid[i][j]$; +- If $i > 0$ and $j > 0$, then $f[i][j] = \min(f[i - 1][j], f[i][j - 1]) + grid[i][j]$. + +Finally, return $f[m - 1][n - 1]$. + +The time complexity is $O(m \times n)$, and the space complexity is $O(m \times n)$. Here, $m$ and $n$ are the number of rows and columns of the grid, respectively. diff --git a/solution/0000-0099/0065.Valid Number/README_EN.md b/solution/0000-0099/0065.Valid Number/README_EN.md index ba7096341605e..b95129c241a19 100644 --- a/solution/0000-0099/0065.Valid Number/README_EN.md +++ b/solution/0000-0099/0065.Valid Number/README_EN.md @@ -67,6 +67,24 @@ ## Solutions +**Solution 1: Case Discussion** + +First, we check if the string starts with a positive or negative sign. If it does, we move the pointer $i$ one step forward. If the pointer $i$ has reached the end of the string at this point, it means the string only contains a positive or negative sign, so we return `false`. + +If the character pointed to by the current pointer $i$ is a decimal point, and there is no number after the decimal point, or if there is an `e` or `E` after the decimal point, we return `false`. + +Next, we use two variables $dot$ and $e$ to record the number of decimal points and `e` or `E` respectively. + +We use pointer $j$ to point to the current character: + +- If the current character is a decimal point, and a decimal point or `e` or `E` has appeared before, return `false`. Otherwise, we increment $dot$ by one; +- If the current character is `e` or `E`, and `e` or `E` has appeared before, or if the current character is at the beginning or end of the string, return `false`. Otherwise, we increment $e$ by one; then check if the next character is a positive or negative sign, if it is, move the pointer $j$ one step forward. If the pointer $j$ has reached the end of the string at this point, return `false`; +- If the current character is not a number, return `false`. + +After traversing the string, return `true`. + +The time complexity is $O(n)$, and the space complexity is $O(1)$. Here, $n$ is the length of the string. + ### **Python3** diff --git a/solution/0000-0099/0067.Add Binary/README_EN.md b/solution/0000-0099/0067.Add Binary/README_EN.md index c1bd9e99d210e..34e0b31835de7 100644 --- a/solution/0000-0099/0067.Add Binary/README_EN.md +++ b/solution/0000-0099/0067.Add Binary/README_EN.md @@ -25,6 +25,12 @@ ## Solutions +**Solution 1: Simulation** + +We use a variable $carry$ to record the current carry, and two pointers $i$ and $j$ to point to the end of $a$ and $b$ respectively, and add them bit by bit from the end to the beginning. + +The time complexity is $O(\max(m, n))$, where $m$ and $n$ are the lengths of strings $a$ and $b$ respectively. The space complexity is $O(1)$. + ### **Python3** diff --git a/solution/0000-0099/0068.Text Justification/README_EN.md b/solution/0000-0099/0068.Text Justification/README_EN.md index 3eb00158c069e..e25d2f6838229 100644 --- a/solution/0000-0099/0068.Text Justification/README_EN.md +++ b/solution/0000-0099/0068.Text Justification/README_EN.md @@ -72,6 +72,12 @@ Note that the second line is also left-justified because it contains only one wo ## Solutions +**Solution 1: Simulation** + +We can simulate the process according to the problem's requirements. Note that if it is the last line, or if there is only one word in the line, then we should align to the left. Otherwise, we should distribute the spaces evenly. + +The time complexity is $O(L)$, and the space complexity is $O(L)$. Here, $L$ is the sum of the lengths of all words. + ### **Python3** diff --git a/solution/0000-0099/0070.Climbing Stairs/README_EN.md b/solution/0000-0099/0070.Climbing Stairs/README_EN.md index 27845272f33fd..c96205caca3b5 100644 --- a/solution/0000-0099/0070.Climbing Stairs/README_EN.md +++ b/solution/0000-0099/0070.Climbing Stairs/README_EN.md @@ -39,6 +39,62 @@ ## Solutions +**Solution 1: Recursion** + +We define $f[i]$ to represent the number of ways to climb to the $i$-th step, then $f[i]$ can be transferred from $f[i - 1]$ and $f[i - 2]$, that is: + +$$ +f[i] = f[i - 1] + f[i - 2] +$$ + +The initial conditions are $f[0] = 1$ and $f[1] = 1$, that is, the number of ways to climb to the 0th step is 1, and the number of ways to climb to the 1st step is also 1. + +The answer is $f[n]$. + +Since $f[i]$ is only related to $f[i - 1]$ and $f[i - 2]$, we can use two variables $a$ and $b$ to maintain the current number of ways, reducing the space complexity to $O(1)$. + +The time complexity is $O(n)$, and the space complexity is $O(1)$. + +**Solution 2: Matrix Quick Power to Accelerate Recursion** + +We set $Fib(n)$ to represent a $1 \times 2$ matrix $\begin{bmatrix} F_n & F_{n - 1} \end{bmatrix}$, where $F_n$ and $F_{n - 1}$ are the $n$-th and $(n - 1)$-th Fibonacci numbers respectively. + +We hope to derive $Fib(n)$ based on $Fib(n-1) = \begin{bmatrix} F_{n - 1} & F_{n - 2} \end{bmatrix}$. That is to say, we need a matrix $base$, so that $Fib(n - 1) \times base = Fib(n)$, that is: + +$$ +\begin{bmatrix} +F_{n - 1} & F_{n - 2} +\end{bmatrix} \times base = \begin{bmatrix} F_n & F_{n - 1} \end{bmatrix} +$$ + +Since $F_n = F_{n - 1} + F_{n - 2}$, the first column of the matrix $base$ is: + +$$ +\begin{bmatrix} +1 \\ +1 +\end{bmatrix} +$$ + +The second column is: + +$$ +\begin{bmatrix} +1 \\ +0 +\end{bmatrix} +$$ + +Therefore: + +$$ +\begin{bmatrix} F_{n - 1} & F_{n - 2} \end{bmatrix} \times \begin{bmatrix}1 & 1 \\ 1 & 0\end{bmatrix} = \begin{bmatrix} F_n & F_{n - 1} \end{bmatrix} +$$ + +We define the initial matrix $res = \begin{bmatrix} 1 & 1 \end{bmatrix}$, then $F_n$ is equal to the first element of the first row of the result matrix of $res$ multiplied by $base^{n - 1}$. We can solve it using matrix quick power. + +The time complexity is $O(\log n)$, and the space complexity is $O(1)$. + ### **Python3** diff --git a/solution/0000-0099/0074.Search a 2D Matrix/README.md b/solution/0000-0099/0074.Search a 2D Matrix/README.md index 3634d252e2b52..2d78e7454434c 100644 --- a/solution/0000-0099/0074.Search a 2D Matrix/README.md +++ b/solution/0000-0099/0074.Search a 2D Matrix/README.md @@ -48,21 +48,21 @@ **方法一:二分查找** -将二维矩阵逻辑展开,然后二分查找即可。 +我们将二维矩阵逻辑展开,然后二分查找即可。 -时间复杂度 $O(log (m \times n))$。 +时间复杂度 $O(\log (m \times n))$。其中 $m$ 和 $n$ 分别是矩阵的行数和列数。空间复杂度 $O(1)$。 **方法二:从左下角或右上角搜索** -这里我们以左下角作为起始搜索点,往右上方向开始搜索,比较当前元素 `matrix[i][j]` 与 `target` 的大小关系: +这里我们以左下角作为起始搜索点,往右上方向开始搜索,比较当前元素 $matrix[i][j]$ 与 $target$ 的大小关系: -- 若 `matrix[i][j] == target`,说明找到了目标值,直接返回 true。 -- 若 `matrix[i][j] > target`,说明这一行从当前位置开始往右的所有元素均大于 target,应该让 i 指针往上移动,即 `i--`。 -- 若 `matrix[i][j] < target`,说明这一列从当前位置开始往上的所有元素均小于 target,应该让 j 指针往右移动,即 `j++`。 +- 若 $matrix[i][j] = target$,说明找到了目标值,直接返回 `true`。 +- 若 $matrix[i][j] > target$,说明这一行从当前位置开始往右的所有元素均大于 target,应该让 i 指针往上移动,即 $i = i - 1$。 +- 若 $matrix[i][j] < target$,说明这一列从当前位置开始往上的所有元素均小于 target,应该让 j 指针往右移动,即 $j = j + 1$。 -若搜索结束依然找不到 target,返回 false。 +若搜索结束依然找不到 $target$,返回 `false`。 -时间复杂度 $O(m + n)$。 +时间复杂度 $O(m + n)$。其中 $m$ 和 $n$ 分别是矩阵的行数和列数。空间复杂度 $O(1)$。 diff --git a/solution/0000-0099/0074.Search a 2D Matrix/README_EN.md b/solution/0000-0099/0074.Search a 2D Matrix/README_EN.md index aba485147802b..da9175503964a 100644 --- a/solution/0000-0099/0074.Search a 2D Matrix/README_EN.md +++ b/solution/0000-0099/0074.Search a 2D Matrix/README_EN.md @@ -42,6 +42,24 @@ ## Solutions +**Solution 1: Binary Search** + +We can logically unfold the two-dimensional matrix and then perform binary search. + +The time complexity is $O(\log(m \times n))$, where $m$ and $n$ are the number of rows and columns of the matrix, respectively. The space complexity is $O(1)$. + +**Solution 2: Search from the Bottom Left or Top Right** + +Here, we start searching from the bottom left corner and move towards the top right direction. We compare the current element $matrix[i][j]$ with $target$: + +- If $matrix[i][j] = target$, we have found the target value and return `true`. +- If $matrix[i][j] > target$, all elements to the right of the current position in this row are greater than target, so we should move the pointer $i$ upwards, i.e., $i = i - 1$. +- If $matrix[i][j] < target$, all elements above the current position in this column are less than target, so we should move the pointer $j$ to the right, i.e., $j = j + 1$. + +If we still can't find $target$ after the search, return `false`. + +The time complexity is $O(m + n)$, where $m$ and $n$ are the number of rows and columns of the matrix, respectively. The space complexity is $O(1)$. + ### **Python3** diff --git a/solution/0000-0099/0075.Sort Colors/README_EN.md b/solution/0000-0099/0075.Sort Colors/README_EN.md index c59f789e3b204..191f2c38b9520 100644 --- a/solution/0000-0099/0075.Sort Colors/README_EN.md +++ b/solution/0000-0099/0075.Sort Colors/README_EN.md @@ -39,6 +39,20 @@ ## Solutions +**Solution 1: Three Pointers** + +We define three pointers $i$, $j$, and $k$. Pointer $i$ is used to point to the rightmost boundary of the elements with a value of $0$ in the array, and pointer $j$ is used to point to the leftmost boundary of the elements with a value of $2$ in the array. Initially, $i=-1$, $j=n$. Pointer $k$ is used to point to the current element being traversed, initially $k=0$. + +When $k < j$, we perform the following operations: + +- If $nums[k] = 0$, then swap it with $nums[i+1]$, then increment both $i$ and $k$ by $1$; +- If $nums[k] = 2$, then swap it with $nums[j-1]$, then decrement $j$ by $1$; +- If $nums[k] = 1$, then increment $k$ by $1$. + +After the traversal, the elements in the array are divided into three parts: $[0,i]$, $[i+1,j-1]$ and $[j,n-1]$. + +The time complexity is $O(n)$, where $n$ is the length of the array. Only one traversal of the array is needed. The space complexity is $O(1)$. + ### **Python3** diff --git a/solution/0000-0099/0076.Minimum Window Substring/README_EN.md b/solution/0000-0099/0076.Minimum Window Substring/README_EN.md index 2aadaf38a3e16..d91c2ac5feef0 100644 --- a/solution/0000-0099/0076.Minimum Window Substring/README_EN.md +++ b/solution/0000-0099/0076.Minimum Window Substring/README_EN.md @@ -51,15 +51,15 @@ Since the largest window of s only has one 'a', return empty string. **Solution 1: Counting + Two Pointers** -We use a hash table or array $need$ to count the number of characters in string $t$, and use another hash table or array $window$ to count the number of characters in the sliding window. In addition, define two pointers $j$ and $i$ pointing to the left and right boundaries of the window, and the variable $cnt$ represents the number of characters in $t$ that are already included in the window. The variables $k$ and $mi$ represent the starting position and length of the minimum cover substring respectively. +We use a hash table or array $need$ to count the number of occurrences of each character in string $t$, and another hash table or array $window$ to count the number of occurrences of each character in the sliding window. In addition, we define two pointers $j$ and $i$ to point to the left and right boundaries of the window, respectively. The variable $cnt$ represents how many characters in $t$ are already included in the window. The variables $k$ and $mi$ represent the starting position and length of the minimum covering substring, respectively. -We traverse the string $s$ from left to right, and for the current character $s[i]$ we traverse: +We traverse the string $s$ from left to right. For the currently traversed character $s[i]$: -We add it to the window, that is, $window[s[i]] = window[s[i]] + 1$. If $need[s[i]] \geq window[s[i]]$ at this time, it means that $s[i]$ is a "necessary character". We add $cnt$ to $cnt$. If $cnt$ equals the length of $t$, it means that the window contains all the characters in $t$ at this time. We can try to update the starting position and length of the minimum cover substring. If $i - j + 1 \lt mi$, it means that the current window represents a shorter substring. We update $mi = i - j + 1$ and $k = j$. Then, we try to move the left boundary $j$. If $need[s[j]] \geq window[s[j]]$ at this time, it means that $s[j]$ is a "necessary character". When the left boundary is moved, the character $s[j]$ will be removed from the window. Therefore, we need to subtract $cnt$ by 1, and update $window[s[j]] = window[s[j]] - 1$, and move $j$ to the right by one bit. If $cnt$ is not equal to the length of $t$, it means that the window does not contain all the characters in $t$ at this time. We do not need to move the left boundary, and just move $i$ to the right by one bit, and continue traversal. +We add it to the window, i.e., $window[s[i]] = window[s[i]] + 1$. If $need[s[i]] \geq window[s[i]]$ at this time, it means that $s[i]$ is a "necessary character", so we increment $cnt$ by one. If $cnt$ equals the length of $t$, it means that all characters in $t$ are already included in the window at this time, so we can try to update the starting position and length of the minimum covering substring. If $i - j + 1 \lt mi$, it means that the substring represented by the current window is shorter, so we update $mi = i - j + 1$ and $k = j$. Then, we try to move the left boundary $j$. If $need[s[j]] \geq window[s[j]]$ at this time, it means that $s[j]$ is a "necessary character". When moving the left boundary, the character $s[j]$ will be removed from the window, so we need to decrement $cnt$ by one, then update $window[s[j]] = window[s[j]] - 1$, and move $j$ one step to the right. If $cnt$ does not equal the length of $t$, it means that all characters in $t$ are not yet included in the window at this time, so we don't need to move the left boundary, just move $i$ one step to the right and continue to traverse. -If the minimum cover substring is not found after traversal, return an empty string. Otherwise, return $s[k:k+mi]$. +After the traversal, if the minimum covering substring is not found, return an empty string, otherwise return $s[k:k+mi]$. -Time complexity $O(m + n)$, space complexity $O(C)$. Where $m$ and $n$ are the lengths of strings $s$ and $t$ respectively; and $C$ is the size of the character set, which is $128$ in this question. +The time complexity is $O(m + n)$, and the space complexity is $O(C)$. Here, $m$ and $n$ are the lengths of strings $s$ and $t$ respectively; and $C$ is the size of the character set, in this problem $C = 128$. diff --git a/solution/0000-0099/0077.Combinations/README_EN.md b/solution/0000-0099/0077.Combinations/README_EN.md index 2bd1b8a784229..eecb9b404b245 100644 --- a/solution/0000-0099/0077.Combinations/README_EN.md +++ b/solution/0000-0099/0077.Combinations/README_EN.md @@ -36,7 +36,27 @@ Note that combinations are unordered, i.e., [1,2] and [2,1] are considered to be ## Solutions -DFS. +**Solution 1: Backtracking (Two Ways)** + +We design a function $dfs(i)$, which represents starting the search from number $i$, with the current search path as $t$, and the answer as $ans$. + +The execution logic of the function $dfs(i)$ is as follows: + +- If the length of the current search path $t$ equals $k$, then add the current search path to the answer and return. +- If $i \gt n$, it means the search has ended, return. +- Otherwise, we can choose to add the number $i$ to the search path $t$, and then continue the search, i.e., execute $dfs(i + 1)$, and then remove the number $i$ from the search path $t$; or we do not add the number $i$ to the search path $t$, and directly execute $dfs(i + 1)$. + +The above method is actually enumerating whether to select the current number or not, and then recursively searching the next number. We can also enumerate the next number $j$ to be selected, where $i \leq j \leq n$. If the next number to be selected is $j$, then we add the number $j$ to the search path $t$, and then continue the search, i.e., execute $dfs(j + 1)$, and then remove the number $j$ from the search path $t$. + +In the main function, we start the search from number $1$, i.e., execute $dfs(1)$. + +The time complexity is $(C_n^k \times k)$, and the space complexity is $O(k)$. Here, $C_n^k$ represents the combination number. + +Similar problems: + +- [39. Combination Sum](/solution/0000-0099/0039.Combination%20Sum/README_EN.md) +- [40. Combination Sum II](/solution/0000-0099/0040.Combination%20Sum%20II/README_EN.md) +- [216. Combination Sum III](/solution/0200-0299/0216.Combination%20Sum%20III/README_EN.md) diff --git a/solution/0000-0099/0078.Subsets/README_EN.md b/solution/0000-0099/0078.Subsets/README_EN.md index dc7dd8aa330c7..4084424c47cd1 100644 --- a/solution/0000-0099/0078.Subsets/README_EN.md +++ b/solution/0000-0099/0078.Subsets/README_EN.md @@ -34,7 +34,24 @@ ## Solutions -DFS. +**Solution 1: DFS (Backtracking)** + +We design a function $dfs(i)$, which represents starting the search from the $i$th element of the array for all subsets. The execution logic of the function $dfs(i)$ is as follows: + +- If $i = n$, it means the current search has ended. Add the current subset $t$ to the answer array $ans$, and then return. +- Otherwise, we can choose not to select the current element and directly execute $dfs(i + 1)$; or we can choose the current element, i.e., add the current element $nums[i]$ to the subset $t$, and then execute $dfs(i + 1)$. Note that we need to remove $nums[i]$ from the subset $t$ after executing $dfs(i + 1)$ (backtracking). + +In the main function, we call $dfs(0)$, i.e., start searching all subsets from the first element of the array. Finally, return the answer array $ans$. + +The time complexity is $O(n \times 2^n)$, and the space complexity is $O(n)$. Here, $n$ is the length of the array. There are a total of $2^n$ subsets, and each subset takes $O(n)$ time to construct. + +**Solution 2: Binary Enumeration** + +We can also use the method of binary enumeration to get all subsets. + +We can use $2^n$ binary numbers to represent all subsets of $n$ elements. For the current binary number $mask$, if the $i$th bit is $1$, it means that the $i$th element is selected, otherwise it means that the $i$th element is not selected. + +The time complexity is $O(n \times 2^n)$, and the space complexity is $O(n)$. Here, $n$ is the length of the array. There are a total of $2^n$ subsets, and each subset takes $O(n)$ time to construct. diff --git a/solution/0000-0099/0079.Word Search/README_EN.md b/solution/0000-0099/0079.Word Search/README_EN.md index 4bff079af746d..a4a56763e5915 100644 --- a/solution/0000-0099/0079.Word Search/README_EN.md +++ b/solution/0000-0099/0079.Word Search/README_EN.md @@ -46,6 +46,20 @@ ## Solutions +**Solution 1: DFS (Backtracking)** + +We can enumerate each position $(i, j)$ in the grid as the starting point of the search, and then start a depth-first search from the starting point. If we can search to the end of the word, it means the word exists, otherwise, it means the word does not exist. + +Therefore, we design a function $dfs(i, j, k)$, which represents whether we can successfully search from the $(i, j)$ position of the grid, starting from the $k$th character of the word. The execution steps of the function $dfs(i, j, k)$ are as follows: + +- If $k = |word|-1$, it means that we have searched to the last character of the word. At this time, we only need to judge whether the character at the $(i, j)$ position of the grid is equal to $word[k]$. If they are equal, it means the word exists, otherwise, it means the word does not exist. Whether the word exists or not, there is no need to continue to search, so return the result directly. +- Otherwise, if the $word[k]$ character is not equal to the character at the $(i, j)$ position of the grid, it means that the search failed this time, so return `false` directly. +- Otherwise, we temporarily store the character at the $(i, j)$ position of the grid in $c$, and then modify the character at this position to a special character `'0'`, indicating that the character at this position has been used to prevent it from being reused in subsequent searches. Then we start from the up, down, left, and right directions of the $(i, j)$ position to search for the $k+1$th character in the grid. If any direction is successful, it means the search is successful, otherwise, it means the search failed. At this time, we need to restore the character at the $(i, j)$ position of the grid, that is, put $c$ back to the $(i, j)$ position (backtracking). + +In the main function, we enumerate each position $(i, j)$ in the grid as the starting point. If calling $dfs(i, j, 0)$ returns `true`, it means the word exists, otherwise, it means the word does not exist, so return `false`. + +The time complexity is $O(m \times n \times 3^k)$, and the space complexity is $O(\min(m \times n, k))$. Here, $m$ and $n$ are the number of rows and columns of the grid, respectively; and $k$ is the length of the string $word$. + ### **Python3** diff --git a/solution/0000-0099/0080.Remove Duplicates from Sorted Array II/README.md b/solution/0000-0099/0080.Remove Duplicates from Sorted Array II/README.md index 8140b980dbd1d..dca20d9316331 100644 --- a/solution/0000-0099/0080.Remove Duplicates from Sorted Array II/README.md +++ b/solution/0000-0099/0080.Remove Duplicates from Sorted Array II/README.md @@ -80,7 +80,9 @@ for (int i = 0; i < len; i++) { - 由于相同的数字最多保留 $k$ 个,那么原数组的前 $k$ 个元素我们可以直接保留; - 对于后面的数字,能够保留的前提是:当前数字 $x$ 与前面已保留的数字的倒数第 $k$ 个元素比较,不同则保留,相同则跳过。 -相似题目:[26. 删除有序数组中的重复项](/solution/0000-0099/0026.Remove%20Duplicates%20from%20Sorted%20Array/README.md) +相似题目: + +- [26. 删除有序数组中的重复项](/solution/0000-0099/0026.Remove%20Duplicates%20from%20Sorted%20Array/README.md) diff --git a/solution/0000-0099/0080.Remove Duplicates from Sorted Array II/README_EN.md b/solution/0000-0099/0080.Remove Duplicates from Sorted Array II/README_EN.md index c0e69513d753e..139078f9db977 100644 --- a/solution/0000-0099/0080.Remove Duplicates from Sorted Array II/README_EN.md +++ b/solution/0000-0099/0080.Remove Duplicates from Sorted Array II/README_EN.md @@ -60,6 +60,27 @@ It does not matter what you leave beyond the returned k (hence they are undersco ## Solutions +**Solution 1: Single Pass** + +We use a variable $k$ to record the current length of the array that has been processed. Initially, $k=0$, representing an empty array. + +Then we traverse the array from left to right. For each element $x$ we traverse, if $k < 2$ or $x \neq nums[k-2]$, we put $x$ in the position of $nums[k]$, and then increment $k$ by $1$. Otherwise, $x$ is the same as $nums[k-2]$, we directly skip this element. Continue to traverse until the entire array is traversed. + +In this way, when the traversal ends, the first $k$ elements in $nums$ are the answer we want, and $k$ is the length of the answer. + +The time complexity is $O(n)$, and the space complexity is $O(1)$. Here, $n$ is the length of the array. + +Supplement: + +The original problem requires that the same number appears at most $2$ times. We can extend it to keep at most $k$ identical numbers. + +- Since the same number can be kept at most $k$ times, we can directly keep the first $k$ elements of the original array; +- For the later numbers, the premise of being able to keep them is: the current number $x$ compares with the $k$th element from the end of the previously kept numbers. If they are different, keep it, otherwise skip it. + +Similar problems: + +- [26. Remove Duplicates from Sorted Array](/solution/0000-0099/0026.Remove%20Duplicates%20from%20Sorted%20Array/README_EN.md) + ### **Python3** diff --git a/solution/0000-0099/0081.Search in Rotated Sorted Array II/README_EN.md b/solution/0000-0099/0081.Search in Rotated Sorted Array II/README_EN.md index f75208393853c..5c80edb6d9aab 100644 --- a/solution/0000-0099/0081.Search in Rotated Sorted Array II/README_EN.md +++ b/solution/0000-0099/0081.Search in Rotated Sorted Array II/README_EN.md @@ -35,6 +35,20 @@ ## Solutions +**Solution 1: Binary Search** + +We define the left boundary $l=0$ and the right boundary $r=n-1$ for the binary search, where $n$ is the length of the array. + +During each binary search process, we get the current midpoint $mid=(l+r)/2$. + +- If $nums[mid] \gt nums[r]$, it means that $[l,mid]$ is ordered. At this time, if $nums[l] \le target \le nums[mid]$, it means that $target$ is in $[l,mid]$, otherwise $target$ is in $[mid+1,r]$. +- If $nums[mid] \lt nums[r]$, it means that $[mid+1,r]$ is ordered. At this time, if $nums[mid] \lt target \le nums[r]$, it means that $target$ is in $[mid+1,r]$, otherwise $target$ is in $[l,mid]$. +- If $nums[mid] = nums[r]$, it means that the elements $nums[mid]$ and $nums[r]$ are equal. At this time, we cannot determine which interval $target$ is in, so we can only decrease $r$ by $1$. + +After the binary search ends, if $nums[l] = target$, it means that the target value $target$ exists in the array, otherwise it means it does not exist. + +The time complexity is approximately $O(\log n)$, and the space complexity is $O(1)$. Here, $n$ is the length of the array. + ### **Python3** diff --git a/solution/0000-0099/0082.Remove Duplicates from Sorted List II/README_EN.md b/solution/0000-0099/0082.Remove Duplicates from Sorted List II/README_EN.md index f8d0559fa32c7..4e7eb3bc3cf31 100644 --- a/solution/0000-0099/0082.Remove Duplicates from Sorted List II/README_EN.md +++ b/solution/0000-0099/0082.Remove Duplicates from Sorted List II/README_EN.md @@ -32,6 +32,16 @@ ## Solutions +**Solution 1: Single Pass** + +First, we create a dummy head node $dummy$, and set $dummy.next = head$. Then we create a pointer $pre$ pointing to $dummy$, and a pointer $cur$ pointing to $head$, and start traversing the linked list. + +When the node value pointed by $cur$ is the same as the node value pointed by $cur.next$, we let $cur$ keep moving forward until the node value pointed by $cur$ is different from the node value pointed by $cur.next$. At this point, we check whether $pre.next$ is equal to $cur$. If they are equal, it means there are no duplicate nodes between $pre$ and $cur$, so we move $pre$ to the position of $cur$; otherwise, it means there are duplicate nodes between $pre$ and $cur$, so we set $pre.next$ to $cur.next$. Then we continue to move $cur$ forward. Continue the above operation until $cur$ is null, and the traversal ends. + +Finally, return $dummy.next$. + +The time complexity is $O(n)$, and the space complexity is $O(1)$. Here, $n$ is the length of the linked list. + ### **Python3** diff --git a/solution/0000-0099/0084.Largest Rectangle in Histogram/README.md b/solution/0000-0099/0084.Largest Rectangle in Histogram/README.md index 545608e7bf927..450765c52267c 100644 --- a/solution/0000-0099/0084.Largest Rectangle in Histogram/README.md +++ b/solution/0000-0099/0084.Largest Rectangle in Histogram/README.md @@ -45,6 +45,10 @@ **方法一:单调栈** +我们可以枚举每根柱子的高度 $h$ 作为矩形的高度,利用单调栈,向左右两边找第一个高度小于 $h$ 的下标 $left_i$, $right_i$。那么此时矩形面积为 $h \times (right_i-left_i-1)$,求最大值即可。 + +时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 表示 $heights$ 的长度。 + 单调栈常见模型:找出每个数左/右边**离它最近的**且**比它大/小的数**。模板: ```python @@ -55,10 +59,6 @@ for i in range(n): stk.append(i) ``` -枚举每根柱子的高度 $h$ 作为矩形的高度,向左右两边找第一个高度小于 $h$ 的下标 $left_i$, $right_i$。那么此时矩形面积为 $h \times (right_i-left_i-1)$,求最大值即可。 - -时间复杂度 $O(n)$,其中 $n$ 表示 $heights$ 的长度。 - ### **Python3** diff --git a/solution/0000-0099/0084.Largest Rectangle in Histogram/README_EN.md b/solution/0000-0099/0084.Largest Rectangle in Histogram/README_EN.md index bb9d021f4f49a..9d1997c59592f 100644 --- a/solution/0000-0099/0084.Largest Rectangle in Histogram/README_EN.md +++ b/solution/0000-0099/0084.Largest Rectangle in Histogram/README_EN.md @@ -33,6 +33,22 @@ The largest rectangle is shown in the red area, which has an area = 10 units. ## Solutions +**Solution 1: Monotonic Stack** + +We can enumerate the height $h$ of each bar as the height of the rectangle. Using a monotonic stack, we find the index $left_i$, $right_i$ of the first bar with a height less than $h$ to the left and right. The area of the rectangle at this time is $h \times (right_i-left_i-1)$. We can find the maximum value. + +The time complexity is $O(n)$, and the space complexity is $O(n)$. Here, $n$ represents the length of $heights$. + +Common model of monotonic stack: Find the **nearest** number to the left/right of each number that is **larger/smaller** than it. Template: + +```python +stk = [] +for i in range(n): + while stk and check(stk[-1], i): + stk.pop() + stk.append(i) +``` + ### **Python3** diff --git a/solution/0000-0099/0085.Maximal Rectangle/README.md b/solution/0000-0099/0085.Maximal Rectangle/README.md index f7fa1ab061356..45e07df6989c4 100644 --- a/solution/0000-0099/0085.Maximal Rectangle/README.md +++ b/solution/0000-0099/0085.Maximal Rectangle/README.md @@ -63,7 +63,7 @@ **方法一:单调栈** -把每一行视为柱状图的底部,对每一行求柱状图的最大面积即可。 +我们把每一行视为柱状图的底部,对每一行求柱状图的最大面积即可。 时间复杂度 $O(m \times n)$,其中 $m$ 表示 $matrix$ 的行数,$n$ 表示 $matrix$ 的列数。 diff --git a/solution/0000-0099/0085.Maximal Rectangle/README_EN.md b/solution/0000-0099/0085.Maximal Rectangle/README_EN.md index 70c37c93730ab..e94431f84c043 100644 --- a/solution/0000-0099/0085.Maximal Rectangle/README_EN.md +++ b/solution/0000-0099/0085.Maximal Rectangle/README_EN.md @@ -41,6 +41,12 @@ ## Solutions +**Solution 1: Monotonic Stack** + +We treat each row as the base of the histogram, and calculate the maximum area of the histogram for each row. + +The time complexity is $O(m \times n)$, where $m$ represents the number of rows in $matrix$, and $n$ represents the number of columns in $matrix$. + ### **Python3** diff --git a/solution/0000-0099/0086.Partition List/README.md b/solution/0000-0099/0086.Partition List/README.md index e6bbca3cb44c1..616af705e35bb 100644 --- a/solution/0000-0099/0086.Partition List/README.md +++ b/solution/0000-0099/0086.Partition List/README.md @@ -42,9 +42,9 @@ **方法一:模拟** -创建两个链表,一个存放小于 `x` 的节点,另一个存放大于等于 `x` 的节点,之后进行拼接即可。 +我们创建两个链表,一个存放小于 $x$ 的节点,另一个存放大于等于 $x$ 的节点,之后进行拼接即可。 -时间复杂度 $O(n),空间复杂度 $O(1)$。其中 $n$ 是原链表的长度。 +时间复杂度 $O(n),其中 $n$ 是原链表的长度。空间复杂度 $O(1)$。 diff --git a/solution/0000-0099/0086.Partition List/README_EN.md b/solution/0000-0099/0086.Partition List/README_EN.md index 77c2ec81ba414..c95f4f179d03a 100644 --- a/solution/0000-0099/0086.Partition List/README_EN.md +++ b/solution/0000-0099/0086.Partition List/README_EN.md @@ -34,6 +34,12 @@ ## Solutions +**Solution 1: Simulation** + +We create two linked lists, one to store nodes less than $x$, and the other to store nodes greater than or equal to $x$. Then we concatenate them. + +The time complexity is $O(n)$, where $n$ is the length of the original linked list. The space complexity is $O(1)$. + ### **Python3** diff --git a/solution/0000-0099/0089.Gray Code/README_EN.md b/solution/0000-0099/0089.Gray Code/README_EN.md index 739f7dd5cdc73..abe208e58b443 100644 --- a/solution/0000-0099/0089.Gray Code/README_EN.md +++ b/solution/0000-0099/0089.Gray Code/README_EN.md @@ -51,7 +51,25 @@ The binary representation of [0,1,3,2] is [00,01,11,10]. ## Solutions -`G(i) = i ^ (i/2)`. +**Solution 1: Binary to Gray Code Conversion** + +Gray code is a type of encoding method that we often encounter in engineering. Its basic feature is that only one bit of binary number is different between any two adjacent codes. + +The rule for converting binary code to binary Gray code is to keep the highest bit of the binary code as the highest bit of the Gray code, and the second highest bit of the Gray code is the XOR of the highest bit and the second highest bit of the binary code. The calculation of the remaining bits of the Gray code is similar to the second highest bit. + +Assume that a binary number is represented as $B_{n-1}B_{n-2}...B_2B_1B_0$, and its Gray code is represented as $G_{n-1}G_{n-2}...G_2G_1G_0$. The highest bit is retained, so $G_{n-1} = B_{n-1}$; and the other bits $G_i = B_{i+1} \oplus B_{i}$, where $i=0,1,2..,n-2$. + +Therefore, for an integer $x$, we can use the function $gray(x)$ to get its Gray code: + +```java +int gray(x) { + return x ^ (x >> 1); +} +``` + +We directly map the integers $[0,..2^n - 1]$ to the corresponding Gray codes to get the answer array. + +The time complexity is $O(2^n)$, where $n$ is the integer given in the problem. Ignoring the space consumption of the answer, the space complexity is $O(1)$. diff --git a/solution/0000-0099/0091.Decode Ways/README_EN.md b/solution/0000-0099/0091.Decode Ways/README_EN.md index 4fba8abd01e0d..433cf19e29e96 100644 --- a/solution/0000-0099/0091.Decode Ways/README_EN.md +++ b/solution/0000-0099/0091.Decode Ways/README_EN.md @@ -61,7 +61,16 @@ ## Solutions -Dynamic programming. +**Solution 1: Dynamic Programming** + +We define $f[i]$ to represent the number of decoding methods for the first $i$ characters of the string. Initially, $f[0]=1$, and the rest $f[i]=0$. + +Consider how $f[i]$ transitions. + +- If the $i$th character (i.e., $s[i-1]$) forms a code on its own, it corresponds to one decoding method, i.e., $f[i]=f[i-1]$. The premise is $s[i-1] \neq 0$. +- If the string formed by the $i-1$th character and the $i$th character is within the range $[1,26]$, then they can be treated as a whole, corresponding to one decoding method, i.e., $f[i] = f[i] + f[i-2]$. The premise is $s[i-2] \neq 0$, and $s[i-2]s[i-1]$ is within the range $[1,26]$. + +The time complexity is $O(n)$, and the space complexity is $O(n)$. Here, $n$ is the length of the string. diff --git a/solution/0000-0099/0092.Reverse Linked List II/README_EN.md b/solution/0000-0099/0092.Reverse Linked List II/README_EN.md index 4dfb0608eb91e..3ec559c047625 100644 --- a/solution/0000-0099/0092.Reverse Linked List II/README_EN.md +++ b/solution/0000-0099/0092.Reverse Linked List II/README_EN.md @@ -36,6 +36,12 @@ ## Solutions +**Solution 1: Simulation** + +Define a dummy head node `dummy`, pointing to the head node `head` of the linked list. Then define a pointer `pre` pointing to `dummy`. Start traversing the linked list from the dummy head node. When you traverse to the `left` node, point `pre` to this node. Then start traversing `right - left + 1` times from this node, and insert the nodes you traverse into the back of `pre`. Finally, return `dummy.next`. + +The time complexity is $O(n)$, and the space complexity is $O(1)$. Here, $n$ is the length of the linked list. + ### **Python3** diff --git a/solution/0000-0099/0093.Restore IP Addresses/README_EN.md b/solution/0000-0099/0093.Restore IP Addresses/README_EN.md index c4c50e9e235a6..c5d9d946913d1 100644 --- a/solution/0000-0099/0093.Restore IP Addresses/README_EN.md +++ b/solution/0000-0099/0093.Restore IP Addresses/README_EN.md @@ -44,7 +44,17 @@ ## Solutions -DFS. +**Solution 1: DFS** + +We define a function $dfs(i)$, which represents the list of IP addresses that can be formed starting from the $i$th position of string $s$. + +The execution steps of function $dfs(i)$ are as follows: + +If $i$ is greater than or equal to the length of string $s$, it means that we have completed the splicing of four segments of the IP address. At this point, we need to check whether it meets the requirements of the four segments of the IP address. If it does, add the current $IP$ to the answer. + +If $i$ is less than the length of string $s$, it means that we still need to splice a segment of the IP address. At this point, we need to determine the value of this segment of the IP address. If the value is greater than $255$, or the current position $i$ is $0$ and the value of several positions after $i$ is greater than $0$, it means that it does not meet the requirements, so we return directly. Otherwise, add it to the IP address list, and continue to search for the next segment of the IP address. + +The time complexity is $O(n \times 3^4)$, and the space complexity is $O(n)$. Here, $n$ is the length of string $s$. diff --git a/solution/0000-0099/0094.Binary Tree Inorder Traversal/README.md b/solution/0000-0099/0094.Binary Tree Inorder Traversal/README.md index 652b514b92ebb..ac3f01820c745 100644 --- a/solution/0000-0099/0094.Binary Tree Inorder Traversal/README.md +++ b/solution/0000-0099/0094.Binary Tree Inorder Traversal/README.md @@ -48,11 +48,13 @@ -**1. 递归遍历** +**方法一:递归遍历** -先递归左子树,再访问根节点,接着递归右子树。 +我们先递归左子树,再访问根节点,接着递归右子树。 -**2. 栈实现非递归遍历** +时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 是二叉树的节点数,空间复杂度主要取决于递归调用的栈空间。 + +**方法二:栈实现非递归遍历** 非递归的思路如下: @@ -61,9 +63,11 @@ 3. 左节点为空时,弹出栈顶元素并处理 4. 重复 2-3 的操作 -**3. Morris 实现中序遍历** +时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 是二叉树的节点数,空间复杂度主要取决于栈空间。 + +**方法三:Morris 实现中序遍历** -Morris 遍历无需使用栈,空间复杂度为 O(1)。核心思想是: +Morris 遍历无需使用栈,空间复杂度为 $O(1)$。核心思想是: 遍历二叉树节点, @@ -73,6 +77,8 @@ Morris 遍历无需使用栈,空间复杂度为 O(1)。核心思想是: - 若前驱节点 prev 的右子树不为空,**将当前节点值添加至结果列表 ans** 中,然后将前驱节点右子树指向空(即解除 prev 与 root 的指向关系),并将当前节点更新为 `root.right`。 3. 循环以上步骤,直至二叉树节点为空,遍历结束。 +时间复杂度 $O(n)$,空间复杂度 $O(1)$。其中 $n$ 是二叉树的节点数。 + ### **Python3** diff --git a/solution/0000-0099/0094.Binary Tree Inorder Traversal/README_EN.md b/solution/0000-0099/0094.Binary Tree Inorder Traversal/README_EN.md index c54e1c8288d57..ff7d900babfdd 100644 --- a/solution/0000-0099/0094.Binary Tree Inorder Traversal/README_EN.md +++ b/solution/0000-0099/0094.Binary Tree Inorder Traversal/README_EN.md @@ -41,11 +41,36 @@ ## Solutions -**1. Recusive Traversal** +**Solution 1: Recursive Traversal** -**2. Non-recursive using Stack** +We first recursively traverse the left subtree, then visit the root node, and finally recursively traverse the right subtree. -**3. Morris Traversal** +The time complexity is $O(n)$, and the space complexity is $O(n)$. Here, $n$ is the number of nodes in the binary tree, and the space complexity mainly depends on the stack space of the recursive call. + +**Solution 2: Stack Implementation for Non-recursive Traversal** + +The non-recursive approach is as follows: + +1. Define a stack `stk`. +2. Push the left nodes of the tree into the stack in sequence. +3. When the left node is null, pop and process the top element of the stack. +4. Repeat steps 2-3. + +The time complexity is $O(n)$, and the space complexity is $O(n)$. Here, $n$ is the number of nodes in the binary tree, and the space complexity mainly depends on the stack space. + +**Solution 3: Morris Implementation for In-order Traversal** + +Morris traversal does not require a stack, so the space complexity is $O(1)$. The core idea is: + +Traverse the binary tree nodes, + +1. If the left subtree of the current node `root` is null, **add the current node value to the result list `ans`**, and update the current node to `root.right`. +2. If the left subtree of the current node `root` is not null, find the rightmost node `prev` of the left subtree (which is the predecessor node of the `root` node in in-order traversal): + - If the right subtree of the predecessor node `prev` is null, point the right subtree of the predecessor node to the current node `root`, and update the current node to `root.left`. + - If the right subtree of the predecessor node `prev` is not null, **add the current node value to the result list `ans`**, then point the right subtree of the predecessor node to null (i.e., disconnect `prev` and `root`), and update the current node to `root.right`. +3. Repeat the above steps until the binary tree node is null, and the traversal ends. + +The time complexity is $O(n)$, and the space complexity is $O(1)$. Here, $n$ is the number of nodes in the binary tree. diff --git a/solution/0000-0099/0096.Unique Binary Search Trees/README.md b/solution/0000-0099/0096.Unique Binary Search Trees/README.md index 42df9a87dab31..bbe1805ff980f 100644 --- a/solution/0000-0099/0096.Unique Binary Search Trees/README.md +++ b/solution/0000-0099/0096.Unique Binary Search Trees/README.md @@ -36,7 +36,15 @@ -假设 n 个节点存在二叉搜索树的个数是 `G(n)`,1 为根节点,2 为根节点,...,n 为根节点,当 1 为根节点时,其左子树节点个数为 0,右子树节点个数为 n-1,同理当 2 为根节点时,其左子树节点个数为 1,右子树节点为 n-2,所以可得 `G(n) = G(0) * G(n-1) + G(1) * (n-2) + ... + G(n-1) * G(0)`。 +**方法一:动态规划** + +我们定义 $f[i]$ 表示 $[1, i]$ 能产生的二叉搜索树的个数,初始时 $f[0] = 1$,答案为 $f[n]$。 + +我们可以枚举节点数 $i$,那么左子树节点数 $j \in [0, i - 1]$,右子树节点数 $k = i - j - 1$,左子树节点数和右子树节点数的组合数为 $f[j] \times f[k]$,因此 $f[i] = \sum_{j = 0}^{i - 1} f[j] \times f[i - j - 1]$。 + +最后返回 $f[n]$ 即可。 + +时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 为节点数。 @@ -47,12 +55,11 @@ ```python class Solution: def numTrees(self, n: int) -> int: - dp = [0] * (n + 1) - dp[0] = 1 - for i in range(1, n + 1): + f = [1] + [0] * n + for i in range(n + 1): for j in range(i): - dp[i] += dp[j] * dp[i - j - 1] - return dp[-1] + f[i] += f[j] * f[i - j - 1] + return f[n] ``` ### **Java** @@ -62,14 +69,14 @@ class Solution: ```java class Solution { public int numTrees(int n) { - int[] dp = new int[n + 1]; - dp[0] = 1; + int[] f = new int[n + 1]; + f[0] = 1; for (int i = 1; i <= n; ++i) { for (int j = 0; j < i; ++j) { - dp[i] += dp[j] * dp[i - j - 1]; + f[i] += f[j] * f[i - j - 1]; } } - return dp[n]; + return f[n]; } } ``` @@ -80,14 +87,14 @@ class Solution { class Solution { public: int numTrees(int n) { - vector dp(n + 1); - dp[0] = 1; + vector f(n + 1); + f[0] = 1; for (int i = 1; i <= n; ++i) { for (int j = 0; j < i; ++j) { - dp[i] += dp[j] * dp[i - j - 1]; + f[i] += f[j] * f[i - j - 1]; } } - return dp[n]; + return f[n]; } }; ``` @@ -96,14 +103,14 @@ public: ```go func numTrees(n int) int { - dp := make([]int, n+1) - dp[0] = 1 + f := make([]int, n+1) + f[0] = 1 for i := 1; i <= n; i++ { for j := 0; j < i; j++ { - dp[i] += dp[j] * dp[i-j-1] + f[i] += f[j] * f[i-j-1] } } - return dp[n] + return f[n] } ``` @@ -113,14 +120,46 @@ func numTrees(n int) int { impl Solution { pub fn num_trees(n: i32) -> i32 { let n = n as usize; - let mut dp = vec![0; n + 1]; - dp[0] = 1; + let mut f = vec![0; n + 1]; + f[0] = 1; for i in 1..=n { for j in 0..i { - dp[i] += dp[j] * dp[i - j - 1]; + f[i] += f[j] * f[i - j - 1]; + } + } + f[n] as i32 + } +} +``` + +### **TypeScript** + +```ts +function numTrees(n: number): number { + const f: number[] = Array(n + 1).fill(0); + f[0] = 1; + for (let i = 1; i <= n; ++i) { + for (let j = 0; j < i; ++j) { + f[i] += f[j] * f[i - j - 1]; + } + } + return f[n]; +} +``` + +### **C#** + +```cs +public class Solution { + public int NumTrees(int n) { + int[] f = new int[n + 1]; + f[0] = 1; + for (int i = 1; i <= n; ++i) { + for (int j = 0; j < i; ++j) { + f[i] += f[j] * f[i - j - 1]; } } - dp[n] as i32 + return f[n]; } } ``` diff --git a/solution/0000-0099/0096.Unique Binary Search Trees/README_EN.md b/solution/0000-0099/0096.Unique Binary Search Trees/README_EN.md index 8d2ca94ccbcb6..1b866b88d4940 100644 --- a/solution/0000-0099/0096.Unique Binary Search Trees/README_EN.md +++ b/solution/0000-0099/0096.Unique Binary Search Trees/README_EN.md @@ -30,6 +30,16 @@ ## Solutions +**Solution 1: Dynamic Programming** + +We define $f[i]$ to represent the number of binary search trees that can be generated from $[1, i]$. Initially, $f[0] = 1$, and the answer is $f[n]$. + +We can enumerate the number of nodes $i$, then the number of nodes in the left subtree $j \in [0, i - 1]$, and the number of nodes in the right subtree $k = i - j - 1$. The number of combinations of the number of nodes in the left subtree and the right subtree is $f[j] \times f[k]$, so $f[i] = \sum_{j = 0}^{i - 1} f[j] \times f[i - j - 1]$. + +Finally, return $f[n]$. + +The time complexity is $O(n)$, and the space complexity is $O(n)$. Here, $n$ is the number of nodes. + ### **Python3** @@ -37,12 +47,11 @@ ```python class Solution: def numTrees(self, n: int) -> int: - dp = [0] * (n + 1) - dp[0] = 1 - for i in range(1, n + 1): + f = [1] + [0] * n + for i in range(n + 1): for j in range(i): - dp[i] += dp[j] * dp[i - j - 1] - return dp[-1] + f[i] += f[j] * f[i - j - 1] + return f[n] ``` ### **Java** @@ -50,14 +59,14 @@ class Solution: ```java class Solution { public int numTrees(int n) { - int[] dp = new int[n + 1]; - dp[0] = 1; + int[] f = new int[n + 1]; + f[0] = 1; for (int i = 1; i <= n; ++i) { for (int j = 0; j < i; ++j) { - dp[i] += dp[j] * dp[i - j - 1]; + f[i] += f[j] * f[i - j - 1]; } } - return dp[n]; + return f[n]; } } ``` @@ -68,14 +77,14 @@ class Solution { class Solution { public: int numTrees(int n) { - vector dp(n + 1); - dp[0] = 1; + vector f(n + 1); + f[0] = 1; for (int i = 1; i <= n; ++i) { for (int j = 0; j < i; ++j) { - dp[i] += dp[j] * dp[i - j - 1]; + f[i] += f[j] * f[i - j - 1]; } } - return dp[n]; + return f[n]; } }; ``` @@ -84,14 +93,14 @@ public: ```go func numTrees(n int) int { - dp := make([]int, n+1) - dp[0] = 1 + f := make([]int, n+1) + f[0] = 1 for i := 1; i <= n; i++ { for j := 0; j < i; j++ { - dp[i] += dp[j] * dp[i-j-1] + f[i] += f[j] * f[i-j-1] } } - return dp[n] + return f[n] } ``` @@ -101,14 +110,46 @@ func numTrees(n int) int { impl Solution { pub fn num_trees(n: i32) -> i32 { let n = n as usize; - let mut dp = vec![0; n + 1]; - dp[0] = 1; + let mut f = vec![0; n + 1]; + f[0] = 1; for i in 1..=n { for j in 0..i { - dp[i] += dp[j] * dp[i - j - 1]; + f[i] += f[j] * f[i - j - 1]; + } + } + f[n] as i32 + } +} +``` + +### **TypeScript** + +```ts +function numTrees(n: number): number { + const f: number[] = Array(n + 1).fill(0); + f[0] = 1; + for (let i = 1; i <= n; ++i) { + for (let j = 0; j < i; ++j) { + f[i] += f[j] * f[i - j - 1]; + } + } + return f[n]; +} +``` + +### **C#** + +```cs +public class Solution { + public int NumTrees(int n) { + int[] f = new int[n + 1]; + f[0] = 1; + for (int i = 1; i <= n; ++i) { + for (int j = 0; j < i; ++j) { + f[i] += f[j] * f[i - j - 1]; } } - dp[n] as i32 + return f[n]; } } ``` diff --git a/solution/0000-0099/0096.Unique Binary Search Trees/Solution.cpp b/solution/0000-0099/0096.Unique Binary Search Trees/Solution.cpp index 21aabb6ba3335..ea316145a9ce5 100644 --- a/solution/0000-0099/0096.Unique Binary Search Trees/Solution.cpp +++ b/solution/0000-0099/0096.Unique Binary Search Trees/Solution.cpp @@ -1,13 +1,13 @@ -class Solution { -public: - int numTrees(int n) { - vector dp(n + 1); - dp[0] = 1; - for (int i = 1; i <= n; ++i) { - for (int j = 0; j < i; ++j) { - dp[i] += dp[j] * dp[i - j - 1]; - } - } - return dp[n]; - } +class Solution { +public: + int numTrees(int n) { + vector f(n + 1); + f[0] = 1; + for (int i = 1; i <= n; ++i) { + for (int j = 0; j < i; ++j) { + f[i] += f[j] * f[i - j - 1]; + } + } + return f[n]; + } }; \ No newline at end of file diff --git a/solution/0000-0099/0096.Unique Binary Search Trees/Solution.cs b/solution/0000-0099/0096.Unique Binary Search Trees/Solution.cs new file mode 100644 index 0000000000000..4e9a6eea897f6 --- /dev/null +++ b/solution/0000-0099/0096.Unique Binary Search Trees/Solution.cs @@ -0,0 +1,12 @@ +public class Solution { + public int NumTrees(int n) { + int[] f = new int[n + 1]; + f[0] = 1; + for (int i = 1; i <= n; ++i) { + for (int j = 0; j < i; ++j) { + f[i] += f[j] * f[i - j - 1]; + } + } + return f[n]; + } +} \ No newline at end of file diff --git a/solution/0000-0099/0096.Unique Binary Search Trees/Solution.go b/solution/0000-0099/0096.Unique Binary Search Trees/Solution.go index eae3a85bc404d..c20c89c323042 100644 --- a/solution/0000-0099/0096.Unique Binary Search Trees/Solution.go +++ b/solution/0000-0099/0096.Unique Binary Search Trees/Solution.go @@ -1,10 +1,10 @@ func numTrees(n int) int { - dp := make([]int, n+1) - dp[0] = 1 + f := make([]int, n+1) + f[0] = 1 for i := 1; i <= n; i++ { for j := 0; j < i; j++ { - dp[i] += dp[j] * dp[i-j-1] + f[i] += f[j] * f[i-j-1] } } - return dp[n] + return f[n] } \ No newline at end of file diff --git a/solution/0000-0099/0096.Unique Binary Search Trees/Solution.java b/solution/0000-0099/0096.Unique Binary Search Trees/Solution.java index 3109d8d70ceb0..3a7a196f25540 100644 --- a/solution/0000-0099/0096.Unique Binary Search Trees/Solution.java +++ b/solution/0000-0099/0096.Unique Binary Search Trees/Solution.java @@ -1,12 +1,12 @@ -class Solution { - public int numTrees(int n) { - int[] dp = new int[n + 1]; - dp[0] = 1; - for (int i = 1; i <= n; ++i) { - for (int j = 0; j < i; ++j) { - dp[i] += dp[j] * dp[i - j - 1]; - } - } - return dp[n]; - } +class Solution { + public int numTrees(int n) { + int[] f = new int[n + 1]; + f[0] = 1; + for (int i = 1; i <= n; ++i) { + for (int j = 0; j < i; ++j) { + f[i] += f[j] * f[i - j - 1]; + } + } + return f[n]; + } } \ No newline at end of file diff --git a/solution/0000-0099/0096.Unique Binary Search Trees/Solution.py b/solution/0000-0099/0096.Unique Binary Search Trees/Solution.py index 7ff784b28719c..16dd7e1a5391d 100644 --- a/solution/0000-0099/0096.Unique Binary Search Trees/Solution.py +++ b/solution/0000-0099/0096.Unique Binary Search Trees/Solution.py @@ -1,8 +1,7 @@ -class Solution: - def numTrees(self, n: int) -> int: - dp = [0] * (n + 1) - dp[0] = 1 - for i in range(1, n + 1): - for j in range(i): - dp[i] += dp[j] * dp[i - j - 1] - return dp[-1] +class Solution: + def numTrees(self, n: int) -> int: + f = [1] + [0] * n + for i in range(n + 1): + for j in range(i): + f[i] += f[j] * f[i - j - 1] + return f[n] diff --git a/solution/0000-0099/0096.Unique Binary Search Trees/Solution.rs b/solution/0000-0099/0096.Unique Binary Search Trees/Solution.rs index 588a416de3516..1cda70eb71f06 100644 --- a/solution/0000-0099/0096.Unique Binary Search Trees/Solution.rs +++ b/solution/0000-0099/0096.Unique Binary Search Trees/Solution.rs @@ -1,13 +1,13 @@ impl Solution { pub fn num_trees(n: i32) -> i32 { let n = n as usize; - let mut dp = vec![0; n + 1]; - dp[0] = 1; + let mut f = vec![0; n + 1]; + f[0] = 1; for i in 1..=n { for j in 0..i { - dp[i] += dp[j] * dp[i - j - 1]; + f[i] += f[j] * f[i - j - 1]; } } - dp[n] as i32 + f[n] as i32 } } diff --git a/solution/0000-0099/0096.Unique Binary Search Trees/Solution.ts b/solution/0000-0099/0096.Unique Binary Search Trees/Solution.ts new file mode 100644 index 0000000000000..0ed6516e24c0a --- /dev/null +++ b/solution/0000-0099/0096.Unique Binary Search Trees/Solution.ts @@ -0,0 +1,10 @@ +function numTrees(n: number): number { + const f: number[] = Array(n + 1).fill(0); + f[0] = 1; + for (let i = 1; i <= n; ++i) { + for (let j = 0; j < i; ++j) { + f[i] += f[j] * f[i - j - 1]; + } + } + return f[n]; +} diff --git a/solution/0000-0099/0097.Interleaving String/README_EN.md b/solution/0000-0099/0097.Interleaving String/README_EN.md index fa443cee8522a..b38333693c8d7 100644 --- a/solution/0000-0099/0097.Interleaving String/README_EN.md +++ b/solution/0000-0099/0097.Interleaving String/README_EN.md @@ -58,6 +58,48 @@ Since s3 can be obtained by interleaving s1 and s2, we return true. ## Solutions +**Solution 1: Memoization Search** + +Let's denote the length of string $s_1$ as $m$ and the length of string $s_2$ as $n$. If $m + n \neq |s_3|$, then $s_3$ is definitely not an interleaving string of $s_1$ and $s_2$, so we return `false`. + +Next, we design a function $dfs(i, j)$, which represents whether the remaining part of $s_3$ can be interleaved from the $i$th character of $s_1$ and the $j$th character of $s_2$. The answer is $dfs(0, 0)$. + +The calculation process of function $dfs(i, j)$ is as follows: + +If $i \geq m$ and $j \geq n$, it means that both $s_1$ and $s_2$ have been traversed, so we return `true`. + +If $i < m$ and $s_1[i] = s_3[i + j]$, it means that the character $s_1[i]$ is part of $s_3[i + j]$. Therefore, we recursively call $dfs(i + 1, j)$ to check whether the next character of $s_1$ can match the current character of $s_2$. If it can match, we return `true`. + +Similarly, if $j < n$ and $s_2[j] = s_3[i + j]$, it means that the character $s_2[j]$ is part of $s_3[i + j]$. Therefore, we recursively call $dfs(i, j + 1)$ to check whether the next character of $s_2$ can match the current character of $s_1$. If it can match, we return `true`. + +Otherwise, we return `false`. + +To avoid repeated calculations, we can use memoization search. + +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 strings $s_1$ and $s_2$ respectively. + +**Solution 2: Dynamic Programming** + +We can convert the memoization search in Solution 1 into dynamic programming. + +We define $f[i][j]$ to represent whether the first $i$ characters of string $s_1$ and the first $j$ characters of string $s_2$ can interleave to form the first $i + j$ characters of string $s_3$. When transitioning states, we can consider whether the current character is obtained from the last character of $s_1$ or the last character of $s_2$. Therefore, we have the state transition equation: + +$$ +f[i][j] = \begin{cases} +f[i - 1][j] & \text{if } s_1[i - 1] = s_3[i + j - 1] \\ +\text{or } f[i][j - 1] & \text{if } s_2[j - 1] = s_3[i + j - 1] \\ +\text{false} & \text{otherwise} +\end{cases} +$$ + +where $f[0][0] = \text{true}$ indicates that an empty string is an interleaving string of two empty strings. + +The answer is $f[m][n]$. + +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 strings $s_1$ and $s_2$ respectively. + +We notice that the state $f[i][j]$ is only related to the states $f[i - 1][j]$, $f[i][j - 1]$, and $f[i - 1][j - 1]$. Therefore, we can use a rolling array to optimize the space complexity, reducing the original space complexity from $O(m \times n)$ to $O(n)$. + ### **Python3** diff --git a/solution/0000-0099/0098.Validate Binary Search Tree/README_EN.md b/solution/0000-0099/0098.Validate Binary Search Tree/README_EN.md index 48221b4b0f346..04f0858e94a9e 100644 --- a/solution/0000-0099/0098.Validate Binary Search Tree/README_EN.md +++ b/solution/0000-0099/0098.Validate Binary Search Tree/README_EN.md @@ -40,6 +40,14 @@ ## Solutions +**Solution 1: Recursion** + +In-order traversal. If it is a valid binary search tree, then the sequence traversed should be monotonically increasing. So, we only need to compare and judge whether the current number traversed is greater than the previous number. + +Alternatively, consider the subtree with `root` as the root, whether all node values are within the valid range, and judge recursively. + +The time complexity is $O(n)$, and the space complexity is $O(n)$. Here, $n$ is the number of nodes in the tree. + ### **Python3** diff --git a/solution/0000-0099/0099.Recover Binary Search Tree/README_EN.md b/solution/0000-0099/0099.Recover Binary Search Tree/README_EN.md index 70d5045022704..a3ef9ad62942b 100644 --- a/solution/0000-0099/0099.Recover Binary Search Tree/README_EN.md +++ b/solution/0000-0099/0099.Recover Binary Search Tree/README_EN.md @@ -36,6 +36,12 @@ ## Solutions +**Solution 1: In-order Traversal** + +In-order traversal of a binary search tree results in an increasing sequence. If two nodes' values are mistakenly swapped, there will definitely be two reverse pairs in the sequence obtained from the in-order traversal. We use `first` and `second` to record the smaller and larger values of these two reverse pairs, respectively. Finally, swapping the values of these two nodes will correct the mistake. + +The time complexity is $O(n)$, and the space complexity is $O(n)$. Here, $n$ is the number of nodes in the binary search tree. + ### **Python3** diff --git a/solution/0100-0199/0100.Same Tree/README_EN.md b/solution/0100-0199/0100.Same Tree/README_EN.md index 03202e3ef831f..810adfe685677 100644 --- a/solution/0100-0199/0100.Same Tree/README_EN.md +++ b/solution/0100-0199/0100.Same Tree/README_EN.md @@ -40,7 +40,21 @@ ## Solutions -DFS or BFS. +**Solution 1: DFS** + +We can use the DFS recursive method to solve this problem. + +First, determine whether the root nodes of the two binary trees are the same. If both root nodes are null, then the two binary trees are the same. If only one of the root nodes is null, then the two binary trees are definitely different. If both root nodes are not null, then determine whether their values are the same. If they are not the same, then the two binary trees are definitely different. If they are the same, then determine whether the left subtrees of the two binary trees are the same and whether the right subtrees are the same. The two binary trees are the same only when all the above conditions are met. + +The time complexity is $O(\min(m, n))$, and the space complexity is $O(\min(m, n))$. Here, $m$ and $n$ are the number of nodes in the two binary trees, respectively. The space complexity mainly depends on the number of layers of recursive calls, which will not exceed the number of nodes in the smaller binary tree. + +**Solution 2: BFS** + +We can also use the BFS iterative method to solve this problem. + +First, add the root nodes of the two binary trees to two queues. Each time, take out one node from each of the two queues and perform the following comparison operations. If the values of the two nodes are not the same, then the structures of the two binary trees are definitely different. If the values of the two nodes are the same, then determine whether the child nodes of the two nodes are null. If only the left child node of one node is null, then the structures of the two binary trees are definitely different. If only the right child node of one node is null, then the structures of the two binary trees are definitely different. If the structures of the left and right child nodes are the same, then add the left and right child nodes of the two nodes to the two queues respectively. For the next iteration, take out one node from each of the two queues for comparison. When both queues are empty at the same time, it means that we have compared all the nodes, and the structures of the two binary trees are completely the same. + +The time complexity is $O(\min(m, n))$, and the space complexity is $O(\min(m, n))$. Here, $m$ and $n$ are the number of nodes in the two binary trees, respectively. The space complexity mainly depends on the number of elements in the queue, which will not exceed the number of nodes in the smaller binary tree. diff --git a/solution/0100-0199/0101.Symmetric Tree/README_EN.md b/solution/0100-0199/0101.Symmetric Tree/README_EN.md index 31031186aa60b..3ab077e2c968e 100644 --- a/solution/0100-0199/0101.Symmetric Tree/README_EN.md +++ b/solution/0100-0199/0101.Symmetric Tree/README_EN.md @@ -34,6 +34,18 @@ ## Solutions +**Solution 1: Recursion** + +We design a function $dfs(root1, root2)$ to determine whether two binary trees are symmetric. The answer is $dfs(root, root)$. + +The logic of the function $dfs(root1, root2)$ is as follows: + +- If both $root1$ and $root2$ are null, then the two binary trees are symmetric, return `true`. +- If only one of $root1$ and $root2$ is null, or if $root1.val \neq root2.val$, then the two binary trees are not symmetric, return `false`. +- Otherwise, determine whether the left subtree of $root1$ is symmetric to the right subtree of $root2$, and whether the right subtree of $root1$ is symmetric to the left subtree of $root2$. Here we use recursion. + +The time complexity is $O(n)$, and the space complexity is $O(n)$. Here, $n$ is the number of nodes in the binary tree. + ### **Python3** diff --git a/solution/0100-0199/0102.Binary Tree Level Order Traversal/README_EN.md b/solution/0100-0199/0102.Binary Tree Level Order Traversal/README_EN.md index a323ff49be9ea..87bc9f9e3c3fa 100644 --- a/solution/0100-0199/0102.Binary Tree Level Order Traversal/README_EN.md +++ b/solution/0100-0199/0102.Binary Tree Level Order Traversal/README_EN.md @@ -38,7 +38,16 @@ ## Solutions -BFS. +**Solution 1: BFS** + +We can use the BFS method to solve this problem. First, enqueue the root node, then continuously perform the following operations until the queue is empty: + +- Traverse all nodes in the current queue, store their values in a temporary array $t$, and then enqueue their child nodes. +- Store the temporary array $t$ in the answer array. + +Finally, return the answer array. + +The time complexity is $O(n)$, and the space complexity is $O(n)$. Here, $n$ is the number of nodes in the binary tree. diff --git a/solution/0100-0199/0103.Binary Tree Zigzag Level Order Traversal/README_EN.md b/solution/0100-0199/0103.Binary Tree Zigzag Level Order Traversal/README_EN.md index b3a9ef4e47763..a0f87f1b6f2a2 100644 --- a/solution/0100-0199/0103.Binary Tree Zigzag Level Order Traversal/README_EN.md +++ b/solution/0100-0199/0103.Binary Tree Zigzag Level Order Traversal/README_EN.md @@ -38,6 +38,12 @@ ## Solutions +**Solution 1: BFS** + +To implement zigzag level order traversal, we need to add a flag `left` on the basis of level order traversal. This flag is used to mark the order of the node values in the current level. If `left` is `true`, the node values of the current level are stored in the result array `ans` from left to right. If `left` is `false`, the node values of the current level are stored in the result array `ans` from right to left. + +The time complexity is $O(n)$, and the space complexity is $O(n)$. Here, $n$ is the number of nodes in the binary tree. + ### **Python3** diff --git a/solution/0100-0199/0104.Maximum Depth of Binary Tree/README_EN.md b/solution/0100-0199/0104.Maximum Depth of Binary Tree/README_EN.md index b0dd3f3fd2d92..0cdee43ac4845 100644 --- a/solution/0100-0199/0104.Maximum Depth of Binary Tree/README_EN.md +++ b/solution/0100-0199/0104.Maximum Depth of Binary Tree/README_EN.md @@ -33,6 +33,12 @@ ## Solutions +**Solution 1: Recursion** + +Recursively traverse the left and right subtrees, calculate the maximum depth of the left and right subtrees, and then take the maximum value plus $1$. + +The time complexity is $O(n)$, where $n$ is the number of nodes in the binary tree. Each node is traversed only once in the recursion. + ### **Python3** diff --git a/solution/0100-0199/0105.Construct Binary Tree from Preorder and Inorder Traversal/README_EN.md b/solution/0100-0199/0105.Construct Binary Tree from Preorder and Inorder Traversal/README_EN.md index ea52dc7232c33..1ce3f1c1e41df 100644 --- a/solution/0100-0199/0105.Construct Binary Tree from Preorder and Inorder Traversal/README_EN.md +++ b/solution/0100-0199/0105.Construct Binary Tree from Preorder and Inorder Traversal/README_EN.md @@ -36,6 +36,20 @@ ## Solutions +**Solution 1: Recursion** + +The first node $preorder[0]$ in the preorder sequence is the root node. We find the position $i$ of the root node in the inorder sequence, which divides the inorder sequence into the left subtree $inorder[0..i]$ and the right subtree $inorder[i+1..]$. + +Through the intervals of the left and right subtrees, we can calculate the number of nodes in the left and right subtrees, assumed to be $m$ and $n$ respectively. Then in the preorder nodes, the $m$ nodes following the root node are the left subtree, and the $n$ nodes after that are the right subtree. + +We can solve this recursively. + +> Preorder traversal: traverse the root node first, then traverse the left and right subtrees; Inorder traversal: traverse the left subtree first, then traverse the root node, and finally traverse the right subtree. + +The time complexity is $O(n)$, and the space complexity is $O(n)$. Here, $n$ is the number of nodes in the binary tree. + +If the node values given in the problem have duplicates, then we only need to record all the positions where each node value appears, and then recursively construct the tree. + ### **Python3** diff --git a/solution/0100-0199/0106.Construct Binary Tree from Inorder and Postorder Traversal/README_EN.md b/solution/0100-0199/0106.Construct Binary Tree from Inorder and Postorder Traversal/README_EN.md index 04ee7ec6251be..7db8d2e67360a 100644 --- a/solution/0100-0199/0106.Construct Binary Tree from Inorder and Postorder Traversal/README_EN.md +++ b/solution/0100-0199/0106.Construct Binary Tree from Inorder and Postorder Traversal/README_EN.md @@ -36,6 +36,12 @@ ## Solutions +**Solution 1: Recursion** + +The approach is the same as in [105. Construct Binary Tree from Preorder and Inorder Traversal](/solution/0100-0199/0105.Construct%20Binary%20Tree%20from%20Preorder%20and%20Inorder%20Traversal/README_EN.md). + +The time complexity is $O(n)$, and the space complexity is $O(n)$. Here, $n$ is the number of nodes in the binary tree. + ### **Python3** diff --git a/solution/0100-0199/0107.Binary Tree Level Order Traversal II/README.md b/solution/0100-0199/0107.Binary Tree Level Order Traversal II/README.md index 152bfbca35c4e..a433a7561637b 100644 --- a/solution/0100-0199/0107.Binary Tree Level Order Traversal II/README.md +++ b/solution/0100-0199/0107.Binary Tree Level Order Traversal II/README.md @@ -44,7 +44,11 @@ -同 [102](/solution/0100-0199/0102.Binary%20Tree%20Level%20Order%20Traversal/README.md),最后反转一下结果即可。 +**方法一:BFS** + +思路同 [102](/solution/0100-0199/0102.Binary%20Tree%20Level%20Order%20Traversal/README.md),最后反转一下结果即可。 + +时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 是二叉树的节点个数。 diff --git a/solution/0100-0199/0107.Binary Tree Level Order Traversal II/README_EN.md b/solution/0100-0199/0107.Binary Tree Level Order Traversal II/README_EN.md index 9031190a766de..7546cce28d74a 100644 --- a/solution/0100-0199/0107.Binary Tree Level Order Traversal II/README_EN.md +++ b/solution/0100-0199/0107.Binary Tree Level Order Traversal II/README_EN.md @@ -38,6 +38,12 @@ ## Solutions +**Solution 1: BFS** + +The approach is the same as in [102. Binary Tree Level Order Traversal](/solution/0100-0199/0102.Binary%20Tree%20Level%20Order%20Traversal/README_EN.md), just reverse the result in the end. + +The time complexity is $O(n)$, and the space complexity is $O(n)$. Here, $n$ is the number of nodes in the binary tree. + ### **Python3** diff --git a/solution/0100-0199/0108.Convert Sorted Array to Binary Search Tree/README_EN.md b/solution/0100-0199/0108.Convert Sorted Array to Binary Search Tree/README_EN.md index e8709c0726d1b..185b0e2fa817f 100644 --- a/solution/0100-0199/0108.Convert Sorted Array to Binary Search Tree/README_EN.md +++ b/solution/0100-0199/0108.Convert Sorted Array to Binary Search Tree/README_EN.md @@ -35,6 +35,22 @@ ## Solutions +**Solution 1: Binary Search + Recursion** + +We design a recursive function $dfs(l, r)$, which indicates that the node values of the current binary search tree to be constructed are all within the index range $[l, r]$ of the array `nums`. This function returns the root node of the constructed binary search tree. + +The execution process of the function $dfs(l, r)$ is as follows: + +1. If $l > r$, it means the current array is empty, return `null`. +2. If $l \leq r$, take the element with the index $mid = \lfloor \frac{l + r}{2} \rfloor$ in the array as the root node of the current binary search tree, where $\lfloor x \rfloor$ represents rounding down $x$. +3. Recursively construct the left subtree of the current binary search tree, whose root node value is the element with the index $mid - 1$ in the array, and the node values of the left subtree are all within the index range $[l, mid - 1]$ of the array. +4. Recursively construct the right subtree of the current binary search tree, whose root node value is the element with the index $mid + 1$ in the array, and the node values of the right subtree are all within the index range $[mid + 1, r]$ of the array. +5. Return the root node of the current binary search tree. + +The answer is the return value of the function $dfs(0, n - 1)$. + +The time complexity is $O(n)$, and the space complexity is $O(\log n)$. Here, $n$ is the length of the array `nums`. + ### **Python3** diff --git a/solution/0100-0199/0110.Balanced Binary Tree/README_EN.md b/solution/0100-0199/0110.Balanced Binary Tree/README_EN.md index 08909de30499c..6f090fd7f16e2 100644 --- a/solution/0100-0199/0110.Balanced Binary Tree/README_EN.md +++ b/solution/0100-0199/0110.Balanced Binary Tree/README_EN.md @@ -38,6 +38,17 @@ ## Solutions +**Solution 1: Bottom-Up Recursion** + +We define a function $height(root)$ to calculate the height of a binary tree, with the following logic: + +- If the binary tree $root$ is null, return $0$. +- Otherwise, recursively calculate the heights of the left and right subtrees, denoted as $l$ and $r$ respectively. If either $l$ or $r$ is $-1$, or the absolute difference between $l$ and $r$ is greater than $1$, then return $-1$. Otherwise, return $max(l, r) + 1$. + +Therefore, if the function $height(root)$ returns $-1$, it means the binary tree $root$ is not balanced. Otherwise, it is balanced. + +The time complexity is $O(n)$, and the space complexity is $O(n)$. Here, $n$ is the number of nodes in the binary tree. + ### **Python3** diff --git a/solution/0100-0199/0111.Minimum Depth of Binary Tree/README_EN.md b/solution/0100-0199/0111.Minimum Depth of Binary Tree/README_EN.md index 6da75841094e0..84e898728c3b8 100644 --- a/solution/0100-0199/0111.Minimum Depth of Binary Tree/README_EN.md +++ b/solution/0100-0199/0111.Minimum Depth of Binary Tree/README_EN.md @@ -35,6 +35,18 @@ ## Solutions +**Solution 1: Recursion** + +The termination condition for recursion is when the current node is null, at which point return $0$. If one of the left or right subtrees of the current node is null, return the minimum depth of the non-null subtree plus $1$. If neither the left nor right subtree of the current node is null, return the smaller value of the minimum depths of the left and right subtrees plus $1$. + +The time complexity is $O(n)$, and the space complexity is $O(n)$. Here, $n$ is the number of nodes in the binary tree. + +**Solution 2: BFS** + +Use a queue to implement breadth-first search, initially adding the root node to the queue. Each time, take a node from the queue. If this node is a leaf node, directly return the current depth. If this node is not a leaf node, add all non-null child nodes of this node to the queue. Continue to search the next layer of nodes until a leaf node is found. + +The time complexity is $O(n)$, and the space complexity is $O(n)$. Here, $n$ is the number of nodes in the binary tree. + ### **Python3** diff --git a/solution/0100-0199/0112.Path Sum/README_EN.md b/solution/0100-0199/0112.Path Sum/README_EN.md index 729a9dc91a565..e797496f5b2ab 100644 --- a/solution/0100-0199/0112.Path Sum/README_EN.md +++ b/solution/0100-0199/0112.Path Sum/README_EN.md @@ -47,6 +47,12 @@ There is no root-to-leaf path with sum = 5. ## Solutions +**Solution 1: Recursion** + +Starting from the root node, recursively traverse the tree and update the value of the node to the path sum from the root node to that node. When you traverse to a leaf node, determine whether this path sum is equal to the target value. If it is equal, return `true`, otherwise return `false`. + +The time complexity is $O(n)$, where $n$ is the number of nodes in the binary tree. Each node is visited once. + ### **Python3** diff --git a/solution/0100-0199/0113.Path Sum II/README_EN.md b/solution/0100-0199/0113.Path Sum II/README_EN.md index 8a2de0c0af4c8..bc2ffb562085b 100644 --- a/solution/0100-0199/0113.Path Sum II/README_EN.md +++ b/solution/0100-0199/0113.Path Sum II/README_EN.md @@ -44,6 +44,12 @@ ## Solutions +**Solution 1: DFS** + +We start from the root node, recursively traverse all paths from the root node to the leaf nodes, and record the path sum. When we traverse to a leaf node, if the current path sum equals `targetSum`, then we add this path to the answer. + +The time complexity is $O(n^2)$, where $n$ is the number of nodes in the binary tree. The space complexity is $O(n)$. + ### **Python3** diff --git a/solution/0100-0199/0114.Flatten Binary Tree to Linked List/README.md b/solution/0100-0199/0114.Flatten Binary Tree to Linked List/README.md index 74da7d185f505..2ad1a5440e67b 100644 --- a/solution/0100-0199/0114.Flatten Binary Tree to Linked List/README.md +++ b/solution/0100-0199/0114.Flatten Binary Tree to Linked List/README.md @@ -59,7 +59,7 @@ 因此,对于当前节点,如果其左子节点不为空,我们找到左子树的最右节点,作为前驱节点,然后将当前节点的右子节点赋给前驱节点的右子节点。然后将当前节点的左子节点赋给当前节点的右子节点,并将当前节点的左子节点置为空。然后将当前节点的右子节点作为下一个节点,继续处理,直至所有节点处理完毕。 -时间复杂度 $O(n)$,其中 $n$ 是树中节点的个数。空间复杂度 O(1)$。 +时间复杂度 $O(n)$,其中 $n$ 是树中节点的个数。空间复杂度 $O(1)$。 diff --git a/solution/0100-0199/0114.Flatten Binary Tree to Linked List/README_EN.md b/solution/0100-0199/0114.Flatten Binary Tree to Linked List/README_EN.md index 46758c585bdd3..5e3dda1af937d 100644 --- a/solution/0100-0199/0114.Flatten Binary Tree to Linked List/README_EN.md +++ b/solution/0100-0199/0114.Flatten Binary Tree to Linked List/README_EN.md @@ -46,6 +46,14 @@ ## Solutions +**Solution 1: Find Predecessor Node** + +The visit order of preorder traversal is "root, left subtree, right subtree". After the last node of the left subtree is visited, the right subtree node of the root node will be visited next. + +Therefore, for the current node, if its left child node is not null, we find the rightmost node of the left subtree as the predecessor node, and then assign the right child node of the current node to the right child node of the predecessor node. Then assign the left child node of the current node to the right child node of the current node, and set the left child node of the current node to null. Then take the right child node of the current node as the next node and continue processing until all nodes are processed. + +The time complexity is $O(n)$, where $n$ is the number of nodes in the tree. The space complexity is $O(1)$. + ### **Python3** diff --git a/solution/0100-0199/0116.Populating Next Right Pointers in Each Node/README_EN.md b/solution/0100-0199/0116.Populating Next Right Pointers in Each Node/README_EN.md index df1614697e80f..1e92a00009663 100644 --- a/solution/0100-0199/0116.Populating Next Right Pointers in Each Node/README_EN.md +++ b/solution/0100-0199/0116.Populating Next Right Pointers in Each Node/README_EN.md @@ -53,6 +53,20 @@ struct Node { ## Solutions +**Solution 1: BFS** + +Use a queue for level order traversal, and each time you traverse a level, connect the nodes of the current level in order. + +The time complexity is $O(n)$, and the space complexity is $O(n)$. Here, $n$ is the number of nodes in the binary tree. + +**Solution 2: DFS** + +Use recursion for preorder traversal, and each time you traverse to a node, connect its left and right child nodes in order. + +Specifically, we design a function $dfs(left, right)$, which points the $next$ pointer of the $left$ node to the $right$ node. In the function, we first check whether $left$ and $right$ are null. If both are not null, point $left.next$ to $right$, and then recursively call $dfs(left.left, left.right)$, $dfs(left.right, right.left)$, $dfs(right.left, right.right)$. + +The time complexity is $O(n)$, and the space complexity is $O(n)$. Here, $n$ is the number of nodes in the binary tree. + ### **Python3** diff --git a/solution/0100-0199/0118.Pascal's Triangle/README_EN.md b/solution/0100-0199/0118.Pascal's Triangle/README_EN.md index 3128d0649a475..9237c2fdefc48 100644 --- a/solution/0100-0199/0118.Pascal's Triangle/README_EN.md +++ b/solution/0100-0199/0118.Pascal's Triangle/README_EN.md @@ -25,6 +25,12 @@ ## Solutions +**Solution 1: Simulation** + +First, we create an answer array $f$, and then set the first row of $f$ to $[1]$. Next, starting from the second row, the first and last elements of each row are $1$, and the other elements are calculated by $f[i][j] = f[i - 1][j - 1] + f[i - 1][j]$. + +The time complexity is $O(n^2)$, and the space complexity is $O(n^2)$. Here, $n$ is the number of rows. + ### **Python3** diff --git a/solution/0100-0199/0119.Pascal's Triangle II/README_EN.md b/solution/0100-0199/0119.Pascal's Triangle II/README_EN.md index 14bb47eb02e27..0e73637c3021b 100644 --- a/solution/0100-0199/0119.Pascal's Triangle II/README_EN.md +++ b/solution/0100-0199/0119.Pascal's Triangle II/README_EN.md @@ -31,6 +31,16 @@ ## Solutions +**Solution 1: Recursion** + +We create an array $f$ of length $rowIndex + 1$, initially all elements are $1$. + +Next, starting from the second row, we calculate the value of the $j$th element in the current row from back to front, $f[j] = f[j] + f[j - 1]$, where $j \in [1, i - 1]$. + +Finally, return $f$. + +The time complexity is $O(n^2)$, and the space complexity is $O(n)$. Here, $n$ is the given number of rows. + ### **Python3**