feat: Revised the book (#978)

* Sync recent changes to the revised Word.

* Revised the preface chapter

* Revised the introduction chapter

* Revised the computation complexity chapter

* Revised the chapter data structure

* Revised the chapter array and linked list

* Revised the chapter stack and queue

* Revised the chapter hashing

* Revised the chapter tree

* Revised the chapter heap

* Revised the chapter graph

* Revised the chapter searching

* Reivised the sorting chapter

* Revised the divide and conquer chapter

* Revised the chapter backtacking

* Revised the DP chapter

* Revised the greedy chapter

* Revised the appendix chapter

* Revised the preface chapter doubly

* Revised the figures
This commit is contained in:
Yudong Jin
2023-12-02 06:21:34 +08:00
committed by GitHub
parent b824d149cb
commit e720aa2d24
404 changed files with 1537 additions and 1558 deletions

View File

@ -35,11 +35,11 @@ func insert(nums []int, num int, index int) {
for i := len(nums) - 1; i > index; i-- {
nums[i] = nums[i-1]
}
// 将 num 赋给 index 处元素
// 将 num 赋给 index 处元素
nums[index] = num
}
/* 删除索引 index 处元素 */
/* 删除索引 index 处元素 */
func remove(nums []int, index int) {
// 把索引 index 之后的所有元素向前移动一位
for i := index; i < len(nums)-1; i++ {

View File

@ -20,7 +20,7 @@ func TestLinkedList(t *testing.T) {
n3 := NewListNode(5)
n4 := NewListNode(4)
// 构建引用指向
// 构建节点之间的引用
n0.Next = n1
n1.Next = n2
n2.Next = n3

View File

@ -28,7 +28,7 @@ func TestList(t *testing.T) {
nums = nil
fmt.Println("清空列表后 nums =", nums)
/* 尾部添加元素 */
/* 尾部添加元素 */
nums = append(nums, 1)
nums = append(nums, 3)
nums = append(nums, 2)
@ -36,7 +36,7 @@ func TestList(t *testing.T) {
nums = append(nums, 4)
fmt.Println("添加元素后 nums =", nums)
/* 中间插入元素 */
/* 中间插入元素 */
nums = append(nums[:3], append([]int{6}, nums[3:]...)...) // 在索引 3 处插入数字 6
fmt.Println("在索引 3 处插入数字 6 ,得到 nums =", nums)

View File

@ -4,7 +4,7 @@
package chapter_array_and_linkedlist
/* 列表类简易实现 */
/* 列表类 */
type myList struct {
arrCapacity int
arr []int
@ -17,12 +17,12 @@ func newMyList() *myList {
return &myList{
arrCapacity: 10, // 列表容量
arr: make([]int, 10), // 数组(存储列表元素)
arrSize: 0, // 列表长度(当前元素数量)
arrSize: 0, // 列表长度(当前元素数量)
extendRatio: 2, // 每次列表扩容的倍数
}
}
/* 获取列表长度(当前元素数量) */
/* 获取列表长度(当前元素数量) */
func (l *myList) size() int {
return l.arrSize
}
@ -49,7 +49,7 @@ func (l *myList) set(num, index int) {
l.arr[index] = num
}
/* 尾部添加元素 */
/* 尾部添加元素 */
func (l *myList) add(num int) {
// 元素数量超出容量时,触发扩容机制
if l.arrSize == l.arrCapacity {
@ -60,7 +60,7 @@ func (l *myList) add(num int) {
l.arrSize++
}
/* 中间插入元素 */
/* 中间插入元素 */
func (l *myList) insert(num, index int) {
if index < 0 || index >= l.arrSize {
panic("索引越界")

View File

@ -13,7 +13,7 @@ import (
func TestMyList(t *testing.T) {
/* 初始化列表 */
nums := newMyList()
/* 尾部添加元素 */
/* 尾部添加元素 */
nums.add(1)
nums.add(3)
nums.add(2)
@ -21,7 +21,7 @@ func TestMyList(t *testing.T) {
nums.add(4)
fmt.Printf("列表 nums = %v ,容量 = %v ,长度 = %v\n", nums.toArray(), nums.capacity(), nums.size())
/* 中间插入元素 */
/* 中间插入元素 */
nums.insert(6, 3)
fmt.Printf("在索引 3 处插入数字 6 ,得到 nums = %v\n", nums.toArray())

View File

@ -21,7 +21,7 @@ func backtrack(row, n int, state *[][]string, res *[][][]string, cols, diags1, d
// 计算该格子对应的主对角线和副对角线
diag1 := row - col + n - 1
diag2 := row + col
// 剪枝:不允许该格子所在列、主对角线、副对角线存在皇后
// 剪枝:不允许该格子所在列、主对角线、副对角线存在皇后
if !(*cols)[col] && !(*diags1)[diag1] && !(*diags2)[diag2] {
// 尝试:将皇后放置在该格子
(*state)[row][col] = "Q"

View File

@ -35,7 +35,7 @@ func whileLoopII(n int) int {
res := 0
// 初始化条件变量
i := 1
// 循环求和 1, 4, ...
// 循环求和 1, 4, 10, ...
for i <= n {
res += i
// 更新条件变量

View File

@ -16,7 +16,7 @@ func move(src, tar *list.List) {
src.Remove(pan)
}
/* 求解汉诺塔问题 f(i) */
/* 求解汉诺塔问题 f(i) */
func dfsHanota(i int, src, buf, tar *list.List) {
// 若 src 只剩下一个圆盘,则直接将其移到 tar
if i == 1 {
@ -31,7 +31,7 @@ func dfsHanota(i int, src, buf, tar *list.List) {
dfsHanota(i-1, buf, src, tar)
}
/* 求解汉诺塔 */
/* 求解汉诺塔问题 */
func solveHanota(A, B, C *list.List) {
n := A.Len()
// 将 A 顶部 n 个圆盘借助 B 移到 C

View File

@ -24,7 +24,7 @@ func backtrack(choices []int, state, n int, res []int) {
/* 爬楼梯:回溯 */
func climbingStairsBacktrack(n int) int {
// 可选择向上爬 1 或 2 阶
// 可选择向上爬 1 或 2 阶
choices := []int{1, 2}
// 从第 0 阶开始爬
state := 0

View File

@ -19,7 +19,7 @@ func coinChangeDP(coins []int, amt int) int {
for a := 1; a <= amt; a++ {
dp[0][a] = max
}
// 状态转移:其余行列
// 状态转移:其余行
for i := 1; i <= n; i++ {
for a := 1; a <= amt; a++ {
if coins[i-1] > a {

View File

@ -16,7 +16,7 @@ func coinChangeIIDP(coins []int, amt int) int {
for i := 0; i <= n; i++ {
dp[i][0] = 1
}
// 状态转移:其余行列
// 状态转移:其余行
for i := 1; i <= n; i++ {
for a := 1; a <= amt; a++ {
if coins[i-1] > a {

View File

@ -76,7 +76,7 @@ func editDistanceDP(s string, t string) int {
for j := 1; j <= m; j++ {
dp[0][j] = j
}
// 状态转移:其余行列
// 状态转移:其余行
for i := 1; i <= n; i++ {
for j := 1; j <= m; j++ {
if s[i-1] == t[j-1] {

View File

@ -8,11 +8,11 @@ import "math"
/* 0-1 背包:暴力搜索 */
func knapsackDFS(wgt, val []int, i, c int) int {
// 若已选完所有物品或背包无容量,则返回价值 0
// 若已选完所有物品或背包无剩余容量,则返回价值 0
if i == 0 || c == 0 {
return 0
}
// 若超过背包容量,则只能不放入背包
// 若超过背包容量,则只能选择不放入背包
if wgt[i-1] > c {
return knapsackDFS(wgt, val, i-1, c)
}
@ -25,7 +25,7 @@ func knapsackDFS(wgt, val []int, i, c int) int {
/* 0-1 背包:记忆化搜索 */
func knapsackDFSMem(wgt, val []int, mem [][]int, i, c int) int {
// 若已选完所有物品或背包无容量,则返回价值 0
// 若已选完所有物品或背包无剩余容量,则返回价值 0
if i == 0 || c == 0 {
return 0
}
@ -33,7 +33,7 @@ func knapsackDFSMem(wgt, val []int, mem [][]int, i, c int) int {
if mem[i][c] != -1 {
return mem[i][c]
}
// 若超过背包容量,则只能不放入背包
// 若超过背包容量,则只能选择不放入背包
if wgt[i-1] > c {
return knapsackDFSMem(wgt, val, mem, i-1, c)
}

View File

@ -62,7 +62,7 @@ func minPathSumDP(grid [][]int) int {
for i := 1; i < n; i++ {
dp[i][0] = dp[i-1][0] + grid[i][0]
}
// 状态转移:其余行列
// 状态转移:其余行
for i := 1; i < n; i++ {
for j := 1; j < m; j++ {
dp[i][j] = int(math.Min(float64(dp[i][j-1]), float64(dp[i-1][j]))) + grid[i][j]
@ -81,7 +81,7 @@ func minPathSumDPComp(grid [][]int) int {
for j := 1; j < m; j++ {
dp[j] = dp[j-1] + grid[0][j]
}
// 状态转移:其余行列
// 状态转移:其余行
for i := 1; i < n; i++ {
// 状态转移:首列
dp[0] = dp[0] + grid[i][0]

View File

@ -14,7 +14,7 @@ import (
/* 基于邻接表实现的无向图类 */
type graphAdjList struct {
// 邻接表key: 顶点value该顶点的所有邻接顶点
// 邻接表key顶点value该顶点的所有邻接顶点
adjList map[Vertex][]Vertex
}

View File

@ -76,7 +76,7 @@ func (g *graphAdjMat) addEdge(i, j int) {
if i < 0 || j < 0 || i >= g.size() || j >= g.size() || i == j {
fmt.Errorf("%s", "Index Out Of Bounds Exception")
}
// 在无向图中,邻接矩阵沿主对角线对称,即满足 (i, j) == (j, i)
// 在无向图中,邻接矩阵关于主对角线对称,即满足 (i, j) == (j, i)
g.adjMat[i][j] = 1
g.adjMat[j][i] = 1
}

View File

@ -12,7 +12,7 @@ type pair struct {
val string
}
/* 基于数组简易实现的哈希表 */
/* 基于数组实现的哈希表 */
type arrayHashMap struct {
buckets []*pair
}

View File

@ -100,7 +100,7 @@ func (h *maxHeap) pop() any {
fmt.Println("error")
return nil
}
// 交换根节点与最右叶节点(交换首元素与尾元素)
// 交换根节点与最右叶节点(交换首元素与尾元素)
h.swap(0, h.size()-1)
// 删除节点
val := h.data[len(h.data)-1]

View File

@ -23,9 +23,9 @@ func binarySearch(nums []int, target int) int {
return -1
}
/* 二分查找(左闭右开) */
/* 二分查找(左闭右开区间 */
func binarySearchLCRO(nums []int, target int) int {
// 初始化左闭右开 [0, n) ,即 i, j 分别指向数组首元素、尾元素+1
// 初始化左闭右开区间 [0, n) ,即 i, j 分别指向数组首元素、尾元素+1
i, j := 0, len(nums)
// 循环,当搜索区间为空时跳出(当 i = j 时为空)
for i < j {

View File

@ -7,7 +7,7 @@ package chapter_searching
/* 方法一:暴力枚举 */
func twoSumBruteForce(nums []int, target int) []int {
size := len(nums)
// 两层循环,时间复杂度 O(n^2)
// 两层循环,时间复杂度 O(n^2)
for i := 0; i < size-1; i++ {
for j := i + 1; i < size; j++ {
if nums[i]+nums[j] == target {
@ -20,9 +20,9 @@ func twoSumBruteForce(nums []int, target int) []int {
/* 方法二:辅助哈希表 */
func twoSumHashTable(nums []int, target int) []int {
// 辅助哈希表,空间复杂度 O(n)
// 辅助哈希表,空间复杂度 O(n)
hashTable := map[int]int{}
// 单层循环,时间复杂度 O(n)
// 单层循环,时间复杂度 O(n)
for idx, val := range nums {
if preIdx, ok := hashTable[target-val]; ok {
return []int{preIdx, idx}

View File

@ -16,7 +16,7 @@ func bucketSort(nums []float64) {
}
// 1. 将数组元素分配到各个桶中
for _, num := range nums {
// 输入数据范围 [0, 1),使用 num * k 映射到索引范围 [0, k-1]
// 输入数据范围 [0, 1),使用 num * k 映射到索引范围 [0, k-1]
i := int(num * float64(k))
// 将 num 添加进桶 i
buckets[i] = append(buckets[i], num)

View File

@ -36,7 +36,7 @@ func heapSort(nums *[]int) {
}
// 从堆中提取最大元素,循环 n-1 轮
for i := len(*nums) - 1; i > 0; i-- {
// 交换根节点与最右叶节点(交换首元素与尾元素)
// 交换根节点与最右叶节点(交换首元素与尾元素)
(*nums)[0], (*nums)[i] = (*nums)[i], (*nums)[0]
// 以根节点为起点,从顶至底进行堆化
siftDown(nums, i, 0)

View File

@ -15,7 +15,7 @@ type quickSortTailCall struct{}
/* 哨兵划分 */
func (q *quickSort) partition(nums []int, left, right int) int {
// 以 nums[left] 为基准数
// 以 nums[left] 为基准数
i, j := left, right
for i < j {
for i < j && nums[j] >= nums[left] {
@ -59,11 +59,11 @@ func (q *quickSortMedian) medianThree(nums []int, left, mid, right int) int {
/* 哨兵划分(三数取中值)*/
func (q *quickSortMedian) partition(nums []int, left, right int) int {
// 以 nums[left] 为基准数
// 以 nums[left] 为基准数
med := q.medianThree(nums, left, (left+right)/2, right)
// 将中位数交换至数组最左端
nums[left], nums[med] = nums[med], nums[left]
// 以 nums[left] 为基准数
// 以 nums[left] 为基准数
i, j := left, right
for i < j {
for i < j && nums[j] >= nums[left] {
@ -95,7 +95,7 @@ func (q *quickSortMedian) quickSort(nums []int, left, right int) {
/* 哨兵划分 */
func (q *quickSortTailCall) partition(nums []int, left, right int) int {
// 以 nums[left] 为基准数
// 以 nums[left] 为基准数
i, j := left, right
for i < j {
for i < j && nums[j] >= nums[left] {
@ -118,7 +118,7 @@ func (q *quickSortTailCall) quickSort(nums []int, left, right int) {
for left < right {
// 哨兵划分操作
pivot := q.partition(nums, left, right)
// 对两个子数组中较短的那个执行快
// 对两个子数组中较短的那个执行快速排序
if pivot-left < right-pivot {
q.quickSort(nums, left, pivot-1) // 递归排序左子数组
left = pivot + 1 // 剩余未排序区间为 [pivot + 1, right]

View File

@ -14,7 +14,7 @@ func digit(num, exp int) int {
/* 计数排序(根据 nums 第 k 位排序) */
func countingSortDigit(nums []int, exp int) {
// 十进制的位范围为 0~9 ,因此需要长度为 10 的桶
// 十进制的位范围为 0~9 ,因此需要长度为 10 的桶数组
counter := make([]int, 10)
n := len(nums)
// 统计 0~9 各数字的出现次数

View File

@ -19,7 +19,7 @@ func TestBinaryTree(t *testing.T) {
n3 := NewTreeNode(3)
n4 := NewTreeNode(4)
n5 := NewTreeNode(5)
// 构建引用指向(即指针)
// 构建节点之间的引用(指针)
n1.Left = n2
n1.Right = n3
n2.Left = n4