This commit is contained in:
krahets 2023-05-21 19:58:35 +08:00
parent 5a68f683b9
commit 2a72cceca6
6 changed files with 29 additions and 13 deletions

View file

@ -8,7 +8,9 @@ comments: true
回溯算法通常采用「深度优先搜索」来遍历解空间。在二叉树章节中,我们提到前序、中序和后序遍历都属于深度优先搜索。下面,我们从二叉树的前序遍历入手,逐步了解回溯算法的工作原理。 回溯算法通常采用「深度优先搜索」来遍历解空间。在二叉树章节中,我们提到前序、中序和后序遍历都属于深度优先搜索。下面,我们从二叉树的前序遍历入手,逐步了解回溯算法的工作原理。
!!! question "例题一:在二叉树中搜索并返回所有值为 $7$ 的节点" !!! question "例题一"
给定一个二叉树,搜索并记录所有值为 $7$ 的节点,返回节点列表。
**解题思路**:前序遍历这颗树,并判断当前节点的值是否为 $7$ ,若是则将该节点的值加入到结果列表 `res` 之中。 **解题思路**:前序遍历这颗树,并判断当前节点的值是否为 $7$ ,若是则将该节点的值加入到结果列表 `res` 之中。
@ -169,7 +171,9 @@ comments: true
值得说明的是,**回退并不等价于函数返回**。为解释这一点,我们对例题一稍作拓展。 值得说明的是,**回退并不等价于函数返回**。为解释这一点,我们对例题一稍作拓展。
!!! question "在二叉树中搜索所有值为 $7$ 的节点,**返回根节点到这些节点的路径**" !!! question "例题二"
在二叉树中搜索所有值为 $7$ 的节点,**返回根节点到这些节点的路径**。
**解题思路**:在例题一代码的基础上,我们需要借助一个列表 `path` 记录访问过的节点路径。当访问到值为 $7$ 的节点时,则复制 `path` 并添加进结果列表 `res` 。遍历完成后,`res` 中保存的就是所有的解。 **解题思路**:在例题一代码的基础上,我们需要借助一个列表 `path` 记录访问过的节点路径。当访问到值为 $7$ 的节点时,则复制 `path` 并添加进结果列表 `res` 。遍历完成后,`res` 中保存的就是所有的解。
@ -393,7 +397,9 @@ comments: true
复杂的回溯问题通常包含一个或多个约束条件,**约束条件通常可用于“剪枝”**。 复杂的回溯问题通常包含一个或多个约束条件,**约束条件通常可用于“剪枝”**。
!!! question "例题三:在二叉树中搜索所有值为 $7$ 的节点,返回根节点到这些节点的路径,**路径中不能包含值为 $3$ 的节点**" !!! question "例题三"
在二叉树中搜索所有值为 $7$ 的节点,返回根节点到这些节点的路径,**路径中不能包含值为 $3$ 的节点**。
**解题思路**:在例题二的基础上添加剪枝操作,当遇到值为 $3$ 的节点时,则终止继续搜索。 **解题思路**:在例题二的基础上添加剪枝操作,当遇到值为 $3$ 的节点时,则终止继续搜索。

View file

@ -4,7 +4,9 @@ comments: true
# 12.3.   N 皇后问题 # 12.3.   N 皇后问题
!!! question "根据国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。给定 $n$ 个皇后和一个 $n \times n$ 大小的棋盘,寻找使得所有皇后之间无法相互攻击的摆放方案。" !!! question
根据国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。给定 $n$ 个皇后和一个 $n \times n$ 大小的棋盘,寻找使得所有皇后之间无法相互攻击的摆放方案。
如下图所示,当 $n = 4$ 时,共可以找到两个解。从回溯算法的角度看,$n \times n$ 大小的棋盘共有 $n^2$ 个格子,给出了所有的选择 `choices` 。在逐个放置皇后的过程中,棋盘状态在不断地变化,每个时刻的棋盘就是状态 `state` 如下图所示,当 $n = 4$ 时,共可以找到两个解。从回溯算法的角度看,$n \times n$ 大小的棋盘共有 $n^2$ 个格子,给出了所有的选择 `choices` 。在逐个放置皇后的过程中,棋盘状态在不断地变化,每个时刻的棋盘就是状态 `state`

View file

