Fix multilingual content typos (#1958)

This commit is contained in:
Yudong Jin
2026-08-18 03:08:23 +08:00
committed by GitHub
parent 69932aed18
commit bf86c39b6c
201 changed files with 289 additions and 271 deletions
+2 -2
View File
@@ -20,7 +20,7 @@ VS Code 拥有强大的扩展包生态系统,支持大多数编程语言的运
### C/C++ 环境
1. Windows 系统需要安装 [MinGW](https://sourceforge.net/projects/mingw-w64/files/)[配置教程](https://blog.csdn.net/qq_33698226/article/details/129031241));MacOS 自带 Clang ,无须安装。
1. Windows 系统需要安装 [MinGW](https://sourceforge.net/projects/mingw-w64/files/)[配置教程](https://blog.csdn.net/qq_33698226/article/details/129031241));macOS 自带 Clang ,无须安装。
2. 在 VS Code 的插件市场中搜索 `c++` ,安装 C/C++ Extension Pack 。
3. (可选)打开 Settings 页面,搜索 `Clang_format_fallback Style` 代码格式化选项,设置为 `{ BasedOnStyle: Microsoft, BreakBeforeBraces: Attach }`
@@ -31,7 +31,7 @@ VS Code 拥有强大的扩展包生态系统,支持大多数编程语言的运
### C# 环境
1. 下载并安装 [.Net 8.0](https://dotnet.microsoft.com/en-us/download) 。
1. 下载并安装 [.NET 8.0](https://dotnet.microsoft.com/en-us/download) 。
2. 在 VS Code 的插件市场中搜索 `C# Dev Kit` ,安装 C# Dev Kit [配置教程](https://code.visualstudio.com/docs/csharp/get-started))。
3. 也可使用 Visual Studio[安装教程](https://learn.microsoft.com/zh-cn/visualstudio/install/install-visual-studio?view=vs-2022))。
+3 -1
View File
@@ -80,7 +80,9 @@
| level-order traversal | 层序遍历 |
| breadth-first traversal | 广度优先遍历 |
| depth-first traversal | 深度优先遍历 |
| binary search tree | 二叉搜索树 |
| pre-order traversal | 前序遍历 |
| in-order traversal | 中序遍历 |
| post-order traversal | 后序遍历 |
| balanced binary search tree | 平衡二叉搜索树 |
| balance factor | 平衡因子 |
| heap | 堆 |
@@ -166,7 +166,7 @@
// 构造方法
class ListNode(x: Int) {
val _val: Int = x // 节点值
val next: ListNode? = null // 指向下一个节点的引用
var next: ListNode? = null // 指向下一个节点的引用
}
```
@@ -658,8 +658,8 @@
// 构造方法
class ListNode(x: Int) {
val _val: Int = x // 节点值
val next: ListNode? = null // 指向后继节点的引用
val prev: ListNode? = null // 指向前驱节点的引用
var next: ListNode? = null // 指向后继节点的引用
var prev: ListNode? = null // 指向前驱节点的引用
}
```
@@ -30,7 +30,7 @@
为了实现每个元素只被选择一次,我们考虑引入一个布尔型数组 `selected` ,其中 `selected[i]` 表示 `choices[i]` 是否已被选择,并基于它实现以下剪枝操作。
- 在做出选择 `choice[i]` 后,我们就将 `selected[i]` 赋值为 $\text{True}$ ,代表它已被选择。
- 在做出选择 `choices[i]` 后,我们就将 `selected[i]` 赋值为 $\text{True}$ ,代表它已被选择。
- 遍历选择列表 `choices` 时,跳过所有已被选择的节点,即剪枝。
如下图所示,假设我们第一轮选择 1 ,第二轮选择 3 ,第三轮选择 2 ,则需要在第二轮剪掉元素 1 的分支,在第三轮剪掉元素 1 和元素 3 的分支。
+1 -1
View File
@@ -10,7 +10,7 @@
- 原码、反码和补码是在计算机中编码数字的三种方法,它们之间可以相互转换。整数的原码的最高位是符号位,其余位是数字的值。
- 整数在计算机中是以补码的形式存储的。在补码表示下,计算机可以对正数和负数的加法一视同仁,不需要为减法操作单独设计特殊的硬件电路,并且不存在正负零歧义的问题。
- 浮点数的编码由 1 位符号位、8 位指数位和 23 位分数位构成。由于存在指数位,因此浮点数的取值范围远大于整数,代价是牺牲了精度。
- ASCII 码是最早出现的英文字符集,长度为 1 字节,共收录 127 个字符。GBK 字符集是常用的中文字符集,共收录两万多个汉字。Unicode 致力于提供一个完整的字符集标准,收录世界上各种语言的字符,从而解决由于字符编码方法不一致而导致的乱码问题。
- ASCII 码是最早出现的英文字符集,长度为 1 字节,共收录 128 个字符。GBK 字符集是常用的中文字符集,共收录两万多个汉字。Unicode 致力于提供一个完整的字符集标准,收录世界上各种语言的字符,从而解决由于字符编码方法不一致而导致的乱码问题。
- UTF-8 是最受欢迎的 Unicode 编码方法,通用性非常好。它是一种变长的编码方法,具有很好的扩展性,有效提升了存储空间的使用效率。UTF-16 和 UTF-32 是等长的编码方法。在编码中文时,UTF-16 占用的空间比 UTF-8 更小。Java 和 C# 等编程语言默认使用 UTF-16 编码。
### Q & A
@@ -21,12 +21,12 @@
根据定义,`preorder``inorder` 都可以划分为三个部分。
- 前序遍历:`[ 根节点 | 左子树 | 右子树 ]` ,例如上图的树对应 `[ 3 | 9 | 2 1 7 ]`
- 中序遍历:`[ 左子树 | 根节点 右子树 ]` ,例如上图的树对应 `[ 9 | 3 | 1 2 7 ]`
- 中序遍历:`[ 左子树 | 根节点 | 右子树 ]` ,例如上图的树对应 `[ 9 | 3 | 1 2 7 ]`
以上图数据为例,我们可以通过下图所示的步骤得到划分结果。
1. 前序遍历的首元素 3 是根节点的值。
2. 查找根节点 3 在 `inorder` 中的索引,利用该索引可将 `inorder` 划分为 `[ 9 | 3 1 2 7 ]`
2. 查找根节点 3 在 `inorder` 中的索引,利用该索引可将 `inorder` 划分为 `[ 9 | 3 | 1 2 7 ]`
3. 根据 `inorder` 的划分结果,易得左子树和右子树的节点数量分别为 1 和 3 ,从而可将 `preorder` 划分为 `[ 3 | 9 | 2 1 7 ]`
![在前序遍历和中序遍历中划分子树](build_binary_tree_problem.assets/build_tree_preorder_inorder_division.png)
@@ -35,7 +35,7 @@
状态 $[i, j]$ 对应的子问题:**将 $s$ 的前 $i$ 个字符更改为 $t$ 的前 $j$ 个字符所需的最少编辑步数**。
至此,得到一个尺寸为 $(i+1) \times (j+1)$ 的二维 $dp$ 表。
至此,得到一个尺寸为 $(n+1) \times (m+1)$ 的二维 $dp$ 表。
**第二步:找出最优子结构,进而推导出状态转移方程**
@@ -134,7 +134,7 @@ $$
### 空间优化
由于每个状态都只与其上一行的状态有关,因此我们可以使用两个数组滚动前进,将空间复杂度从 $O(n^2)$ 降至 $O(n)$ 。
由于每个状态都只与其上一行的状态有关,因此我们可以使用两个数组滚动前进,将空间复杂度从 $O(n \times cap)$ 降至 $O(cap)$ 。
进一步思考,我们能否仅用一个数组实现空间优化呢?观察可知,每个状态都是由正上方或左上方的格子转移过来的。假设只有一个数组,当开始遍历第 $i$ 行时,该数组存储的仍然是第 $i-1$ 行的状态。
+1 -1
View File
@@ -21,5 +21,5 @@
**编辑距离问题**
- 编辑距离(Levenshtein 距离)用于衡量两个字符串之间的相似度,其定义为从一个字符串到另一个字符串的最少编辑步数,编辑操作包括添加、删除、替换。
- 编辑距离问题的状态定义为将 $s$ 的前 $i$ 个字符更改为 $t$ 的前 $j$ 个字符所需的最少编辑步数。当 $s[i] \ne t[j]$ 时,具有三种决策:添加、删除、替换,它们都有相应的剩余子问题。据此便可以找出最优子结构与构建状态转移方程。而当 $s[i] = t[j]$ 时,无须编辑当前字符。
- 编辑距离问题的状态定义为将 $s$ 的前 $i$ 个字符更改为 $t$ 的前 $j$ 个字符所需的最少编辑步数。当 $s[i-1] \ne t[j-1]$ 时,具有三种决策:添加、删除、替换,它们都有相应的剩余子问题。据此便可以找出最优子结构与构建状态转移方程。而当 $s[i-1] = t[j-1]$ 时,无须编辑当前字符。
- 在编辑距离中,状态依赖其正上方、正左方、左上方的状态,因此空间优化后正序或倒序遍历都无法正确地进行状态转移。为此,我们利用一个变量暂存左上方状态,从而转化到与完全背包问题等价的情况,可以在空间优化后进行正序遍历。
@@ -33,7 +33,7 @@
[file]{fractional_knapsack}-[class]{}-[func]{fractional_knapsack}
```
内置排序算法的时间复杂度通常为 $O(\log n)$ ,空间复杂度通常为 $O(\log n)$ 或 $O(n)$ ,取决于编程语言的具体实现。
内置排序算法的时间复杂度通常为 $O(n \log n)$ ,空间复杂度通常为 $O(\log n)$ 或 $O(n)$ ,取决于编程语言的具体实现。
除排序之外,在最差情况下,需要遍历整个物品列表,**因此时间复杂度为 $O(n)$** ,其中 $n$ 为物品数量。
+1 -1
View File
@@ -91,4 +91,4 @@
- **分数背包问题**:给定一组物品和一个载重量,你的目标是选择一组物品,使得总重量不超过载重量,且总价值最大。如果每次都选择性价比最高(价值 / 重量)的物品,那么贪心算法在一些情况下可以得到最优解。
- **股票买卖问题**:给定一组股票的历史价格,你可以进行多次买卖,但如果你已经持有股票,那么在卖出之前不能再买,目标是获取最大利润。
- **霍夫曼编码**:霍夫曼编码是一种用于无损数据压缩的贪心算法。通过构建霍夫曼树,每次选择出现频率最低的两个节点合并,最后得到的霍夫曼树的带权路径长度(编码长度)最小。
- **Dijkstra 算法**:它是一种解决给定源顶点到其余各顶点的最短路径问题的贪心算法。
- **Dijkstra 算法**在所有边的权重均为非负数的图中,它是一种解决给定源顶点到其余各顶点的最短路径问题的贪心算法。
@@ -51,7 +51,7 @@ $$
1. 输入整数 $n$ ,从其不断地切分出因子 $3$ ,直至余数为 $0$、$1$、$2$ 。
2. 当余数为 $0$ 时,代表 $n$ 是 $3$ 的倍数,因此不做任何处理。
3. 当余数为 $2$ 时,不继续划分,保留。
4. 当余数为 $1$ 时,由于 $2 \times 2 > 1 \times 3$ ,因此应将最后一个 $3$ 替换为 $2$ 。
4. 当余数为 $1$ 时,由于 $2 \times 2 > 1 \times 3$ ,因此应将最后一个 $3$ 和余数 $1$ 替换为两个 $2$ 。
### 代码实现
+1 -1
View File
@@ -160,7 +160,7 @@ $$
size_t hashStr = hash<string>()(str);
// 字符串“Hello 算法”的哈希值为 15466937326284535026
// 在 C++ 中,内置 std:hash() 仅提供基本数据类型的哈希值计算
// 在 C++ 中,内置 std::hash() 仅提供基本数据类型的哈希值计算
// 数组、对象的哈希值计算需要自行实现
```
+1 -1
View File
@@ -10,7 +10,7 @@
- 负载因子定义为哈希表中元素数量除以桶数量,反映了哈希冲突的严重程度,常用作触发哈希表扩容的条件。
- 链式地址通过将单个元素转化为链表,将所有冲突元素存储在同一个链表中。然而,链表过长会降低查询效率,可以通过进一步将链表转换为红黑树来提高效率。
- 开放寻址通过多次探测来处理哈希冲突。线性探测使用固定步长,缺点是不能删除元素,且容易产生聚集。多次哈希使用多个哈希函数进行探测,相较线性探测更不易产生聚集,但多个哈希函数增加了计算量。
- 不同编程语言采取了不同的哈希表实现。例如,Java 的 `HashMap` 使用链式地址,而 Python 的 `Dict` 采用开放寻址。
- 不同编程语言采取了不同的哈希表实现。例如,Java 的 `HashMap` 使用链式地址,而 Python 的 `dict` 采用开放寻址。
- 在哈希表中,我们希望哈希算法具有确定性、高效率和均匀分布的特点。在密码学中,哈希算法还应该具备抗碰撞性和雪崩效应。
- 哈希算法通常采用大质数作为模数,以最大化地保证哈希值均匀分布,减少哈希冲突。
- 常见的哈希算法包括 MD5、SHA-1、SHA-2 和 SHA-3 等。MD5 常用于校验文件完整性,SHA-2 常用于安全应用与协议。
+1 -1
View File
@@ -31,7 +31,7 @@
下面,我们来尝试推算第二种建堆方法的时间复杂度。
- 假设完全二叉树的节点数量为 $n$ ,则叶节点数量为 $(n + 1) / 2$ ,其中 $/$ 为向下整除。因此需要堆化的节点数量为 $(n - 1) / 2$ 。
- 假设完全二叉树的节点数量为 $n$ ,则叶节点数量为 $(n + 1) / 2$ ,其中 $/$ 为向下整除。因此需要堆化的节点数量为 $n / 2$ 。
- 在从顶至底堆化的过程中,每个节点最多堆化到叶节点,因此最大迭代次数为二叉树高度 $\log n$ 。
将上述两者相乘,可得到建堆过程的时间复杂度为 $O(n \log n)$ 。**但这个估算结果并不准确,因为我们没有考虑到二叉树底层节点数量远多于顶层节点的性质**。
+1 -1
View File
@@ -41,7 +41,7 @@
### 转化为查找元素
我们知道,当数组不包含 `target` 时,最终 $i$ 和 $j$ 会分别指向首个大于小于 `target` 的元素。
我们知道,当数组不包含 `target` 时,最终 $i$ 和 $j$ 会分别指向首个大于 `target` 的元素和最右一个小于 `target` 的元素。
因此,如下图所示,我们可以构造一个数组中不存在的元素,用于查找左右边界。
@@ -20,7 +20,7 @@
进一步思考二分查找过程:当 `nums[m] < target` 时 $i$ 移动,这意味着指针 $i$ 在向大于等于 `target` 的元素靠近。同理,指针 $j$ 始终在向小于等于 `target` 的元素靠近。
因此二分结束时一定有:$i$ 指向首个大于 `target` 的元素,$j$ 指向个小于 `target` 的元素。**易得当数组不包含 `target` 时,插入索引为 $i$** 。代码如下所示:
因此二分结束时一定有:$i$ 指向首个大于 `target` 的元素,$j$ 指向最右一个小于 `target` 的元素。**易得当数组不包含 `target` 时,插入索引为 $i$** 。代码如下所示:
```src
[file]{binary_search_insertion}-[class]{}-[func]{binary_search_insertion_simple}
@@ -48,7 +48,7 @@
-`nums[m] < target``nums[m] > target` 时,说明还没有找到 `target` ,因此采用普通二分查找的缩小区间操作,**从而使指针 $i$ 和 $j$ 向 `target` 靠近**。
-`nums[m] == target` 时,说明小于 `target` 的元素在区间 $[i, m - 1]$ 中,因此采用 $j = m - 1$ 来缩小区间,**从而使指针 $j$ 向小于 `target` 的元素靠近**。
循环完成后,$i$ 指向最左边的 `target` $j$ 指向个小于 `target` 的元素,**因此索引 $i$ 就是插入点**。
循环完成后,$i$ 指向最左边的 `target` $j$ 指向最右一个小于 `target` 的元素,**因此索引 $i$ 就是插入点**。
=== "<1>"
![二分查找重复元素的插入点的步骤](binary_search_insertion.assets/binary_search_insertion_step1.png)
+1 -1
View File
@@ -1,6 +1,6 @@
# 桶排序
前述几种排序算法都属于“基于比较的排序算法”,它们通过比较元素间的大小来实现排序。此类排序算法的时间复杂度无法超越 $O(n \log n)$ 。接下来,我们将探讨几种“非比较排序算法”,它们的时间复杂度可以达到线性阶。
前述几种排序算法都属于“基于比较的排序算法”,它们通过比较元素间的大小来实现排序。此类排序算法在最坏情况下的时间复杂度下界为 $\Omega(n \log n)$ 。接下来,我们将探讨几种“非比较排序算法”,它们的时间复杂度可以达到线性阶。
<u>桶排序(bucket sort</u>是分治策略的一个典型应用。它通过设置一些具有大小顺序的桶,每个桶对应一个数据范围,将数据平均分配到各个桶中;然后,在每个桶内部分别执行排序;最终按照桶的顺序将所有数据合并。
+1 -1
View File
@@ -51,7 +51,7 @@
## 算法特性
- **时间复杂度为 $O(n^2)$、非自适应排序**:外循环共 $n - 1$ 轮,第一轮的未排序区间长度为 $n$ ,最后一轮的未排序区间长度为 $2$ ,即各轮循环分别包含 $n$、$n - 1$、$\dots$、$3$、$2$ 轮内循环,求和为 $\frac{(n - 1)(n + 2)}{2}$ 。
- **时间复杂度为 $O(n^2)$、非自适应排序**:外循环共 $n - 1$ 轮,第一轮内循环执行 $n - 1$ ,最后一轮执行 $1$ ,即各轮循环分别执行 $n - 1$、$n - 2$、$\dots$、$2$、$1$ ,求和为 $\frac{n(n - 1)}{2}$ 。
- **空间复杂度为 $O(1)$、原地排序**:指针 $i$ 和 $j$ 使用常数大小的额外空间。
- **非稳定排序**:如下图所示,元素 `nums[i]` 有可能被交换至与其相等的元素的右边,导致两者的相对顺序发生改变。
+1 -1
View File
@@ -37,7 +37,7 @@
**自适应性**<u>自适应排序</u>能够利用输入数据已有的顺序信息来减少计算量,达到更优的时间效率。自适应排序算法的最佳时间复杂度通常优于平均时间复杂度。
**是否基于比较**<u>基于比较的排序</u>依赖比较运算符($<$、$=$、$>$)来判断元素的相对顺序,从而排序整个数组,理论最优时间复杂度为 $O(n \log n)$ 。而<u>非比较排序</u>不使用比较运算符,时间复杂度可达 $O(n)$ ,但其通用性相对较差。
**是否基于比较**<u>基于比较的排序</u>依赖比较运算符($<$、$=$、$>$)来判断元素的相对顺序,从而排序整个数组,其最坏时间复杂度的下界为 $\Omega(n \log n)$ 。而<u>非比较排序</u>不使用比较运算符,时间复杂度可达 $O(n)$ ,但其通用性相对较差。
## 理想排序算法
+2 -2
View File
@@ -175,7 +175,7 @@
/* 元素出队 */
// 由于是数组,因此 removeFirst 的复杂度为 O(n)
let pool = queue.removeFirst()
let pop = queue.removeFirst()
/* 获取队列的长度 */
let size = queue.count
@@ -244,7 +244,7 @@
```dart title="queue.dart"
/* 初始化队列 */
// 在 Dart 中,队列类 Qeque 是双向队列,也可作为队列使用
// 在 Dart 中,队列类 Queue 是双向队列,也可作为队列使用
Queue<int> queue = Queue();
/* 元素入队 */
+3 -3
View File
@@ -205,9 +205,9 @@ AVL 树既是二叉搜索树,也是平衡二叉树,同时满足这两类二
```kotlin title=""
/* AVL 树节点类 */
class TreeNode(val _val: Int) { // 节点值
val height: Int = 0 // 节点高度
val left: TreeNode? = null // 左子节点
val right: TreeNode? = null // 右子节点
var height: Int = 0 // 节点高度
var left: TreeNode? = null // 左子节点
var right: TreeNode? = null // 右子节点
}
```
+2 -2
View File
@@ -181,8 +181,8 @@
```kotlin title=""
/* 二叉树节点类 */
class TreeNode(val _val: Int) { // 节点值
val left: TreeNode? = null // 左子节点引用
val right: TreeNode? = null // 右子节点引用
var left: TreeNode? = null // 左子节点引用
var right: TreeNode? = null // 右子节点引用
}
```