mirror of
https://github.com/krahets/hello-algo.git
synced 2025-11-02 21:24:53 +08:00
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:
@ -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++ {
|
||||
|
||||
@ -20,7 +20,7 @@ func TestLinkedList(t *testing.T) {
|
||||
n3 := NewListNode(5)
|
||||
n4 := NewListNode(4)
|
||||
|
||||
// 构建引用指向
|
||||
// 构建节点之间的引用
|
||||
n0.Next = n1
|
||||
n1.Next = n2
|
||||
n2.Next = n3
|
||||
|
||||
@ -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)
|
||||
|
||||
|
||||
@ -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("索引越界")
|
||||
|
||||
@ -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())
|
||||
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -35,7 +35,7 @@ func whileLoopII(n int) int {
|
||||
res := 0
|
||||
// 初始化条件变量
|
||||
i := 1
|
||||
// 循环求和 1, 4, ...
|
||||
// 循环求和 1, 4, 10, ...
|
||||
for i <= n {
|
||||
res += i
|
||||
// 更新条件变量
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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] {
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -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]
|
||||
|
||||
@ -14,7 +14,7 @@ import (
|
||||
|
||||
/* 基于邻接表实现的无向图类 */
|
||||
type graphAdjList struct {
|
||||
// 邻接表,key: 顶点,value:该顶点的所有邻接顶点
|
||||
// 邻接表,key:顶点,value:该顶点的所有邻接顶点
|
||||
adjList map[Vertex][]Vertex
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -12,7 +12,7 @@ type pair struct {
|
||||
val string
|
||||
}
|
||||
|
||||
/* 基于数组简易实现的哈希表 */
|
||||
/* 基于数组实现的哈希表 */
|
||||
type arrayHashMap struct {
|
||||
buckets []*pair
|
||||
}
|
||||
|
||||
@ -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]
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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}
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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]
|
||||
|
||||
@ -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 各数字的出现次数
|
||||
|
||||
@ -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
|
||||
|
||||
Reference in New Issue
Block a user