mirror of
https://github.com/krahets/hello-algo.git
synced 2024-12-25 13:16:29 +08:00
Update preorder_traversal_iii.
This commit is contained in:
parent
90af225dae
commit
b067016bfa
20 changed files with 48 additions and 56 deletions
|
@ -37,7 +37,6 @@ void backtrack(vector<TreeNode *> &state, vector<TreeNode *> &choices, vector<ve
|
||||||
if (isSolution(state)) {
|
if (isSolution(state)) {
|
||||||
// 记录解
|
// 记录解
|
||||||
recordSolution(state, res);
|
recordSolution(state, res);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
// 遍历所有选择
|
// 遍历所有选择
|
||||||
for (TreeNode *choice : choices) {
|
for (TreeNode *choice : choices) {
|
||||||
|
|
|
@ -41,7 +41,7 @@ public class preorder_traversal_iii_compact {
|
||||||
res = new List<List<TreeNode>>();
|
res = new List<List<TreeNode>>();
|
||||||
preOrder(root);
|
preOrder(root);
|
||||||
|
|
||||||
Console.WriteLine("\n输出所有根节点到节点 7 的路径,路径中不包含值为 3 的节点,仅包含一个值为 7 的节点");
|
Console.WriteLine("\n输出所有根节点到节点 7 的路径,路径中不包含值为 3 的节点");
|
||||||
foreach (List<TreeNode> path in res) {
|
foreach (List<TreeNode> path in res) {
|
||||||
PrintUtil.PrintList(path.Select(p => p.val).ToList());
|
PrintUtil.PrintList(path.Select(p => p.val).ToList());
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,6 @@ public class preorder_traversal_iii_template {
|
||||||
if (isSolution(state)) {
|
if (isSolution(state)) {
|
||||||
// 记录解
|
// 记录解
|
||||||
recordSolution(state, res);
|
recordSolution(state, res);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
// 遍历所有选择
|
// 遍历所有选择
|
||||||
foreach (TreeNode choice in choices) {
|
foreach (TreeNode choice in choices) {
|
||||||
|
|
|
@ -59,7 +59,7 @@ func TestPreorderTraversalIIICompact(t *testing.T) {
|
||||||
res := make([][]*TreeNode, 0)
|
res := make([][]*TreeNode, 0)
|
||||||
preOrderIII(root, &res, &path)
|
preOrderIII(root, &res, &path)
|
||||||
|
|
||||||
fmt.Println("\n输出所有根节点到节点 7 的路径,路径中不包含值为 3 的节点,仅包含一个值为 7 的节点")
|
fmt.Println("\n输出所有根节点到节点 7 的路径,路径中不包含值为 3 的节点")
|
||||||
for _, path := range res {
|
for _, path := range res {
|
||||||
for _, node := range path {
|
for _, node := range path {
|
||||||
fmt.Printf("%v ", node.Val)
|
fmt.Printf("%v ", node.Val)
|
||||||
|
@ -81,7 +81,7 @@ func TestPreorderTraversalIIITemplate(t *testing.T) {
|
||||||
choices = append(choices, root)
|
choices = append(choices, root)
|
||||||
backtrackIII(&state, &choices, &res)
|
backtrackIII(&state, &choices, &res)
|
||||||
|
|
||||||
fmt.Println("\n输出所有根节点到节点 7 的路径,路径中不包含值为 3 的节点,仅包含一个值为 7 的节点")
|
fmt.Println("\n输出所有根节点到节点 7 的路径,路径中不包含值为 3 的节点")
|
||||||
for _, path := range res {
|
for _, path := range res {
|
||||||
for _, node := range path {
|
for _, node := range path {
|
||||||
fmt.Printf("%v ", node.Val)
|
fmt.Printf("%v ", node.Val)
|
||||||
|
|
|
@ -43,7 +43,7 @@ public class preorder_traversal_iii_compact {
|
||||||
res = new ArrayList<>();
|
res = new ArrayList<>();
|
||||||
preOrder(root);
|
preOrder(root);
|
||||||
|
|
||||||
System.out.println("\n输出所有根节点到节点 7 的路径,路径中不包含值为 3 的节点,仅包含一个值为 7 的节点");
|
System.out.println("\n输出所有根节点到节点 7 的路径,路径中不包含值为 3 的节点");
|
||||||
for (List<TreeNode> path : res) {
|
for (List<TreeNode> path : res) {
|
||||||
List<Integer> vals = new ArrayList<>();
|
List<Integer> vals = new ArrayList<>();
|
||||||
for (TreeNode node : path) {
|
for (TreeNode node : path) {
|
||||||
|
|
|
@ -41,7 +41,6 @@ public class preorder_traversal_iii_template {
|
||||||
if (isSolution(state)) {
|
if (isSolution(state)) {
|
||||||
// 记录解
|
// 记录解
|
||||||
recordSolution(state, res);
|
recordSolution(state, res);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
// 遍历所有选择
|
// 遍历所有选择
|
||||||
for (TreeNode choice : choices) {
|
for (TreeNode choice : choices) {
|
||||||
|
|
|
@ -37,7 +37,7 @@ const path = [];
|
||||||
const res = [];
|
const res = [];
|
||||||
preOrder(root, path, res);
|
preOrder(root, path, res);
|
||||||
|
|
||||||
console.log('\n输出所有根节点到节点 7 的路径,路径中不包含值为 3 的节点,仅包含一个值为 7 的节点');
|
console.log('\n输出所有根节点到节点 7 的路径,路径中不包含值为 3 的节点');
|
||||||
res.forEach((path) => {
|
res.forEach((path) => {
|
||||||
console.log(path.map((node) => node.val));
|
console.log(path.map((node) => node.val));
|
||||||
});
|
});
|
||||||
|
|
|
@ -38,7 +38,6 @@ function backtrack(state, choices, res) {
|
||||||
if (isSolution(state)) {
|
if (isSolution(state)) {
|
||||||
// 记录解
|
// 记录解
|
||||||
recordSolution(state, res);
|
recordSolution(state, res);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
// 遍历所有选择
|
// 遍历所有选择
|
||||||
for (const choice of choices) {
|
for (const choice of choices) {
|
||||||
|
|
|
@ -39,6 +39,6 @@ if __name__ == "__main__":
|
||||||
res = list[list[TreeNode]]()
|
res = list[list[TreeNode]]()
|
||||||
pre_order(root)
|
pre_order(root)
|
||||||
|
|
||||||
print("\n输出所有根节点到节点 7 的路径,路径中不包含值为 3 的节点,仅包含一个值为 7 的节点")
|
print("\n输出所有根节点到节点 7 的路径,路径中不包含值为 3 的节点")
|
||||||
for path in res:
|
for path in res:
|
||||||
print([node.val for node in path])
|
print([node.val for node in path])
|
||||||
|
|
|
@ -43,7 +43,6 @@ def backtrack(
|
||||||
if is_solution(state):
|
if is_solution(state):
|
||||||
# 记录解
|
# 记录解
|
||||||
record_solution(state, res)
|
record_solution(state, res)
|
||||||
return
|
|
||||||
# 遍历所有选择
|
# 遍历所有选择
|
||||||
for choice in choices:
|
for choice in choices:
|
||||||
# 剪枝:检查选择是否合法
|
# 剪枝:检查选择是否合法
|
||||||
|
|
|
@ -9,7 +9,7 @@ from .list_node import (
|
||||||
linked_list_to_list,
|
linked_list_to_list,
|
||||||
get_list_node,
|
get_list_node,
|
||||||
)
|
)
|
||||||
from .tree_node import TreeNode, list_to_tree, tree_to_list, get_tree_node
|
from .tree_node import TreeNode, list_to_tree, tree_to_list
|
||||||
from .vertex import Vertex, vals_to_vets, vets_to_vals
|
from .vertex import Vertex, vals_to_vets, vets_to_vals
|
||||||
from .print_util import (
|
from .print_util import (
|
||||||
print_matrix,
|
print_matrix,
|
||||||
|
|
|
@ -67,14 +67,3 @@ def tree_to_list(root: TreeNode | None) -> list[int]:
|
||||||
res = []
|
res = []
|
||||||
tree_to_list_dfs(root, 0, res)
|
tree_to_list_dfs(root, 0, res)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
def get_tree_node(root: TreeNode | None, val: int) -> TreeNode | None:
|
|
||||||
"""Get a tree node with specific value in a binary tree"""
|
|
||||||
if not root:
|
|
||||||
return
|
|
||||||
if root.val == val:
|
|
||||||
return root
|
|
||||||
left: TreeNode | None = get_tree_node(root.left, val)
|
|
||||||
right: TreeNode | None = get_tree_node(root.right, val)
|
|
||||||
return left if left else right
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ pub fn main() {
|
||||||
let mut res = Vec::new();
|
let mut res = Vec::new();
|
||||||
pre_order(&mut res, &mut path, root);
|
pre_order(&mut res, &mut path, root);
|
||||||
|
|
||||||
println!("\n输出所有根节点到节点 7 的路径,路径中不包含值为 3 的节点,仅包含一个值为 7 的节点");
|
println!("\n输出所有根节点到节点 7 的路径,路径中不包含值为 3 的节点");
|
||||||
for path in res {
|
for path in res {
|
||||||
let mut vals = Vec::new();
|
let mut vals = Vec::new();
|
||||||
for node in path {
|
for node in path {
|
||||||
|
|
|
@ -40,7 +40,6 @@ fn backtrack(state: &mut Vec<Rc<RefCell<TreeNode>>>, choices: &mut Vec<Rc<RefCel
|
||||||
if is_solution(state) {
|
if is_solution(state) {
|
||||||
// 记录解
|
// 记录解
|
||||||
record_solution(state, res);
|
record_solution(state, res);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
// 遍历所有选择
|
// 遍历所有选择
|
||||||
for choice in choices {
|
for choice in choices {
|
||||||
|
|
|
@ -42,7 +42,7 @@ enum PreorderTraversalIIICompact {
|
||||||
res = []
|
res = []
|
||||||
preOrder(root: root)
|
preOrder(root: root)
|
||||||
|
|
||||||
print("\n输出所有根节点到节点 7 的路径,路径中不包含值为 3 的节点,仅包含一个值为 7 的节点")
|
print("\n输出所有根节点到节点 7 的路径,路径中不包含值为 3 的节点")
|
||||||
for path in res {
|
for path in res {
|
||||||
var vals: [Int] = []
|
var vals: [Int] = []
|
||||||
for node in path {
|
for node in path {
|
||||||
|
|
|
@ -36,7 +36,6 @@ func backtrack(state: inout [TreeNode], choices: [TreeNode], res: inout [[TreeNo
|
||||||
// 检查是否为解
|
// 检查是否为解
|
||||||
if isSolution(state: state) {
|
if isSolution(state: state) {
|
||||||
recordSolution(state: state, res: &res)
|
recordSolution(state: state, res: &res)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
// 遍历所有选择
|
// 遍历所有选择
|
||||||
for choice in choices {
|
for choice in choices {
|
||||||
|
@ -65,7 +64,7 @@ enum PreorderTraversalIIITemplate {
|
||||||
var res: [[TreeNode]] = []
|
var res: [[TreeNode]] = []
|
||||||
backtrack(state: &state, choices: [root].compactMap { $0 }, res: &res)
|
backtrack(state: &state, choices: [root].compactMap { $0 }, res: &res)
|
||||||
|
|
||||||
print("\n输出所有根节点到节点 7 的路径,路径中不包含值为 3 的节点,仅包含一个值为 7 的节点")
|
print("\n输出所有根节点到节点 7 的路径,路径中不包含值为 3 的节点")
|
||||||
for path in res {
|
for path in res {
|
||||||
var vals: [Int] = []
|
var vals: [Int] = []
|
||||||
for node in path {
|
for node in path {
|
||||||
|
|
|
@ -42,7 +42,7 @@ const path: TreeNode[] = [];
|
||||||
const res: TreeNode[][] = [];
|
const res: TreeNode[][] = [];
|
||||||
preOrder(root, path, res);
|
preOrder(root, path, res);
|
||||||
|
|
||||||
console.log('\n输出所有根节点到节点 7 的路径,路径中不包含值为 3 的节点,仅包含一个值为 7 的节点');
|
console.log('\n输出所有根节点到节点 7 的路径,路径中不包含值为 3 的节点');
|
||||||
res.forEach((path) => {
|
res.forEach((path) => {
|
||||||
console.log(path.map((node) => node.val));
|
console.log(path.map((node) => node.val));
|
||||||
});
|
});
|
||||||
|
|
|
@ -43,7 +43,6 @@ function backtrack(
|
||||||
if (isSolution(state)) {
|
if (isSolution(state)) {
|
||||||
// 记录解
|
// 记录解
|
||||||
recordSolution(state, res);
|
recordSolution(state, res);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
// 遍历所有选择
|
// 遍历所有选择
|
||||||
for (const choice of choices) {
|
for (const choice of choices) {
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 116 KiB |
|
@ -201,12 +201,9 @@
|
||||||
|
|
||||||
!!! question "例题三"
|
!!! question "例题三"
|
||||||
|
|
||||||
在二叉树中搜索所有值为 $7$ 的节点,请返回根节点到这些节点的路径,**要求路径中只存在一个值为 $7$ 的节点,并且不允许有值为 $3$ 的节点**。
|
在二叉树中搜索所有值为 $7$ 的节点,请返回根节点到这些节点的路径,**并要求路径中不包含值为 $3$ 的节点**。
|
||||||
|
|
||||||
在例题二的基础上添加剪枝操作,包括:
|
为了满足以上约束条件,**我们需要添加剪枝操作**:在搜索过程中,若遇到值为 $3$ 的节点,则提前返回,停止继续搜索。
|
||||||
|
|
||||||
- 当遇到值为 $7$ 的节点时,记录解并返回,停止搜索。
|
|
||||||
- 当遇到值为 $3$ 的节点时,则直接返回,停止搜索。
|
|
||||||
|
|
||||||
=== "Java"
|
=== "Java"
|
||||||
|
|
||||||
|
@ -274,27 +271,10 @@
|
||||||
[class]{}-[func]{preOrder}
|
[class]{}-[func]{preOrder}
|
||||||
```
|
```
|
||||||
|
|
||||||
剪枝是一个非常形象的名词。在搜索过程中,**我们利用约束条件“剪掉”了不满足约束条件的搜索分支**,避免许多无意义的尝试,从而提升搜索效率。
|
剪枝是一个非常形象的名词。在搜索过程中,**我们“剪掉”了不满足约束条件的搜索分支**,避免许多无意义的尝试,从而实现搜索效率的提高。
|
||||||
|
|
||||||
![根据约束条件剪枝](backtracking_algorithm.assets/preorder_find_constrained_paths.png)
|
![根据约束条件剪枝](backtracking_algorithm.assets/preorder_find_constrained_paths.png)
|
||||||
|
|
||||||
## 常用术语
|
|
||||||
|
|
||||||
为了更清晰地分析算法问题,我们总结一下回溯算法中常用术语的含义,并对照例题三给出对应示例。
|
|
||||||
|
|
||||||
| 名词 | 定义 | 例题三 |
|
|
||||||
| ------------------- | -------------------------------------------------------------------------- | -------------------------------------------------------------------- |
|
|
||||||
| 解 Solution | 解是满足问题特定条件的答案,可能有一个或多个 | 根节点到节点 $7$ 的满足约束条件的所有路径 |
|
|
||||||
| 约束条件 Constraint | 约束条件是问题中限制解的可行性的条件,通常用于剪枝 | 路径中不包含节点 $3$ ,只包含一个节点 $7$ |
|
|
||||||
| 状态 State | 状态表示问题在某一时刻的情况,包括已经做出的选择 | 当前已访问的节点路径,即 `path` 节点列表 |
|
|
||||||
| 尝试 Attempt | 尝试是根据可用选择来探索解空间的过程,包括做出选择,更新状态,检查是否为解 | 递归访问左(右)子节点,将节点添加进 `path` ,判断节点的值是否为 $7$ |
|
|
||||||
| 回退 Backtracking | 回退指遇到不满足约束条件的状态时,撤销前面做出的选择,回到上一个状态 | 当越过叶结点、结束结点访问、遇到值为 $3$ 的节点时终止搜索,函数返回 |
|
|
||||||
| 剪枝 Pruning | 剪枝是根据问题特性和约束条件避免无意义的搜索路径的方法,可提高搜索效率 | 当遇到值为 $3$ 的节点时,则终止继续搜索 |
|
|
||||||
|
|
||||||
!!! tip
|
|
||||||
|
|
||||||
问题、解、状态等概念是通用的,在分治、回溯、动态规划、贪心等算法中都有涉及。
|
|
||||||
|
|
||||||
## 框架代码
|
## 框架代码
|
||||||
|
|
||||||
接下来,我们尝试将回溯的“尝试、回退、剪枝”的主体框架提炼出来,提升代码的通用性。
|
接下来,我们尝试将回溯的“尝试、回退、剪枝”的主体框架提炼出来,提升代码的通用性。
|
||||||
|
@ -310,6 +290,7 @@
|
||||||
if (isSolution(state)) {
|
if (isSolution(state)) {
|
||||||
// 记录解
|
// 记录解
|
||||||
recordSolution(state, res);
|
recordSolution(state, res);
|
||||||
|
// 停止继续搜索
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 遍历所有选择
|
// 遍历所有选择
|
||||||
|
@ -335,6 +316,7 @@
|
||||||
if (isSolution(state)) {
|
if (isSolution(state)) {
|
||||||
// 记录解
|
// 记录解
|
||||||
recordSolution(state, res);
|
recordSolution(state, res);
|
||||||
|
// 停止继续搜索
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 遍历所有选择
|
// 遍历所有选择
|
||||||
|
@ -354,12 +336,13 @@
|
||||||
=== "Python"
|
=== "Python"
|
||||||
|
|
||||||
```python title=""
|
```python title=""
|
||||||
def backtrack(state: State, choices: list[choice], res: list[state]) -> None:
|
def backtrack(state: State, choices: list[choice], res: list[state]):
|
||||||
"""回溯算法框架"""
|
"""回溯算法框架"""
|
||||||
# 判断是否为解
|
# 判断是否为解
|
||||||
if is_solution(state):
|
if is_solution(state):
|
||||||
# 记录解
|
# 记录解
|
||||||
record_solution(state, res)
|
record_solution(state, res)
|
||||||
|
# 停止继续搜索
|
||||||
return
|
return
|
||||||
# 遍历所有选择
|
# 遍历所有选择
|
||||||
for choice in choices:
|
for choice in choices:
|
||||||
|
@ -381,6 +364,7 @@
|
||||||
if isSolution(state) {
|
if isSolution(state) {
|
||||||
// 记录解
|
// 记录解
|
||||||
recordSolution(state, res)
|
recordSolution(state, res)
|
||||||
|
// 停止继续搜索
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// 遍历所有选择
|
// 遍历所有选择
|
||||||
|
@ -406,6 +390,7 @@
|
||||||
if (isSolution(state)) {
|
if (isSolution(state)) {
|
||||||
// 记录解
|
// 记录解
|
||||||
recordSolution(state, res);
|
recordSolution(state, res);
|
||||||
|
// 停止继续搜索
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 遍历所有选择
|
// 遍历所有选择
|
||||||
|
@ -431,6 +416,7 @@
|
||||||
if (isSolution(state)) {
|
if (isSolution(state)) {
|
||||||
// 记录解
|
// 记录解
|
||||||
recordSolution(state, res);
|
recordSolution(state, res);
|
||||||
|
// 停止继续搜索
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 遍历所有选择
|
// 遍历所有选择
|
||||||
|
@ -456,6 +442,7 @@
|
||||||
if (isSolution(state)) {
|
if (isSolution(state)) {
|
||||||
// 记录解
|
// 记录解
|
||||||
recordSolution(state, res, numRes);
|
recordSolution(state, res, numRes);
|
||||||
|
// 停止继续搜索
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 遍历所有选择
|
// 遍历所有选择
|
||||||
|
@ -481,6 +468,7 @@
|
||||||
if (isSolution(state)) {
|
if (isSolution(state)) {
|
||||||
// 记录解
|
// 记录解
|
||||||
recordSolution(state, res);
|
recordSolution(state, res);
|
||||||
|
// 停止继续搜索
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 遍历所有选择
|
// 遍历所有选择
|
||||||
|
@ -506,6 +494,7 @@
|
||||||
if isSolution(state: state) {
|
if isSolution(state: state) {
|
||||||
// 记录解
|
// 记录解
|
||||||
recordSolution(state: state, res: &res)
|
recordSolution(state: state, res: &res)
|
||||||
|
// 停止继续搜索
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// 遍历所有选择
|
// 遍历所有选择
|
||||||
|
@ -537,6 +526,7 @@
|
||||||
if (isSolution(state)) {
|
if (isSolution(state)) {
|
||||||
// 记录解
|
// 记录解
|
||||||
recordSolution(state, res);
|
recordSolution(state, res);
|
||||||
|
// 停止继续搜索
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 遍历所有选择
|
// 遍历所有选择
|
||||||
|
@ -553,7 +543,7 @@
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
下面,我们基于框架代码来解决例题三:状态 `state` 为节点遍历路径,选择 `choices` 为当前节点的左子节点和右子节点,结果 `res` 是路径列表。
|
接下来,我们基于框架代码来解决例题三。状态 `state` 为节点遍历路径,选择 `choices` 为当前节点的左子节点和右子节点,结果 `res` 是路径列表。
|
||||||
|
|
||||||
=== "Java"
|
=== "Java"
|
||||||
|
|
||||||
|
@ -731,7 +721,28 @@
|
||||||
[class]{}-[func]{backtrack}
|
[class]{}-[func]{backtrack}
|
||||||
```
|
```
|
||||||
|
|
||||||
相比基于前序遍历的代码实现,基于回溯算法框架的代码实现虽然显得啰嗦,但通用性更好。实际上,**许多回溯问题都可以在该框架下解决**。我们只需根据具体问题来定义 `state` 和 `choices` ,并实现框架中的各个方法。
|
根据题意,当找到值为 7 的节点后应该继续搜索,**因此我们需要将记录解之后的 `return` 语句删除**。下图对比了保留或删除 `return` 语句的搜索过程。
|
||||||
|
|
||||||
|
![保留与删除 return 的搜索过程对比](backtracking_algorithm.assets/backtrack_remove_return_or_not.png)
|
||||||
|
|
||||||
|
相比基于前序遍历的代码实现,基于回溯算法框架的代码实现虽然显得啰嗦,但通用性更好。实际上,**许多回溯问题都可以在该框架下解决**。我们只需根据具体问题来定义 `state` 和 `choices` ,并实现框架中的各个方法即可。
|
||||||
|
|
||||||
|
## 常用术语
|
||||||
|
|
||||||
|
为了更清晰地分析算法问题,我们总结一下回溯算法中常用术语的含义,并对照例题三给出对应示例。
|
||||||
|
|
||||||
|
| 名词 | 定义 | 例题三 |
|
||||||
|
| ------------------- | -------------------------------------------------------------------------- | -------------------------------------------------------------------- |
|
||||||
|
| 解 Solution | 解是满足问题特定条件的答案,可能有一个或多个 | 根节点到节点 $7$ 的满足约束条件的所有路径 |
|
||||||
|
| 约束条件 Constraint | 约束条件是问题中限制解的可行性的条件,通常用于剪枝 | 路径中不包含节点 $3$ ,只包含一个节点 $7$ |
|
||||||
|
| 状态 State | 状态表示问题在某一时刻的情况,包括已经做出的选择 | 当前已访问的节点路径,即 `path` 节点列表 |
|
||||||
|
| 尝试 Attempt | 尝试是根据可用选择来探索解空间的过程,包括做出选择,更新状态,检查是否为解 | 递归访问左(右)子节点,将节点添加进 `path` ,判断节点的值是否为 $7$ |
|
||||||
|
| 回退 Backtracking | 回退指遇到不满足约束条件的状态时,撤销前面做出的选择,回到上一个状态 | 当越过叶结点、结束结点访问、遇到值为 $3$ 的节点时终止搜索,函数返回 |
|
||||||
|
| 剪枝 Pruning | 剪枝是根据问题特性和约束条件避免无意义的搜索路径的方法,可提高搜索效率 | 当遇到值为 $3$ 的节点时,则终止继续搜索 |
|
||||||
|
|
||||||
|
!!! tip
|
||||||
|
|
||||||
|
问题、解、状态等概念是通用的,在分治、回溯、动态规划、贪心等算法中都有涉及。
|
||||||
|
|
||||||
## 优势与局限性
|
## 优势与局限性
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue