mirror of
https://github.com/krahets/hello-algo.git
synced 2025-11-02 04:31:55 +08:00
Bug fixes and improvements (#1348)
* Add "reference" for EN version. Bug fixes. * Unify the figure reference as "the figure below" and "the figure above". Bug fixes. * Format the EN markdown files. * Replace "" with <u></u> for EN version and bug fixes * Fix biary_tree_dfs.png * Fix biary_tree_dfs.png * Fix zh-hant/biary_tree_dfs.png * Fix heap_sort_step1.png * Sync zh and zh-hant versions. * Bug fixes * Fix EN figures * Bug fixes * Fix the figure labels for EN version
This commit is contained in:
@ -8,7 +8,7 @@ Backtracking typically employs "depth-first search" to traverse the solution spa
|
||||
|
||||
Given a binary tree, search and record all nodes with a value of $7$, please return a list of nodes.
|
||||
|
||||
For this problem, we traverse this tree in preorder and check if the current node's value is $7$. If it is, we add the node's value to the result list `res`. The relevant process is shown in the following diagram and code:
|
||||
For this problem, we traverse this tree in preorder and check if the current node's value is $7$. If it is, we add the node's value to the result list `res`. The relevant process is shown in the figure below:
|
||||
|
||||
```src
|
||||
[file]{preorder_traversal_i_compact}-[class]{}-[func]{pre_order}
|
||||
@ -36,7 +36,7 @@ Based on the code from Example One, we need to use a list `path` to record the v
|
||||
|
||||
In each "try", we record the path by adding the current node to `path`; before "retreating", we need to pop the node from `path` **to restore the state before this attempt**.
|
||||
|
||||
Observe the process shown below, **we can understand trying and retreating as "advancing" and "undoing"**, two operations that are reverse to each other.
|
||||
Observe the process shown in the figure below, **we can understand trying and retreating as "advancing" and "undoing"**, two operations that are reverse to each other.
|
||||
|
||||
=== "<1>"
|
||||

|
||||
@ -85,7 +85,7 @@ To meet the above constraints, **we need to add a pruning operation**: during th
|
||||
[file]{preorder_traversal_iii_compact}-[class]{}-[func]{pre_order}
|
||||
```
|
||||
|
||||
"Pruning" is a very vivid noun. As shown in the diagram below, in the search process, **we "cut off" the search branches that do not meet the constraints**, avoiding many meaningless attempts, thus enhancing the search efficiency.
|
||||
"Pruning" is a very vivid noun. As shown in the figure below, in the search process, **we "cut off" the search branches that do not meet the constraints**, avoiding many meaningless attempts, thus enhancing the search efficiency.
|
||||
|
||||

|
||||
|
||||
@ -421,7 +421,7 @@ Next, we solve Example Three based on the framework code. The `state` is the nod
|
||||
[file]{preorder_traversal_iii_template}-[class]{}-[func]{backtrack}
|
||||
```
|
||||
|
||||
As per the requirements, after finding a node with a value of $7$, the search should continue, **thus the `return` statement after recording the solution should be removed**. The following diagram compares the search processes with and without retaining the `return` statement.
|
||||
As per the requirements, after finding a node with a value of $7$, the search should continue, **thus the `return` statement after recording the solution should be removed**. The figure below compares the search processes with and without retaining the `return` statement.
|
||||
|
||||

|
||||
|
||||
|
||||
@ -8,7 +8,7 @@ As shown in the figure below, when $n = 4$, there are two solutions. From the pe
|
||||
|
||||

|
||||
|
||||
The following image shows the three constraints of this problem: **multiple queens cannot be on the same row, column, or diagonal**. It is important to note that diagonals are divided into the main diagonal `\` and the secondary diagonal `/`.
|
||||
The figure below shows the three constraints of this problem: **multiple queens cannot be on the same row, column, or diagonal**. It is important to note that diagonals are divided into the main diagonal `\` and the secondary diagonal `/`.
|
||||
|
||||

|
||||
|
||||
@ -18,7 +18,7 @@ As the number of queens equals the number of rows on the chessboard, both being
|
||||
|
||||
This means that we can adopt a row-by-row placing strategy: starting from the first row, place one queen per row until the last row is reached.
|
||||
|
||||
The image below shows the row-by-row placing process for the 4 queens problem. Due to space limitations, the image only expands one search branch of the first row, and prunes any placements that do not meet the column and diagonal constraints.
|
||||
The figure below shows the row-by-row placing process for the 4 queens problem. Due to space limitations, the figure only expands one search branch of the first row, and prunes any placements that do not meet the column and diagonal constraints.
|
||||
|
||||

|
||||
|
||||
@ -30,7 +30,7 @@ To satisfy column constraints, we can use a boolean array `cols` of length $n$ t
|
||||
|
||||
How about the diagonal constraints? Let the row and column indices of a cell on the chessboard be $(row, col)$. By selecting a specific main diagonal, we notice that the difference $row - col$ is the same for all cells on that diagonal, **meaning that $row - col$ is a constant value on that diagonal**.
|
||||
|
||||
Thus, if two cells satisfy $row_1 - col_1 = row_2 - col_2$, they are definitely on the same main diagonal. Using this pattern, we can utilize the array `diags1` shown below to track whether a queen is on any main diagonal.
|
||||
Thus, if two cells satisfy $row_1 - col_1 = row_2 - col_2$, they are definitely on the same main diagonal. Using this pattern, we can utilize the array `diags1` shown in the figure below to track whether a queen is on any main diagonal.
|
||||
|
||||
Similarly, **the sum $row + col$ is a constant value for all cells on a secondary diagonal**. We can also use the array `diags2` to handle secondary diagonal constraints.
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ The table below lists several example data, including the input arrays and their
|
||||
|
||||
<p align="center"> Table <id> Permutation examples </p>
|
||||
|
||||
| Input array | Permutations |
|
||||
| Input array | Permutations |
|
||||
| :---------- | :----------------------------------------------------------------- |
|
||||
| $[1]$ | $[1]$ |
|
||||
| $[1, 2]$ | $[1, 2], [2, 1]$ |
|
||||
@ -22,7 +22,7 @@ From the perspective of the backtracking algorithm, **we can imagine the process
|
||||
|
||||
From the code perspective, the candidate set `choices` contains all elements of the input array, and the state `state` contains elements that have been selected so far. Please note that each element can only be chosen once, **thus all elements in `state` must be unique**.
|
||||
|
||||
As shown in the following figure, we can unfold the search process into a recursive tree, where each node represents the current state `state`. Starting from the root node, after three rounds of choices, we reach the leaf nodes, each corresponding to a permutation.
|
||||
As shown in the figure below, we can unfold the search process into a recursive tree, where each node represents the current state `state`. Starting from the root node, after three rounds of choices, we reach the leaf nodes, each corresponding to a permutation.
|
||||
|
||||

|
||||
|
||||
@ -33,11 +33,11 @@ To ensure that each element is selected only once, we consider introducing a boo
|
||||
- After making the choice `choice[i]`, we set `selected[i]` to $\text{True}$, indicating it has been chosen.
|
||||
- When iterating through the choice list `choices`, skip all nodes that have already been selected, i.e., prune.
|
||||
|
||||
As shown in the following figure, suppose we choose 1 in the first round, 3 in the second round, and 2 in the third round, we need to prune the branch of element 1 in the second round and elements 1 and 3 in the third round.
|
||||
As shown in the figure below, suppose we choose 1 in the first round, 3 in the second round, and 2 in the third round, we need to prune the branch of element 1 in the second round and elements 1 and 3 in the third round.
|
||||
|
||||

|
||||
|
||||
Observing the above figure, this pruning operation reduces the search space size from $O(n^n)$ to $O(n!)$.
|
||||
Observing the figure above, this pruning operation reduces the search space size from $O(n^n)$ to $O(n!)$.
|
||||
|
||||
### Code implementation
|
||||
|
||||
@ -55,7 +55,7 @@ After understanding the above information, we can "fill in the blanks" in the fr
|
||||
|
||||
Suppose the input array is $[1, 1, 2]$. To differentiate the two duplicate elements $1$, we mark the second $1$ as $\hat{1}$.
|
||||
|
||||
As shown in the following figure, half of the permutations generated by the above method are duplicates.
|
||||
As shown in the figure below, half of the permutations generated by the above method are duplicates.
|
||||
|
||||

|
||||
|
||||
@ -63,7 +63,7 @@ So, how do we eliminate duplicate permutations? Most directly, consider using a
|
||||
|
||||
### Pruning of equal elements
|
||||
|
||||
Observing the following figure, in the first round, choosing $1$ or $\hat{1}$ results in identical permutations under both choices, thus we should prune $\hat{1}$.
|
||||
Observing the figure below, in the first round, choosing $1$ or $\hat{1}$ results in identical permutations under both choices, thus we should prune $\hat{1}$.
|
||||
|
||||
Similarly, after choosing $2$ in the first round, choosing $1$ and $\hat{1}$ in the second round also produces duplicate branches, so we should also prune $\hat{1}$ in the second round.
|
||||
|
||||
@ -90,6 +90,6 @@ Please note, although both `selected` and `duplicated` are used for pruning, the
|
||||
- **Repeated choice pruning**: There is only one `selected` throughout the search process. It records which elements are currently in the state, aiming to prevent an element from appearing repeatedly in `state`.
|
||||
- **Equal element pruning**: Each round of choices (each call to the `backtrack` function) contains a `duplicated`. It records which elements have been chosen in the current traversal (`for` loop), aiming to ensure equal elements are selected only once.
|
||||
|
||||
The following figure shows the scope of the two pruning conditions. Note, each node in the tree represents a choice, and the nodes from the root to the leaf form a permutation.
|
||||
The figure below shows the scope of the two pruning conditions. Note, each node in the tree represents a choice, and the nodes from the root to the leaf form a permutation.
|
||||
|
||||

|
||||
|
||||
@ -23,7 +23,7 @@ Unlike the permutation problem, **elements in this problem can be chosen an unli
|
||||
|
||||
Inputting the array $[3, 4, 5]$ and target element $9$ into the above code yields the results $[3, 3, 3], [4, 5], [5, 4]$. **Although it successfully finds all subsets with a sum of $9$, it includes the duplicate subset $[4, 5]$ and $[5, 4]$**.
|
||||
|
||||
This is because the search process distinguishes the order of choices, however, subsets do not distinguish the choice order. As shown in the following figure, choosing $4$ before $5$ and choosing $5$ before $4$ are different branches, but correspond to the same subset.
|
||||
This is because the search process distinguishes the order of choices, however, subsets do not distinguish the choice order. As shown in the figure below, choosing $4$ before $5$ and choosing $5$ before $4$ are different branches, but correspond to the same subset.
|
||||
|
||||

|
||||
|
||||
@ -34,7 +34,7 @@ To eliminate duplicate subsets, **a straightforward idea is to deduplicate the r
|
||||
|
||||
### Duplicate subset pruning
|
||||
|
||||
**We consider deduplication during the search process through pruning**. Observing the following figure, duplicate subsets are generated when choosing array elements in different orders, for example in the following situations.
|
||||
**We consider deduplication during the search process through pruning**. Observing the figure below, duplicate subsets are generated when choosing array elements in different orders, for example in the following situations.
|
||||
|
||||
1. When choosing $3$ in the first round and $4$ in the second round, all subsets containing these two elements are generated, denoted as $[3, 4, \dots]$.
|
||||
2. Later, when $4$ is chosen in the first round, **the second round should skip $3$** because the subset $[4, 3, \dots]$ generated by this choice completely duplicates the subset from step `1.`.
|
||||
@ -62,7 +62,7 @@ Besides, we have made the following two optimizations to the code.
|
||||
[file]{subset_sum_i}-[class]{}-[func]{subset_sum_i}
|
||||
```
|
||||
|
||||
The following figure shows the overall backtracking process after inputting the array $[3, 4, 5]$ and target element $9$ into the above code.
|
||||
The figure below shows the overall backtracking process after inputting the array $[3, 4, 5]$ and target element $9$ into the above code.
|
||||
|
||||

|
||||
|
||||
@ -74,7 +74,7 @@ The following figure shows the overall backtracking process after inputting the
|
||||
|
||||
Compared to the previous question, **this question's input array may contain duplicate elements**, introducing new problems. For example, given the array $[4, \hat{4}, 5]$ and target element $9$, the existing code's output results in $[4, 5], [\hat{4}, 5]$, resulting in duplicate subsets.
|
||||
|
||||
**The reason for this duplication is that equal elements are chosen multiple times in a certain round**. In the following figure, the first round has three choices, two of which are $4$, generating two duplicate search branches, thus outputting duplicate subsets; similarly, the two $4$s in the second round also produce duplicate subsets.
|
||||
**The reason for this duplication is that equal elements are chosen multiple times in a certain round**. In the figure below, the first round has three choices, two of which are $4$, generating two duplicate search branches, thus outputting duplicate subsets; similarly, the two $4$s in the second round also produce duplicate subsets.
|
||||
|
||||

|
||||
|
||||
@ -90,6 +90,6 @@ At the same time, **this question stipulates that each array element can only be
|
||||
[file]{subset_sum_ii}-[class]{}-[func]{subset_sum_ii}
|
||||
```
|
||||
|
||||
The following figure shows the backtracking process for the array $[4, 4, 5]$ and target element $9$, including four types of pruning operations. Please combine the illustration with the code comments to understand the entire search process and how each type of pruning operation works.
|
||||
The figure below shows the backtracking process for the array $[4, 4, 5]$ and target element $9$, including four types of pruning operations. Please combine the illustration with the code comments to understand the entire search process and how each type of pruning operation works.
|
||||
|
||||

|
||||
|
||||
Reference in New Issue
Block a user