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

@@ -32,11 +32,11 @@ pub fn insert(nums: []i32, num: i32, index: usize) void {
while (i > index) : (i -= 1) {
nums[i] = nums[i - 1];
}
// 将 num 赋给 index 处元素
// 将 num 赋给 index 处元素
nums[index] = num;
}
// 删除索引 index 处元素
// 删除索引 index 处元素
pub fn remove(nums: []i32, index: usize) void {
// 把索引 index 之后的所有元素向前移动一位
var i = index;

View File

@@ -53,7 +53,7 @@ pub fn main() !void {
var n2 = inc.ListNode(i32){.val = 2};
var n3 = inc.ListNode(i32){.val = 5};
var n4 = inc.ListNode(i32){.val = 4};
// 构建引用指向
// 构建节点之间的引用
n0.next = &n1;
n1.next = &n2;
n2.next = &n3;

View File

@@ -29,7 +29,7 @@ pub fn main() !void {
std.debug.print("\n清空列表后 nums = ", .{});
inc.PrintUtil.printList(i32, nums);
// 尾部添加元素
// 尾部添加元素
try nums.append(1);
try nums.append(3);
try nums.append(2);
@@ -38,7 +38,7 @@ pub fn main() !void {
std.debug.print("\n添加元素后 nums = ", .{});
inc.PrintUtil.printList(i32, nums);
// 中间插入元素
// 中间插入元素
try nums.insert(3, 6);
std.debug.print("\n在索引 3 处插入数字 6 ,得到 nums = ", .{});
inc.PrintUtil.printList(i32, nums);

View File

@@ -5,14 +5,14 @@
const std = @import("std");
const inc = @import("include");
// 列表类简易实现
// 列表类
pub fn MyList(comptime T: type) type {
return struct {
const Self = @This();
arr: []T = undefined, // 数组(存储列表元素)
arrCapacity: usize = 10, // 列表容量
numSize: usize = 0, // 列表长度(当前元素数量)
numSize: usize = 0, // 列表长度(当前元素数量)
extendRatio: usize = 2, // 每次列表扩容的倍数
mem_arena: ?std.heap.ArenaAllocator = null,
mem_allocator: std.mem.Allocator = undefined, // 内存分配器
@@ -33,7 +33,7 @@ pub fn MyList(comptime T: type) type {
self.mem_arena.?.deinit();
}
// 获取列表长度(当前元素数量)
// 获取列表长度(当前元素数量)
pub fn size(self: *Self) usize {
return self.numSize;
}
@@ -57,7 +57,7 @@ pub fn MyList(comptime T: type) type {
self.arr[index] = num;
}
// 尾部添加元素
// 尾部添加元素
pub fn add(self: *Self, num: T) !void {
// 元素数量超出容量时,触发扩容机制
if (self.size() == self.capacity()) try self.extendCapacity();
@@ -66,7 +66,7 @@ pub fn MyList(comptime T: type) type {
self.numSize += 1;
}
// 中间插入元素
// 中间插入元素
pub fn insert(self: *Self, index: usize, num: T) !void {
if (index < 0 or index >= self.size()) @panic("索引越界");
// 元素数量超出容量时,触发扩容机制
@@ -130,7 +130,7 @@ pub fn main() !void {
// 延迟释放内存
defer nums.deinit();
// 尾部添加元素
// 尾部添加元素
try nums.add(1);
try nums.add(3);
try nums.add(2);
@@ -140,7 +140,7 @@ pub fn main() !void {
inc.PrintUtil.printArray(i32, try nums.toArray());
std.debug.print(" ,容量 = {} ,长度 = {}", .{nums.capacity(), nums.size()});
// 中间插入元素
// 中间插入元素
try nums.insert(3, 6);
std.debug.print("\n在索引 3 处插入数字 6 ,得到 nums = ", .{});
inc.PrintUtil.printArray(i32, try nums.toArray());

View File

@@ -31,7 +31,7 @@ fn whileLoop(n: i32) i32 {
fn whileLoopII(n: i32) i32 {
var res: i32 = 0;
var i: i32 = 1; // 初始化条件变量
// 循环求和 1, 4, ...
// 循环求和 1, 4, 10, ...
while (i <= n) {
res += @intCast(i);
// 更新条件变量

View File

@@ -24,7 +24,7 @@ fn backtrack(choices: []i32, state: i32, n: i32, res: std.ArrayList(i32)) void {
// 爬楼梯:回溯
fn climbingStairsBacktrack(n: usize) !i32 {
var choices = [_]i32{ 1, 2 }; // 可选择向上爬 1 或 2 阶
var choices = [_]i32{ 1, 2 }; // 可选择向上爬 1 或 2 阶
var state: i32 = 0; // 从第 0 阶开始爬
var res = std.ArrayList(i32).init(std.heap.page_allocator);
defer res.deinit();

View File

@@ -14,7 +14,7 @@ fn coinChangeDP(comptime coins: []i32, comptime amt: usize) i32 {
for (1..amt + 1) |a| {
dp[0][a] = max;
}
// 状态转移:其余行列
// 状态转移:其余行
for (1..n + 1) |i| {
for (1..amt + 1) |a| {
if (coins[i - 1] > @as(i32, @intCast(a))) {

View File

@@ -73,7 +73,7 @@ fn editDistanceDP(comptime s: []const u8, comptime t: []const u8) i32 {
for (1..m + 1) |j| {
dp[0][j] = @intCast(j);
}
// 状态转移:其余行列
// 状态转移:其余行
for (1..n + 1) |i| {
for (1..m + 1) |j| {
if (s[i - 1] == t[j - 1]) {

View File

@@ -6,11 +6,11 @@ const std = @import("std");
// 0-1 背包:暴力搜索
fn knapsackDFS(wgt: []i32, val: []i32, i: usize, c: usize) i32 {
// 若已选完所有物品或背包无容量,则返回价值 0
// 若已选完所有物品或背包无剩余容量,则返回价值 0
if (i == 0 or c == 0) {
return 0;
}
// 若超过背包容量,则只能不放入背包
// 若超过背包容量,则只能选择不放入背包
if (wgt[i - 1] > c) {
return knapsackDFS(wgt, val, i - 1, c);
}
@@ -23,7 +23,7 @@ fn knapsackDFS(wgt: []i32, val: []i32, i: usize, c: usize) i32 {
// 0-1 背包:记忆化搜索
fn knapsackDFSMem(wgt: []i32, val: []i32, mem: anytype, i: usize, c: usize) i32 {
// 若已选完所有物品或背包无容量,则返回价值 0
// 若已选完所有物品或背包无剩余容量,则返回价值 0
if (i == 0 or c == 0) {
return 0;
}
@@ -31,7 +31,7 @@ fn knapsackDFSMem(wgt: []i32, val: []i32, mem: anytype, i: usize, c: usize) i32
if (mem[i][c] != -1) {
return mem[i][c];
}
// 若超过背包容量,则只能不放入背包
// 若超过背包容量,则只能选择不放入背包
if (wgt[i - 1] > c) {
return knapsackDFSMem(wgt, val, mem, i - 1, c);
}

View File

@@ -59,7 +59,7 @@ fn minPathSumDP(comptime grid: anytype) i32 {
for (1..n) |i| {
dp[i][0] = dp[i - 1][0] + grid[i][0];
}
// 状态转移:其余行列
// 状态转移:其余行
for (1..n) |i| {
for (1..m) |j| {
dp[i][j] = @min(dp[i][j - 1], dp[i - 1][j]) + grid[i][j];

View File

@@ -18,7 +18,7 @@ const Pair = struct {
}
};
// 基于数组简易实现的哈希表
// 基于数组实现的哈希表
pub fn ArrayHashMap(comptime T: type) type {
return struct {
bucket: ?std.ArrayList(?T) = null,

View File

@@ -95,7 +95,7 @@ pub fn MaxHeap(comptime T: type) type {
pub fn pop(self: *Self) !T {
// 判断处理
if (self.isEmpty()) unreachable;
// 交换根节点与最右叶节点(交换首元素与尾元素)
// 交换根节点与最右叶节点(交换首元素与尾元素)
try self.swap(0, self.size() - 1);
// 删除节点
var val = self.max_heap.?.pop();

View File

@@ -25,9 +25,9 @@ fn binarySearch(comptime T: type, nums: std.ArrayList(T), target: T) T {
return -1;
}
// 二分查找(左闭右开)
// 二分查找(左闭右开区间
fn binarySearchLCRO(comptime T: type, nums: std.ArrayList(T), target: T) T {
// 初始化左闭右开 [0, n) ,即 i, j 分别指向数组首元素、尾元素+1
// 初始化左闭右开区间 [0, n) ,即 i, j 分别指向数组首元素、尾元素+1
var i: usize = 0;
var j: usize = nums.items.len;
// 循环,当搜索区间为空时跳出(当 i = j 时为空)
@@ -56,7 +56,7 @@ pub fn main() !void {
var index = binarySearch(i32, nums, target);
std.debug.print("目标元素 6 的索引 = {}\n", .{index});
// 二分查找(左闭右开)
// 二分查找(左闭右开区间
index = binarySearchLCRO(i32, nums, target);
std.debug.print("目标元素 6 的索引 = {}\n", .{index});

View File

@@ -9,7 +9,7 @@ const inc = @import("include");
pub fn twoSumBruteForce(nums: []i32, target: i32) ?[2]i32 {
var size: usize = nums.len;
var i: usize = 0;
// 两层循环,时间复杂度 O(n^2)
// 两层循环,时间复杂度 O(n^2)
while (i < size - 1) : (i += 1) {
var j = i + 1;
while (j < size) : (j += 1) {
@@ -24,11 +24,11 @@ pub fn twoSumBruteForce(nums: []i32, target: i32) ?[2]i32 {
// 方法二:辅助哈希表
pub fn twoSumHashTable(nums: []i32, target: i32) !?[2]i32 {
var size: usize = nums.len;
// 辅助哈希表,空间复杂度 O(n)
// 辅助哈希表,空间复杂度 O(n)
var dic = std.AutoHashMap(i32, i32).init(std.heap.page_allocator);
defer dic.deinit();
var i: usize = 0;
// 单层循环,时间复杂度 O(n)
// 单层循环,时间复杂度 O(n)
while (i < size) : (i += 1) {
if (dic.contains(target - nums[i])) {
return [_]i32{dic.get(target - nums[i]).?, @intCast(i)};

View File

@@ -17,7 +17,7 @@ const QuickSort = struct {
// 哨兵划分
pub fn partition(nums: []i32, left: usize, right: usize) usize {
// 以 nums[left] 为基准数
// 以 nums[left] 为基准数
var i = left;
var j = right;
while (i < j) {
@@ -70,7 +70,7 @@ const QuickSortMedian = struct {
var med = medianThree(nums, left, (left + right) / 2, right);
// 将中位数交换至数组最左端
swap(nums, left, med);
// 以 nums[left] 为基准数
// 以 nums[left] 为基准数
var i = left;
var j = right;
while (i < j) {
@@ -107,7 +107,7 @@ const QuickSortTailCall = struct {
// 哨兵划分
pub fn partition(nums: []i32, left: usize, right: usize) usize {
// 以 nums[left] 为基准数
// 以 nums[left] 为基准数
var i = left;
var j = right;
while (i < j) {
@@ -127,7 +127,7 @@ const QuickSortTailCall = struct {
while (left < right) {
// 哨兵划分操作
var pivot = partition(nums, left, right);
// 对两个子数组中较短的那个执行快
// 对两个子数组中较短的那个执行快速排序
if (pivot - left < right - pivot) {
quickSort(nums, left, pivot - 1); // 递归排序左子数组
left = pivot + 1; // 剩余未排序区间为 [pivot + 1, right]

View File

@@ -13,7 +13,7 @@ fn digit(num: i32, exp: i32) i32 {
// 计数排序(根据 nums 第 k 位排序)
fn countingSortDigit(nums: []i32, exp: i32) !void {
// 十进制的位范围为 0~9 ,因此需要长度为 10 的桶
// 十进制的位范围为 0~9 ,因此需要长度为 10 的桶数组
var mem_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
// defer mem_arena.deinit();
const mem_allocator = mem_arena.allocator();

View File

@@ -65,7 +65,7 @@ pub fn LinkedListDeque(comptime T: type) type {
pub fn push(self: *Self, num: T, is_front: bool) !void {
var node = try self.mem_allocator.create(ListNode(T));
node.init(num);
// 若链表为空,则令 front, rear 都指向 node
// 若链表为空,则令 front rear 都指向 node
if (self.isEmpty()) {
self.front = node;
self.rear = node;

View File

@@ -14,7 +14,7 @@ pub fn main() !void {
var n3 = inc.TreeNode(i32){ .val = 3 };
var n4 = inc.TreeNode(i32){ .val = 4 };
var n5 = inc.TreeNode(i32){ .val = 5 };
// 构建引用指向(即指针)
// 构建节点之间的引用(指针)
n1.left = &n2;
n1.right = &n3;
n2.left = &n4;