@ -20,7 +20,9 @@ comments: true
## 12.2.1.   无重复的情况 ## 12.2.1.   无重复的情况
!!! question "输入一个整数数组,数组中不包含重复元素,返回所有可能的排列。" !!! question
输入一个整数数组,数组中不包含重复元素,返回所有可能的排列。
**从回溯算法的角度看,我们可以把生成排列的过程想象成一系列选择的结果**。假设输入数组为 $[1, 2, 3]$ ,如果我们先选择 $1$ 、再选择 $3$ 、最后选择 $2$ ,则获得排列 $[1, 3, 2]$ 。回退表示撤销一个选择,之后继续尝试其他选择。 **从回溯算法的角度看,我们可以把生成排列的过程想象成一系列选择的结果**。假设输入数组为 $[1, 2, 3]$ ,如果我们先选择 $1$ 、再选择 $3$ 、最后选择 $2$ ,则获得排列 $[1, 3, 2]$ 。回退表示撤销一个选择,之后继续尝试其他选择。
@ -344,7 +346,9 @@ comments: true
## 12.2.2.   考虑重复的情况 ## 12.2.2.   考虑重复的情况
!!! question "输入一个整数数组,**数组中可能包含重复元素**,返回所有不重复的排列。" !!! question
输入一个整数数组,**数组中可能包含重复元素**,返回所有不重复的排列。
假设输入数组为 $[1, 1, 2]$ 。为了方便区分两个重复的元素 $1$ ,接下来我们将第二个元素记为 $\hat{1}$ 。如下图所示,上述方法生成的排列有一半都是重复的。 假设输入数组为 $[1, 1, 2]$ 。为了方便区分两个重复的元素 $1$ ,接下来我们将第二个元素记为 $\hat{1}$ 。如下图所示,上述方法生成的排列有一半都是重复的。

View file

@ -8,7 +8,9 @@ comments: true
我们先来求解一个简单的二分查找问题。 我们先来求解一个简单的二分查找问题。
!!! question "给定一个长度为 $n$ 的有序数组 `nums` ,元素按从小到大的顺序排列。查找并返回元素 `target` 在该数组中的索引。若数组中不包含该元素,则返回 $-1$ 。数组中不包含重复元素。" !!! question
给定一个长度为 $n$ 的有序数组 `nums` ,元素按从小到大的顺序排列。请查找并返回元素 `target` 在该数组中的索引。若数组中不包含该元素,则返回 $-1$ 。数组中不包含重复元素。
该数组的索引范围可以使用区间 $[0, n - 1]$ 来表示。其中,**中括号表示“闭区间”,即包含边界值本身**。在该表示下,区间 $[i, j]$ 在 $i = j$ 时仍包含一个元素,在 $i > j$ 时为空区间。 该数组的索引范围可以使用区间 $[0, n - 1]$ 来表示。其中,**中括号表示“闭区间”,即包含边界值本身**。在该表示下,区间 $[i, j]$ 在 $i = j$ 时仍包含一个元素,在 $i > j$ 时为空区间。

View file

@ -14,7 +14,9 @@ comments: true
## 10.2.1.   查找最左一个元素 ## 10.2.1.   查找最左一个元素
!!! question "查找并返回元素 `target` 在有序数组 `nums` 中首次出现的索引。若数组中不包含该元素,则返回 $-1$ 。数组可能包含重复元素。" !!! question
给定一个长度为 $n$ 的有序数组 `nums` 。请查找并返回元素 `target` 在该数组中首次出现的索引。若数组中不包含该元素,则返回 $-1$ 。数组可能包含重复元素。
实际上,我们可以仅通过二分查找解决以上问题。方法的整体框架不变,先计算中点索引 `m` ,再判断 `target``nums[m]` 大小关系: 实际上,我们可以仅通过二分查找解决以上问题。方法的整体框架不变,先计算中点索引 `m` ,再判断 `target``nums[m]` 大小关系:
@ -104,11 +106,11 @@ comments: true
while i <= j: while i <= j:
m = (i + j) // 2 # 计算中点索引 m m = (i + j) // 2 # 计算中点索引 m
if nums[m] < target: if nums[m] < target:
i = m + 1 # 此情况说明 target 在区间 [m+1, j] 中 i = m + 1 # target 在区间 [m+1, j] 中
elif nums[m] > target: elif nums[m] > target:
j = m - 1 # 此情况说明 target 在区间 [i, m-1] 中 j = m - 1 # target 在区间 [i, m-1] 中
else: else:
j = m - 1 # 此情况说明首个小于 target 的元素在区间 [i, m-1] 中 j = m - 1 # 首个小于 target 的元素在区间 [i, m-1] 中
if i == len(nums) or nums[i] != target: if i == len(nums) or nums[i] != target:
return -1 # 未找到目标元素,返回 -1 return -1 # 未找到目标元素,返回 -1
return i return i

View file

@ -6,9 +6,9 @@ comments: true
在算法题中,**我们常通过将线性查找替换为哈希查找来降低算法的时间复杂度**。我们借助一个算法题来加深理解。 在算法题中,**我们常通过将线性查找替换为哈希查找来降低算法的时间复杂度**。我们借助一个算法题来加深理解。
!!! question "两数之和" !!! question
给定一个整数数组 `nums` 和一个整数目标值 `target` ,请在数组中搜索“和”为目标值 `target` 的两个整数,并返回他们在数组中的索引。注意,数组中同一个元素在答案里不能重复出现。返回任意一个解即可。 给定一个整数数组 `nums` 和一个目标元素 `target` ,请在数组中搜索“和”为 `target` 的两个元素,并返回它们的数组索引。返回任意一个解即可。
## 10.3.1. &nbsp; 线性查找:以时间换空间 ## 10.3.1. &nbsp; 线性查找:以时间换空间