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:
Yudong Jin
2024-05-06 14:44:48 +08:00
committed by GitHub
parent 8e60d12151
commit c4a7966882
99 changed files with 615 additions and 259 deletions

View File

@ -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>"
![Trying and retreating](backtracking_algorithm.assets/preorder_find_paths_step1.png)
@ -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.
![Pruning based on constraints](backtracking_algorithm.assets/preorder_find_constrained_paths.png)
@ -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.
![Comparison of retaining and removing the return in the search process](backtracking_algorithm.assets/backtrack_remove_return_or_not.png)

View File

@ -8,7 +8,7 @@ As shown in the figure below, when $n = 4$, there are two solutions. From the pe
![Solution to the 4 queens problem](n_queens_problem.assets/solution_4_queens.png)
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 `/`.
![Constraints of the n queens problem](n_queens_problem.assets/n_queens_constraints.png)
@ -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.
![Row-by-row placing strategy](n_queens_problem.assets/n_queens_placing.png)
@ -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.

View File

@ -6,7 +6,7 @@ The table below lists several example data, including the input arrays and their
<p align="center"> Table <id> &nbsp; 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.
![Permutation recursive tree](permutations_problem.assets/permutations_i.png)
@ -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.
![Permutation pruning example](permutations_problem.assets/permutations_i_pruning.png)
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.
![Duplicate permutations](permutations_problem.assets/permutations_ii.png)
@ -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.
![Scope of the two pruning conditions](permutations_problem.assets/permutations_ii_pruning_summary.png)

View File

@ -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.
![Subset search and pruning out of bounds](subset_sum_problem.assets/subset_sum_i_naive.png)
@ -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.
![Subset sum I backtracking process](subset_sum_problem.assets/subset_sum_i.png)
@ -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.
![Duplicate subsets caused by equal elements](subset_sum_problem.assets/subset_sum_ii_repeat.png)
@ -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.
![Subset sum II backtracking process](subset_sum_problem.assets/subset_sum_ii.png)