From 6bac0db1c4dd217b6f0ed17c28c8f294d91bfa10 Mon Sep 17 00:00:00 2001 From: krahets Date: Fri, 24 May 2024 16:12:17 +0800 Subject: [PATCH] build --- .../backtracking_algorithm.md | 120 ++++++++++++++++-- docs/chapter_backtracking/n_queens_problem.md | 42 +++++- .../permutations_problem.md | 68 +++++++++- .../subset_sum_problem.md | 104 +++++++++++++-- .../binary_search_recur.md | 2 +- docs/chapter_hashing/hash_collision.md | 4 +- docs/chapter_sorting/merge_sort.md | 34 ++--- docs/chapter_sorting/quick_sort.md | 2 +- docs/chapter_sorting/radix_sort.md | 4 +- .../binary_search_recur.md | 4 +- en/docs/chapter_searching/binary_search.md | 4 +- .../binary_search_insertion.md | 4 +- en/docs/chapter_sorting/merge_sort.md | 6 +- .../backtracking_algorithm.md | 120 ++++++++++++++++-- .../chapter_backtracking/n_queens_problem.md | 42 +++++- .../permutations_problem.md | 68 +++++++++- .../subset_sum_problem.md | 104 +++++++++++++-- .../binary_search_recur.md | 2 +- .../docs/chapter_hashing/hash_collision.md | 4 +- zh-Hant/docs/chapter_sorting/merge_sort.md | 34 ++--- zh-Hant/docs/chapter_sorting/quick_sort.md | 2 +- zh-Hant/docs/chapter_sorting/radix_sort.md | 4 +- 22 files changed, 657 insertions(+), 121 deletions(-) diff --git a/docs/chapter_backtracking/backtracking_algorithm.md b/docs/chapter_backtracking/backtracking_algorithm.md index 4c0a89fcc..9abc8e295 100644 --- a/docs/chapter_backtracking/backtracking_algorithm.md +++ b/docs/chapter_backtracking/backtracking_algorithm.md @@ -220,7 +220,16 @@ comments: true === "Ruby" ```ruby title="preorder_traversal_i_compact.rb" - [class]{}-[func]{pre_order} + ### 前序遍历:例题一 ### + def pre_order(root) + return unless root + + # 记录解 + $res << root if root.val == 7 + + pre_order(root.left) + pre_order(root.right) + end ``` === "Zig" @@ -522,7 +531,22 @@ comments: true === "Ruby" ```ruby title="preorder_traversal_ii_compact.rb" - [class]{}-[func]{pre_order} + ### 前序遍历:例题二 ### + def pre_order(root) + return unless root + + # 尝试 + $path << root + + # 记录解 + $res << $path.dup if root.val == 7 + + pre_order(root.left) + pre_order(root.right) + + # 回退 + $path.pop + end ``` === "Zig" @@ -866,7 +890,23 @@ comments: true === "Ruby" ```ruby title="preorder_traversal_iii_compact.rb" - [class]{}-[func]{pre_order} + ### 前序遍历:例题三 ### + def pre_order(root) + # 剪枝 + return if !root || root.val == 3 + + # 尝试 + $path.append(root) + + # 记录解 + $res << $path.dup if root.val == 7 + + pre_order(root.left) + pre_order(root.right) + + # 回退 + $path.pop + end ``` === "Zig" @@ -1203,7 +1243,27 @@ comments: true === "Ruby" ```ruby title="" + ### 回溯算法框架 ### + def backtrack(state, choices, res) + # 判断是否为解 + if is_solution?(state) + # 记录解 + record_solution(state, res) + return + end + # 遍历所有选择 + for choice in choices + # 剪枝:判断选择是否合法 + if is_valid?(state, choice) + # 尝试:做出选择,更新状态 + make_choice(state, choice) + backtrack(state, choices, res) + # 回退:撤销选择,恢复到之前的状态 + undo_choice(state, choice) + end + end + end ``` === "Zig" @@ -1843,17 +1903,49 @@ comments: true === "Ruby" ```ruby title="preorder_traversal_iii_template.rb" - [class]{}-[func]{is_solution} - - [class]{}-[func]{record_solution} - - [class]{}-[func]{is_valid} - - [class]{}-[func]{make_choice} - - [class]{}-[func]{undo_choice} - - [class]{}-[func]{backtrack} + ### 判断当前状态是否为解 ### + def is_solution?(state) + !state.empty? && state.last.val == 7 + end + + ### 记录解 ### + def record_solution(state, res) + res << state.dup + end + + ### 判断在当前状态下,该选择是否合法 ### + def is_valid?(state, choice) + choice && choice.val != 3 + end + + ### 更新状态 ### + def make_choice(state, choice) + state << choice + end + + ### 恢复状态 ### + def undo_choice(state, choice) + state.pop + end + + ### 回溯算法:例题三 ### + def backtrack(state, choices, res) + # 检查是否为解 + record_solution(state, res) if is_solution?(state) + + # 遍历所有选择 + for choice in choices + # 剪枝:检查选择是否合法 + if is_valid?(state, choice) + # 尝试:做出选择,更新状态 + make_choice(state, choice) + # 进行下一轮选择 + backtrack(state, [choice.left, choice.right], res) + # 回退:撤销选择,恢复到之前的状态 + undo_choice(state, choice) + end + end + end ``` === "Zig" diff --git a/docs/chapter_backtracking/n_queens_problem.md b/docs/chapter_backtracking/n_queens_problem.md index afd3e80b7..eb9b4ef88 100644 --- a/docs/chapter_backtracking/n_queens_problem.md +++ b/docs/chapter_backtracking/n_queens_problem.md @@ -710,9 +710,45 @@ comments: true === "Ruby" ```ruby title="n_queens.rb" - [class]{}-[func]{backtrack} - - [class]{}-[func]{n_queens} + ### 回溯算法:n 皇后 ### + def backtrack(row, n, state, res, cols, diags1, diags2) + # 当放置完所有行时,记录解 + if row == n + res << state.map { |row| row.dup } + return + end + + # 遍历所有列 + for col in 0...n + # 计算该格子对应的主对角线和次对角线 + diag1 = row - col + n - 1 + diag2 = row + col + # 剪枝:不允许该格子所在列、主对角线、次对角线上存在皇后 + if !cols[col] && !diags1[diag1] && !diags2[diag2] + # 尝试:将皇后放置在该格子 + state[row][col] = "Q" + cols[col] = diags1[diag1] = diags2[diag2] = true + # 放置下一行 + backtrack(row + 1, n, state, res, cols, diags1, diags2) + # 回退:将该格子恢复为空位 + state[row][col] = "#" + cols[col] = diags1[diag1] = diags2[diag2] = false + end + end + end + + ### 求解 n 皇后 ### + def n_queens(n) + # 初始化 n*n 大小的棋盘,其中 'Q' 代表皇后,'#' 代表空位 + state = Array.new(n) { Array.new(n, "#") } + cols = Array.new(n, false) # 记录列是否有皇后 + diags1 = Array.new(2 * n - 1, false) # 记录主对角线上是否有皇后 + diags2 = Array.new(2 * n - 1, false) # 记录次对角线上是否有皇后 + res = [] + backtrack(0, n, state, res, cols, diags1, diags2) + + res + end ``` === "Zig" diff --git a/docs/chapter_backtracking/permutations_problem.md b/docs/chapter_backtracking/permutations_problem.md index e8d1c1a67..9692efd20 100644 --- a/docs/chapter_backtracking/permutations_problem.md +++ b/docs/chapter_backtracking/permutations_problem.md @@ -506,9 +506,36 @@ comments: true === "Ruby" ```ruby title="permutations_i.rb" - [class]{}-[func]{backtrack} - - [class]{}-[func]{permutations_i} + ### 回溯算法:全排列 I ### + def backtrack(state, choices, selected, res) + # 当状态长度等于元素数量时,记录解 + if state.length == choices.length + res << state.dup + return + end + + # 遍历所有选择 + choices.each_with_index do |choice, i| + # 剪枝:不允许重复选择元素 + unless selected[i] + # 尝试:做出选择,更新状态 + selected[i] = true + state << choice + # 进行下一轮选择 + backtrack(state, choices, selected, res) + # 回退:撤销选择,恢复到之前的状态 + selected[i] = false + state.pop + end + end + end + + ### 全排列 I ### + def permutations_i(nums) + res = [] + backtrack([], nums, Array.new(nums.length, false), res) + res + end ``` === "Zig" @@ -1032,9 +1059,38 @@ comments: true === "Ruby" ```ruby title="permutations_ii.rb" - [class]{}-[func]{backtrack} - - [class]{}-[func]{permutations_ii} + ### 回溯算法:全排列 II ### + def backtrack(state, choices, selected, res) + # 当状态长度等于元素数量时,记录解 + if state.length == choices.length + res << state.dup + return + end + + # 遍历所有选择 + duplicated = Set.new + choices.each_with_index do |choice, i| + # 剪枝:不允许重复选择元素 且 不允许重复选择相等元素 + if !selected[i] && !duplicated.include?(choice) + # 尝试:做出选择,更新状态 + duplicated.add(choice) + selected[i] = true + state << choice + # 进行下一轮选择 + backtrack(state, choices, selected, res) + # 回退:撤销选择,恢复到之前的状态 + selected[i] = false + state.pop + end + end + end + + ### 全排列 II ### + def permutations_ii(nums) + res = [] + backtrack([], nums, Array.new(nums.length, false), res) + res + end ``` === "Zig" diff --git a/docs/chapter_backtracking/subset_sum_problem.md b/docs/chapter_backtracking/subset_sum_problem.md index 2cb091379..4d63813cf 100644 --- a/docs/chapter_backtracking/subset_sum_problem.md +++ b/docs/chapter_backtracking/subset_sum_problem.md @@ -470,9 +470,35 @@ comments: true === "Ruby" ```ruby title="subset_sum_i_naive.rb" - [class]{}-[func]{backtrack} - - [class]{}-[func]{subset_sum_i_naive} + ### 回溯算法:子集和 I ### + def backtrack(state, target, total, choices, res) + # 子集和等于 target 时,记录解 + if total == target + res << state.dup + return + end + + # 遍历所有选择 + for i in 0...choices.length + # 剪枝:若子集和超过 target ,则跳过该选择 + next if total + choices[i] > target + # 尝试:做出选择,更新元素和 total + state << choices[i] + # 进行下一轮选择 + backtrack(state, target, total + choices[i], choices, res) + # 回退:撤销选择,恢复到之前的状态 + state.pop + end + end + + ### 求解子集和 I(包含重复子集)### + def subset_sum_i_naive(nums, target) + state = [] # 状态(子集) + total = 0 # 子集和 + res = [] # 结果列表(子集列表) + backtrack(state, target, total, nums, res) + res + end ``` === "Zig" @@ -1011,9 +1037,37 @@ comments: true === "Ruby" ```ruby title="subset_sum_i.rb" - [class]{}-[func]{backtrack} - - [class]{}-[func]{subset_sum_i} + ### 回溯算法:子集和 I ### + def backtrack(state, target, choices, start, res) + # 子集和等于 target 时,记录解 + if target.zero? + res << state.dup + return + end + # 遍历所有选择 + # 剪枝二:从 start 开始遍历,避免生成重复子集 + for i in start...choices.length + # 剪枝一:若子集和超过 target ,则直接结束循环 + # 这是因为数组已排序,后边元素更大,子集和一定超过 target + break if target - choices[i] < 0 + # 尝试:做出选择,更新 target, start + state << choices[i] + # 进行下一轮选择 + backtrack(state, target - choices[i], choices, i, res) + # 回退:撤销选择,恢复到之前的状态 + state.pop + end + end + + ### 求解子集和 I ### + def subset_sum_i(nums, target) + state = [] # 状态(子集) + nums.sort! # 对 nums 进行排序 + start = 0 # 遍历起始点 + res = [] # 结果列表(子集列表) + backtrack(state, target, nums, start, res) + res + end ``` === "Zig" @@ -1598,9 +1652,41 @@ comments: true === "Ruby" ```ruby title="subset_sum_ii.rb" - [class]{}-[func]{backtrack} - - [class]{}-[func]{subset_sum_ii} + ### 回溯算法:子集和 II ### + def backtrack(state, target, choices, start, res) + # 子集和等于 target 时,记录解 + if target.zero? + res << state.dup + return + end + + # 遍历所有选择 + # 剪枝二:从 start 开始遍历,避免生成重复子集 + # 剪枝三:从 start 开始遍历,避免重复选择同一元素 + for i in start...choices.length + # 剪枝一:若子集和超过 target ,则直接结束循环 + # 这是因为数组已排序,后边元素更大,子集和一定超过 target + break if target - choices[i] < 0 + # 剪枝四:如果该元素与左边元素相等,说明该搜索分支重复,直接跳过 + next if i > start && choices[i] == choices[i - 1] + # 尝试:做出选择,更新 target, start + state << choices[i] + # 进行下一轮选择 + backtrack(state, target - choices[i], choices, i + 1, res) + # 回退:撤销选择,恢复到之前的状态 + state.pop + end + end + + ### 求解子集和 II ### + def subset_sum_ii(nums, target) + state = [] # 状态(子集) + nums.sort! # 对 nums 进行排序 + start = 0 # 遍历起始点 + res = [] # 结果列表(子集列表) + backtrack(state, target, nums, start, res) + res + end ``` === "Zig" diff --git a/docs/chapter_divide_and_conquer/binary_search_recur.md b/docs/chapter_divide_and_conquer/binary_search_recur.md index 5ee60bcd8..e547a935f 100644 --- a/docs/chapter_divide_and_conquer/binary_search_recur.md +++ b/docs/chapter_divide_and_conquer/binary_search_recur.md @@ -331,7 +331,7 @@ comments: true if i > j { return -1; } - let m: i32 = (i + j) / 2; + let m: i32 = i + (j - i) / 2; if nums[m as usize] < target { // 递归子问题 f(m+1, j) return dfs(nums, target, m + 1, j); diff --git a/docs/chapter_hashing/hash_collision.md b/docs/chapter_hashing/hash_collision.md index 0ce44df38..9519880da 100644 --- a/docs/chapter_hashing/hash_collision.md +++ b/docs/chapter_hashing/hash_collision.md @@ -2896,7 +2896,7 @@ comments: true hashMap->capacity = 4; hashMap->loadThres = 2.0 / 3.0; hashMap->extendRatio = 2; - hashMap->buckets = (Pair **)malloc(sizeof(Pair *) * hashMap->capacity); + hashMap->buckets = (Pair **)calloc(hashMap->capacity, sizeof(Pair *)); hashMap->TOMBSTONE = (Pair *)malloc(sizeof(Pair)); hashMap->TOMBSTONE->key = -1; hashMap->TOMBSTONE->val = "-1"; @@ -3015,7 +3015,7 @@ comments: true int oldCapacity = hashMap->capacity; // 初始化扩容后的新哈希表 hashMap->capacity *= hashMap->extendRatio; - hashMap->buckets = (Pair **)malloc(sizeof(Pair *) * hashMap->capacity); + hashMap->buckets = (Pair **)calloc(hashMap->capacity, sizeof(Pair *)); hashMap->size = 0; // 将键值对从原哈希表搬运至新哈希表 for (int i = 0; i < oldCapacity; i++) { diff --git a/docs/chapter_sorting/merge_sort.md b/docs/chapter_sorting/merge_sort.md index 8ec1ed9af..2af130e60 100755 --- a/docs/chapter_sorting/merge_sort.md +++ b/docs/chapter_sorting/merge_sort.md @@ -99,7 +99,7 @@ comments: true if left >= right: return # 当子数组长度为 1 时终止递归 # 划分阶段 - mid = (left + right) // 2 # 计算中点 + mid = (left + right) // 2 # 计算中点 merge_sort(nums, left, mid) # 递归左子数组 merge_sort(nums, mid + 1, right) # 递归右子数组 # 合并阶段 @@ -142,7 +142,7 @@ comments: true if (left >= right) return; // 当子数组长度为 1 时终止递归 // 划分阶段 - int mid = (left + right) / 2; // 计算中点 + int mid = left + (right - left) / 2; // 计算中点 mergeSort(nums, left, mid); // 递归左子数组 mergeSort(nums, mid + 1, right); // 递归右子数组 // 合并阶段 @@ -186,7 +186,7 @@ comments: true if (left >= right) return; // 当子数组长度为 1 时终止递归 // 划分阶段 - int mid = (left + right) / 2; // 计算中点 + int mid = left + (right - left) / 2; // 计算中点 mergeSort(nums, left, mid); // 递归左子数组 mergeSort(nums, mid + 1, right); // 递归右子数组 // 合并阶段 @@ -229,7 +229,7 @@ comments: true // 终止条件 if (left >= right) return; // 当子数组长度为 1 时终止递归 // 划分阶段 - int mid = (left + right) / 2; // 计算中点 + int mid = left + (right - left) / 2; // 计算中点 MergeSort(nums, left, mid); // 递归左子数组 MergeSort(nums, mid + 1, right); // 递归右子数组 // 合并阶段 @@ -282,7 +282,7 @@ comments: true return } // 划分阶段 - mid := (left + right) / 2 + mid := left + (right - left) / 2 mergeSort(nums, left, mid) mergeSort(nums, mid+1, right) // 合并阶段 @@ -335,7 +335,7 @@ comments: true return } // 划分阶段 - let mid = (left + right) / 2 // 计算中点 + let mid = left + (right - left) / 2 // 计算中点 mergeSort(nums: &nums, left: left, right: mid) // 递归左子数组 mergeSort(nums: &nums, left: mid + 1, right: right) // 递归右子数组 // 合并阶段 @@ -381,7 +381,7 @@ comments: true // 终止条件 if (left >= right) return; // 当子数组长度为 1 时终止递归 // 划分阶段 - let mid = Math.floor((left + right) / 2); // 计算中点 + let mid = Math.floor(left + (right - left) / 2); // 计算中点 mergeSort(nums, left, mid); // 递归左子数组 mergeSort(nums, mid + 1, right); // 递归右子数组 // 合并阶段 @@ -427,7 +427,7 @@ comments: true // 终止条件 if (left >= right) return; // 当子数组长度为 1 时终止递归 // 划分阶段 - let mid = Math.floor((left + right) / 2); // 计算中点 + let mid = Math.floor(left + (right - left) / 2); // 计算中点 mergeSort(nums, left, mid); // 递归左子数组 mergeSort(nums, mid + 1, right); // 递归右子数组 // 合并阶段 @@ -470,7 +470,7 @@ comments: true // 终止条件 if (left >= right) return; // 当子数组长度为 1 时终止递归 // 划分阶段 - int mid = (left + right) ~/ 2; // 计算中点 + int mid = left + (right - left) ~/ 2; // 计算中点 mergeSort(nums, left, mid); // 递归左子数组 mergeSort(nums, mid + 1, right); // 递归右子数组 // 合并阶段 @@ -525,7 +525,7 @@ comments: true } // 划分阶段 - let mid = (left + right) / 2; // 计算中点 + let mid = left + (right - left) / 2; // 计算中点 merge_sort(nums, left, mid); // 递归左子数组 merge_sort(nums, mid + 1, right); // 递归右子数组 @@ -574,7 +574,7 @@ comments: true if (left >= right) return; // 当子数组长度为 1 时终止递归 // 划分阶段 - int mid = (left + right) / 2; // 计算中点 + int mid = left + (right - left) / 2; // 计算中点 mergeSort(nums, left, mid); // 递归左子数组 mergeSort(nums, mid + 1, right); // 递归右子数组 // 合并阶段 @@ -598,7 +598,7 @@ comments: true while (i <= mid && j <= right) { if (nums[i] <= nums[j]) tmp[k++] = nums[i++] - else + else tmp[k++] = nums[j++] } // 将左子数组和右子数组的剩余元素复制到临时数组中 @@ -619,7 +619,7 @@ comments: true // 终止条件 if (left >= right) return // 当子数组长度为 1 时终止递归 // 划分阶段 - val mid = (left + right) / 2 // 计算中点 + val mid = left + (right - left) / 2 // 计算中点 mergeSort(nums, left, mid) // 递归左子数组 mergeSort(nums, mid + 1, right) // 递归右子数组 // 合并阶段 @@ -671,7 +671,7 @@ comments: true # 当子数组长度为 1 时终止递归 return if left >= right # 划分阶段 - mid = (left + right) / 2 # 计算中点 + mid = left + (right - left) / 2 # 计算中点 merge_sort(nums, left, mid) # 递归左子数组 merge_sort(nums, mid + 1, right) # 递归右子数组 # 合并阶段 @@ -692,10 +692,10 @@ comments: true const mem_allocator = mem_arena.allocator(); var tmp = try mem_allocator.alloc(i32, right + 1 - left); std.mem.copy(i32, tmp, nums[left..right+1]); - // 左子数组的起始索引和结束索引 + // 左子数组的起始索引和结束索引 var leftStart = left - left; var leftEnd = mid - left; - // 右子数组的起始索引和结束索引 + // 右子数组的起始索引和结束索引 var rightStart = mid + 1 - left; var rightEnd = right - left; // i, j 分别指向左子数组、右子数组的首元素 @@ -725,7 +725,7 @@ comments: true // 终止条件 if (left >= right) return; // 当子数组长度为 1 时终止递归 // 划分阶段 - var mid = (left + right) / 2; // 计算中点 + var mid = left + (right - left) / 2; // 计算中点 try mergeSort(nums, left, mid); // 递归左子数组 try mergeSort(nums, mid + 1, right); // 递归右子数组 // 合并阶段 diff --git a/docs/chapter_sorting/quick_sort.md b/docs/chapter_sorting/quick_sort.md index 98bd76015..5930acda0 100755 --- a/docs/chapter_sorting/quick_sort.md +++ b/docs/chapter_sorting/quick_sort.md @@ -861,7 +861,7 @@ comments: true /* 哨兵划分(三数取中值) */ func partitionMedian(nums: inout [Int], left: Int, right: Int) -> Int { // 选取三个候选元素的中位数 - let med = medianThree(nums: nums, left: left, mid: (left + right) / 2, right: right) + let med = medianThree(nums: nums, left: left, mid: left + (right - left) / 2, right: right) // 将中位数交换至数组最左端 nums.swapAt(left, med) return partition(nums: &nums, left: left, right: right) diff --git a/docs/chapter_sorting/radix_sort.md b/docs/chapter_sorting/radix_sort.md index eb5067b5e..7380d86e5 100644 --- a/docs/chapter_sorting/radix_sort.md +++ b/docs/chapter_sorting/radix_sort.md @@ -545,9 +545,7 @@ $$ counter[d] -= 1; // 将 d 的数量减 1 } // 使用结果覆盖原数组 nums - for i in 0..n { - nums[i] = res[i]; - } + nums.copy_from_slice(&res); } /* 基数排序 */ diff --git a/en/docs/chapter_divide_and_conquer/binary_search_recur.md b/en/docs/chapter_divide_and_conquer/binary_search_recur.md index 9b1a289da..4f560db15 100644 --- a/en/docs/chapter_divide_and_conquer/binary_search_recur.md +++ b/en/docs/chapter_divide_and_conquer/binary_search_recur.md @@ -83,7 +83,7 @@ In the implementation code, we declare a recursive function `dfs()` to solve the return -1; } // Calculate midpoint index m - int m = (i + j) / 2; + int m = i + (j - i) / 2; if (nums[m] < target) { // Recursive subproblem f(m+1, j) return dfs(nums, target, m + 1, j); @@ -114,7 +114,7 @@ In the implementation code, we declare a recursive function `dfs()` to solve the return -1; } // Calculate midpoint index m - int m = (i + j) / 2; + int m = i + (j - i) / 2; if (nums[m] < target) { // Recursive subproblem f(m+1, j) return dfs(nums, target, m + 1, j); diff --git a/en/docs/chapter_searching/binary_search.md b/en/docs/chapter_searching/binary_search.md index a9df591f1..b44664cd2 100644 --- a/en/docs/chapter_searching/binary_search.md +++ b/en/docs/chapter_searching/binary_search.md @@ -63,7 +63,7 @@ The code is as follows: # Loop until the search interval is empty (when i > j, it is empty) while i <= j: # Theoretically, Python's numbers can be infinitely large (depending on memory size), so there is no need to consider large number overflow - m = (i + j) // 2 # Calculate midpoint index m + m = i + (j - i) // 2 # Calculate midpoint index m if nums[m] < target: i = m + 1 # This situation indicates that target is in the interval [m+1, j] elif nums[m] > target: @@ -202,7 +202,7 @@ We can implement a binary search algorithm with the same functionality based on i, j = 0, len(nums) # Loop until the search interval is empty (when i = j, it is empty) while i < j: - m = (i + j) // 2 # Calculate midpoint index m + m = i + (j - i) // 2 # Calculate midpoint index m if nums[m] < target: i = m + 1 # This situation indicates that target is in the interval [m+1, j) elif nums[m] > target: diff --git a/en/docs/chapter_searching/binary_search_insertion.md b/en/docs/chapter_searching/binary_search_insertion.md index c6a39b03d..4b01f838b 100644 --- a/en/docs/chapter_searching/binary_search_insertion.md +++ b/en/docs/chapter_searching/binary_search_insertion.md @@ -35,7 +35,7 @@ Therefore, at the end of the binary, it is certain that: $i$ points to the first """Binary search for insertion point (no duplicate elements)""" i, j = 0, len(nums) - 1 # Initialize double closed interval [0, n-1] while i <= j: - m = (i + j) // 2 # Calculate midpoint index m + m = i + (j - i) // 2 # Calculate midpoint index m if nums[m] < target: i = m + 1 # Target is in interval [m+1, j] elif nums[m] > target: @@ -217,7 +217,7 @@ Even so, we can still keep the conditions expanded, as their logic is clearer an """Binary search for insertion point (with duplicate elements)""" i, j = 0, len(nums) - 1 # Initialize double closed interval [0, n-1] while i <= j: - m = (i + j) // 2 # Calculate midpoint index m + m = i + (j - i) // 2 # Calculate midpoint index m if nums[m] < target: i = m + 1 # Target is in interval [m+1, j] elif nums[m] > target: diff --git a/en/docs/chapter_sorting/merge_sort.md b/en/docs/chapter_sorting/merge_sort.md index 94f1ea90c..9f0593f71 100644 --- a/en/docs/chapter_sorting/merge_sort.md +++ b/en/docs/chapter_sorting/merge_sort.md @@ -99,7 +99,7 @@ The implementation of merge sort is shown in the following code. Note that the i if left >= right: return # Terminate recursion when subarray length is 1 # Partition stage - mid = (left + right) // 2 # Calculate midpoint + mid = left + (right - left) // 2 # Calculate midpoint merge_sort(nums, left, mid) # Recursively process the left subarray merge_sort(nums, mid + 1, right) # Recursively process the right subarray # Merge stage @@ -142,7 +142,7 @@ The implementation of merge sort is shown in the following code. Note that the i if (left >= right) return; // Terminate recursion when subarray length is 1 // Partition stage - int mid = (left + right) / 2; // Calculate midpoint + int mid = left + (right - left) / 2; // Calculate midpoint mergeSort(nums, left, mid); // Recursively process the left subarray mergeSort(nums, mid + 1, right); // Recursively process the right subarray // Merge stage @@ -186,7 +186,7 @@ The implementation of merge sort is shown in the following code. Note that the i if (left >= right) return; // Terminate recursion when subarray length is 1 // Partition stage - int mid = (left + right) / 2; // Calculate midpoint + int mid = left + (right - left) / 2; // Calculate midpoint mergeSort(nums, left, mid); // Recursively process the left subarray mergeSort(nums, mid + 1, right); // Recursively process the right subarray // Merge stage diff --git a/zh-Hant/docs/chapter_backtracking/backtracking_algorithm.md b/zh-Hant/docs/chapter_backtracking/backtracking_algorithm.md index 69e4f5b8b..385f69db4 100644 --- a/zh-Hant/docs/chapter_backtracking/backtracking_algorithm.md +++ b/zh-Hant/docs/chapter_backtracking/backtracking_algorithm.md @@ -220,7 +220,16 @@ comments: true === "Ruby" ```ruby title="preorder_traversal_i_compact.rb" - [class]{}-[func]{pre_order} + ### 前序走訪:例題一 ### + def pre_order(root) + return unless root + + # 記錄解 + $res << root if root.val == 7 + + pre_order(root.left) + pre_order(root.right) + end ``` === "Zig" @@ -522,7 +531,22 @@ comments: true === "Ruby" ```ruby title="preorder_traversal_ii_compact.rb" - [class]{}-[func]{pre_order} + ### 前序走訪:例題二 ### + def pre_order(root) + return unless root + + # 嘗試 + $path << root + + # 記錄解 + $res << $path.dup if root.val == 7 + + pre_order(root.left) + pre_order(root.right) + + # 回退 + $path.pop + end ``` === "Zig" @@ -866,7 +890,23 @@ comments: true === "Ruby" ```ruby title="preorder_traversal_iii_compact.rb" - [class]{}-[func]{pre_order} + ### 前序走訪:例題三 ### + def pre_order(root) + # 剪枝 + return if !root || root.val == 3 + + # 嘗試 + $path.append(root) + + # 記錄解 + $res << $path.dup if root.val == 7 + + pre_order(root.left) + pre_order(root.right) + + # 回退 + $path.pop + end ``` === "Zig" @@ -1203,7 +1243,27 @@ comments: true === "Ruby" ```ruby title="" + ### 回溯演算法框架 ### + def backtrack(state, choices, res) + # 判斷是否為解 + if is_solution?(state) + # 記錄解 + record_solution(state, res) + return + end + # 走訪所有選擇 + for choice in choices + # 剪枝:判斷選擇是否合法 + if is_valid?(state, choice) + # 嘗試:做出選擇,更新狀態 + make_choice(state, choice) + backtrack(state, choices, res) + # 回退:撤銷選擇,恢復到之前的狀態 + undo_choice(state, choice) + end + end + end ``` === "Zig" @@ -1843,17 +1903,49 @@ comments: true === "Ruby" ```ruby title="preorder_traversal_iii_template.rb" - [class]{}-[func]{is_solution} - - [class]{}-[func]{record_solution} - - [class]{}-[func]{is_valid} - - [class]{}-[func]{make_choice} - - [class]{}-[func]{undo_choice} - - [class]{}-[func]{backtrack} + ### 判斷當前狀態是否為解 ### + def is_solution?(state) + !state.empty? && state.last.val == 7 + end + + ### 記錄解 ### + def record_solution(state, res) + res << state.dup + end + + ### 判斷在當前狀態下,該選擇是否合法 ### + def is_valid?(state, choice) + choice && choice.val != 3 + end + + ### 更新狀態 ### + def make_choice(state, choice) + state << choice + end + + ### 恢復狀態 ### + def undo_choice(state, choice) + state.pop + end + + ### 回溯演算法:例題三 ### + def backtrack(state, choices, res) + # 檢查是否為解 + record_solution(state, res) if is_solution?(state) + + # 走訪所有選擇 + for choice in choices + # 剪枝:檢查選擇是否合法 + if is_valid?(state, choice) + # 嘗試:做出選擇,更新狀態 + make_choice(state, choice) + # 進行下一輪選擇 + backtrack(state, [choice.left, choice.right], res) + # 回退:撤銷選擇,恢復到之前的狀態 + undo_choice(state, choice) + end + end + end ``` === "Zig" diff --git a/zh-Hant/docs/chapter_backtracking/n_queens_problem.md b/zh-Hant/docs/chapter_backtracking/n_queens_problem.md index 566f4e3ad..4f15d689d 100644 --- a/zh-Hant/docs/chapter_backtracking/n_queens_problem.md +++ b/zh-Hant/docs/chapter_backtracking/n_queens_problem.md @@ -710,9 +710,45 @@ comments: true === "Ruby" ```ruby title="n_queens.rb" - [class]{}-[func]{backtrack} - - [class]{}-[func]{n_queens} + ### 回溯演算法:n 皇后 ### + def backtrack(row, n, state, res, cols, diags1, diags2) + # 當放置完所有行時,記錄解 + if row == n + res << state.map { |row| row.dup } + return + end + + # 走訪所有列 + for col in 0...n + # 計算該格子對應的主對角線和次對角線 + diag1 = row - col + n - 1 + diag2 = row + col + # 剪枝:不允許該格子所在列、主對角線、次對角線上存在皇后 + if !cols[col] && !diags1[diag1] && !diags2[diag2] + # 嘗試:將皇后放置在該格子 + state[row][col] = "Q" + cols[col] = diags1[diag1] = diags2[diag2] = true + # 放置下一行 + backtrack(row + 1, n, state, res, cols, diags1, diags2) + # 回退:將該格子恢復為空位 + state[row][col] = "#" + cols[col] = diags1[diag1] = diags2[diag2] = false + end + end + end + + ### 求解 n 皇后 ### + def n_queens(n) + # 初始化 n*n 大小的棋盤,其中 'Q' 代表皇后,'#' 代表空位 + state = Array.new(n) { Array.new(n, "#") } + cols = Array.new(n, false) # 記錄列是否有皇后 + diags1 = Array.new(2 * n - 1, false) # 記錄主對角線上是否有皇后 + diags2 = Array.new(2 * n - 1, false) # 記錄次對角線上是否有皇后 + res = [] + backtrack(0, n, state, res, cols, diags1, diags2) + + res + end ``` === "Zig" diff --git a/zh-Hant/docs/chapter_backtracking/permutations_problem.md b/zh-Hant/docs/chapter_backtracking/permutations_problem.md index ddb3a6459..c33ab0cfb 100644 --- a/zh-Hant/docs/chapter_backtracking/permutations_problem.md +++ b/zh-Hant/docs/chapter_backtracking/permutations_problem.md @@ -506,9 +506,36 @@ comments: true === "Ruby" ```ruby title="permutations_i.rb" - [class]{}-[func]{backtrack} - - [class]{}-[func]{permutations_i} + ### 回溯演算法:全排列 I ### + def backtrack(state, choices, selected, res) + # 當狀態長度等於元素數量時,記錄解 + if state.length == choices.length + res << state.dup + return + end + + # 走訪所有選擇 + choices.each_with_index do |choice, i| + # 剪枝:不允許重複選擇元素 + unless selected[i] + # 嘗試:做出選擇,更新狀態 + selected[i] = true + state << choice + # 進行下一輪選擇 + backtrack(state, choices, selected, res) + # 回退:撤銷選擇,恢復到之前的狀態 + selected[i] = false + state.pop + end + end + end + + ### 全排列 I ### + def permutations_i(nums) + res = [] + backtrack([], nums, Array.new(nums.length, false), res) + res + end ``` === "Zig" @@ -1032,9 +1059,38 @@ comments: true === "Ruby" ```ruby title="permutations_ii.rb" - [class]{}-[func]{backtrack} - - [class]{}-[func]{permutations_ii} + ### 回溯演算法:全排列 II ### + def backtrack(state, choices, selected, res) + # 當狀態長度等於元素數量時,記錄解 + if state.length == choices.length + res << state.dup + return + end + + # 走訪所有選擇 + duplicated = Set.new + choices.each_with_index do |choice, i| + # 剪枝:不允許重複選擇元素 且 不允許重複選擇相等元素 + if !selected[i] && !duplicated.include?(choice) + # 嘗試:做出選擇,更新狀態 + duplicated.add(choice) + selected[i] = true + state << choice + # 進行下一輪選擇 + backtrack(state, choices, selected, res) + # 回退:撤銷選擇,恢復到之前的狀態 + selected[i] = false + state.pop + end + end + end + + ### 全排列 II ### + def permutations_ii(nums) + res = [] + backtrack([], nums, Array.new(nums.length, false), res) + res + end ``` === "Zig" diff --git a/zh-Hant/docs/chapter_backtracking/subset_sum_problem.md b/zh-Hant/docs/chapter_backtracking/subset_sum_problem.md index 2aa5218d8..c6c8293be 100644 --- a/zh-Hant/docs/chapter_backtracking/subset_sum_problem.md +++ b/zh-Hant/docs/chapter_backtracking/subset_sum_problem.md @@ -470,9 +470,35 @@ comments: true === "Ruby" ```ruby title="subset_sum_i_naive.rb" - [class]{}-[func]{backtrack} - - [class]{}-[func]{subset_sum_i_naive} + ### 回溯演算法:子集和 I ### + def backtrack(state, target, total, choices, res) + # 子集和等於 target 時,記錄解 + if total == target + res << state.dup + return + end + + # 走訪所有選擇 + for i in 0...choices.length + # 剪枝:若子集和超過 target ,則跳過該選擇 + next if total + choices[i] > target + # 嘗試:做出選擇,更新元素和 total + state << choices[i] + # 進行下一輪選擇 + backtrack(state, target, total + choices[i], choices, res) + # 回退:撤銷選擇,恢復到之前的狀態 + state.pop + end + end + + ### 求解子集和 I(包含重複子集)### + def subset_sum_i_naive(nums, target) + state = [] # 狀態(子集) + total = 0 # 子集和 + res = [] # 結果串列(子集串列) + backtrack(state, target, total, nums, res) + res + end ``` === "Zig" @@ -1011,9 +1037,37 @@ comments: true === "Ruby" ```ruby title="subset_sum_i.rb" - [class]{}-[func]{backtrack} - - [class]{}-[func]{subset_sum_i} + ### 回溯演算法:子集和 I ### + def backtrack(state, target, choices, start, res) + # 子集和等於 target 時,記錄解 + if target.zero? + res << state.dup + return + end + # 走訪所有選擇 + # 剪枝二:從 start 開始走訪,避免生成重複子集 + for i in start...choices.length + # 剪枝一:若子集和超過 target ,則直接結束迴圈 + # 這是因為陣列已排序,後邊元素更大,子集和一定超過 target + break if target - choices[i] < 0 + # 嘗試:做出選擇,更新 target, start + state << choices[i] + # 進行下一輪選擇 + backtrack(state, target - choices[i], choices, i, res) + # 回退:撤銷選擇,恢復到之前的狀態 + state.pop + end + end + + ### 求解子集和 I ### + def subset_sum_i(nums, target) + state = [] # 狀態(子集) + nums.sort! # 對 nums 進行排序 + start = 0 # 走訪起始點 + res = [] # 結果串列(子集串列) + backtrack(state, target, nums, start, res) + res + end ``` === "Zig" @@ -1598,9 +1652,41 @@ comments: true === "Ruby" ```ruby title="subset_sum_ii.rb" - [class]{}-[func]{backtrack} - - [class]{}-[func]{subset_sum_ii} + ### 回溯演算法:子集和 II ### + def backtrack(state, target, choices, start, res) + # 子集和等於 target 時,記錄解 + if target.zero? + res << state.dup + return + end + + # 走訪所有選擇 + # 剪枝二:從 start 開始走訪,避免生成重複子集 + # 剪枝三:從 start 開始走訪,避免重複選擇同一元素 + for i in start...choices.length + # 剪枝一:若子集和超過 target ,則直接結束迴圈 + # 這是因為陣列已排序,後邊元素更大,子集和一定超過 target + break if target - choices[i] < 0 + # 剪枝四:如果該元素與左邊元素相等,說明該搜尋分支重複,直接跳過 + next if i > start && choices[i] == choices[i - 1] + # 嘗試:做出選擇,更新 target, start + state << choices[i] + # 進行下一輪選擇 + backtrack(state, target - choices[i], choices, i + 1, res) + # 回退:撤銷選擇,恢復到之前的狀態 + state.pop + end + end + + ### 求解子集和 II ### + def subset_sum_ii(nums, target) + state = [] # 狀態(子集) + nums.sort! # 對 nums 進行排序 + start = 0 # 走訪起始點 + res = [] # 結果串列(子集串列) + backtrack(state, target, nums, start, res) + res + end ``` === "Zig" diff --git a/zh-Hant/docs/chapter_divide_and_conquer/binary_search_recur.md b/zh-Hant/docs/chapter_divide_and_conquer/binary_search_recur.md index f417cdf2f..256f86cfc 100644 --- a/zh-Hant/docs/chapter_divide_and_conquer/binary_search_recur.md +++ b/zh-Hant/docs/chapter_divide_and_conquer/binary_search_recur.md @@ -331,7 +331,7 @@ comments: true if i > j { return -1; } - let m: i32 = (i + j) / 2; + let m: i32 = i + (j - i) / 2; if nums[m as usize] < target { // 遞迴子問題 f(m+1, j) return dfs(nums, target, m + 1, j); diff --git a/zh-Hant/docs/chapter_hashing/hash_collision.md b/zh-Hant/docs/chapter_hashing/hash_collision.md index 4e37beeda..92e8028a5 100644 --- a/zh-Hant/docs/chapter_hashing/hash_collision.md +++ b/zh-Hant/docs/chapter_hashing/hash_collision.md @@ -2896,7 +2896,7 @@ comments: true hashMap->capacity = 4; hashMap->loadThres = 2.0 / 3.0; hashMap->extendRatio = 2; - hashMap->buckets = (Pair **)malloc(sizeof(Pair *) * hashMap->capacity); + hashMap->buckets = (Pair **)calloc(hashMap->capacity, sizeof(Pair *)); hashMap->TOMBSTONE = (Pair *)malloc(sizeof(Pair)); hashMap->TOMBSTONE->key = -1; hashMap->TOMBSTONE->val = "-1"; @@ -3015,7 +3015,7 @@ comments: true int oldCapacity = hashMap->capacity; // 初始化擴容後的新雜湊表 hashMap->capacity *= hashMap->extendRatio; - hashMap->buckets = (Pair **)malloc(sizeof(Pair *) * hashMap->capacity); + hashMap->buckets = (Pair **)calloc(hashMap->capacity, sizeof(Pair *)); hashMap->size = 0; // 將鍵值對從原雜湊表搬運至新雜湊表 for (int i = 0; i < oldCapacity; i++) { diff --git a/zh-Hant/docs/chapter_sorting/merge_sort.md b/zh-Hant/docs/chapter_sorting/merge_sort.md index 4ee6c2381..a74cbbbef 100755 --- a/zh-Hant/docs/chapter_sorting/merge_sort.md +++ b/zh-Hant/docs/chapter_sorting/merge_sort.md @@ -99,7 +99,7 @@ comments: true if left >= right: return # 當子陣列長度為 1 時終止遞迴 # 劃分階段 - mid = (left + right) // 2 # 計算中點 + mid = (left + right) // 2 # 計算中點 merge_sort(nums, left, mid) # 遞迴左子陣列 merge_sort(nums, mid + 1, right) # 遞迴右子陣列 # 合併階段 @@ -142,7 +142,7 @@ comments: true if (left >= right) return; // 當子陣列長度為 1 時終止遞迴 // 劃分階段 - int mid = (left + right) / 2; // 計算中點 + int mid = left + (right - left) / 2; // 計算中點 mergeSort(nums, left, mid); // 遞迴左子陣列 mergeSort(nums, mid + 1, right); // 遞迴右子陣列 // 合併階段 @@ -186,7 +186,7 @@ comments: true if (left >= right) return; // 當子陣列長度為 1 時終止遞迴 // 劃分階段 - int mid = (left + right) / 2; // 計算中點 + int mid = left + (right - left) / 2; // 計算中點 mergeSort(nums, left, mid); // 遞迴左子陣列 mergeSort(nums, mid + 1, right); // 遞迴右子陣列 // 合併階段 @@ -229,7 +229,7 @@ comments: true // 終止條件 if (left >= right) return; // 當子陣列長度為 1 時終止遞迴 // 劃分階段 - int mid = (left + right) / 2; // 計算中點 + int mid = left + (right - left) / 2; // 計算中點 MergeSort(nums, left, mid); // 遞迴左子陣列 MergeSort(nums, mid + 1, right); // 遞迴右子陣列 // 合併階段 @@ -282,7 +282,7 @@ comments: true return } // 劃分階段 - mid := (left + right) / 2 + mid := left + (right - left) / 2 mergeSort(nums, left, mid) mergeSort(nums, mid+1, right) // 合併階段 @@ -335,7 +335,7 @@ comments: true return } // 劃分階段 - let mid = (left + right) / 2 // 計算中點 + let mid = left + (right - left) / 2 // 計算中點 mergeSort(nums: &nums, left: left, right: mid) // 遞迴左子陣列 mergeSort(nums: &nums, left: mid + 1, right: right) // 遞迴右子陣列 // 合併階段 @@ -381,7 +381,7 @@ comments: true // 終止條件 if (left >= right) return; // 當子陣列長度為 1 時終止遞迴 // 劃分階段 - let mid = Math.floor((left + right) / 2); // 計算中點 + let mid = Math.floor(left + (right - left) / 2); // 計算中點 mergeSort(nums, left, mid); // 遞迴左子陣列 mergeSort(nums, mid + 1, right); // 遞迴右子陣列 // 合併階段 @@ -427,7 +427,7 @@ comments: true // 終止條件 if (left >= right) return; // 當子陣列長度為 1 時終止遞迴 // 劃分階段 - let mid = Math.floor((left + right) / 2); // 計算中點 + let mid = Math.floor(left + (right - left) / 2); // 計算中點 mergeSort(nums, left, mid); // 遞迴左子陣列 mergeSort(nums, mid + 1, right); // 遞迴右子陣列 // 合併階段 @@ -470,7 +470,7 @@ comments: true // 終止條件 if (left >= right) return; // 當子陣列長度為 1 時終止遞迴 // 劃分階段 - int mid = (left + right) ~/ 2; // 計算中點 + int mid = left + (right - left) ~/ 2; // 計算中點 mergeSort(nums, left, mid); // 遞迴左子陣列 mergeSort(nums, mid + 1, right); // 遞迴右子陣列 // 合併階段 @@ -525,7 +525,7 @@ comments: true } // 劃分階段 - let mid = (left + right) / 2; // 計算中點 + let mid = left + (right - left) / 2; // 計算中點 merge_sort(nums, left, mid); // 遞迴左子陣列 merge_sort(nums, mid + 1, right); // 遞迴右子陣列 @@ -574,7 +574,7 @@ comments: true if (left >= right) return; // 當子陣列長度為 1 時終止遞迴 // 劃分階段 - int mid = (left + right) / 2; // 計算中點 + int mid = left + (right - left) / 2; // 計算中點 mergeSort(nums, left, mid); // 遞迴左子陣列 mergeSort(nums, mid + 1, right); // 遞迴右子陣列 // 合併階段 @@ -598,7 +598,7 @@ comments: true while (i <= mid && j <= right) { if (nums[i] <= nums[j]) tmp[k++] = nums[i++] - else + else tmp[k++] = nums[j++] } // 將左子陣列和右子陣列的剩餘元素複製到臨時陣列中 @@ -619,7 +619,7 @@ comments: true // 終止條件 if (left >= right) return // 當子陣列長度為 1 時終止遞迴 // 劃分階段 - val mid = (left + right) / 2 // 計算中點 + val mid = left + (right - left) / 2 // 計算中點 mergeSort(nums, left, mid) // 遞迴左子陣列 mergeSort(nums, mid + 1, right) // 遞迴右子陣列 // 合併階段 @@ -671,7 +671,7 @@ comments: true # 當子陣列長度為 1 時終止遞迴 return if left >= right # 劃分階段 - mid = (left + right) / 2 # 計算中點 + mid = left + (right - left) / 2 # 計算中點 merge_sort(nums, left, mid) # 遞迴左子陣列 merge_sort(nums, mid + 1, right) # 遞迴右子陣列 # 合併階段 @@ -692,10 +692,10 @@ comments: true const mem_allocator = mem_arena.allocator(); var tmp = try mem_allocator.alloc(i32, right + 1 - left); std.mem.copy(i32, tmp, nums[left..right+1]); - // 左子陣列的起始索引和結束索引 + // 左子陣列的起始索引和結束索引 var leftStart = left - left; var leftEnd = mid - left; - // 右子陣列的起始索引和結束索引 + // 右子陣列的起始索引和結束索引 var rightStart = mid + 1 - left; var rightEnd = right - left; // i, j 分別指向左子陣列、右子陣列的首元素 @@ -725,7 +725,7 @@ comments: true // 終止條件 if (left >= right) return; // 當子陣列長度為 1 時終止遞迴 // 劃分階段 - var mid = (left + right) / 2; // 計算中點 + var mid = left + (right - left) / 2; // 計算中點 try mergeSort(nums, left, mid); // 遞迴左子陣列 try mergeSort(nums, mid + 1, right); // 遞迴右子陣列 // 合併階段 diff --git a/zh-Hant/docs/chapter_sorting/quick_sort.md b/zh-Hant/docs/chapter_sorting/quick_sort.md index d6f964735..f9f456b94 100755 --- a/zh-Hant/docs/chapter_sorting/quick_sort.md +++ b/zh-Hant/docs/chapter_sorting/quick_sort.md @@ -861,7 +861,7 @@ comments: true /* 哨兵劃分(三數取中值) */ func partitionMedian(nums: inout [Int], left: Int, right: Int) -> Int { // 選取三個候選元素的中位數 - let med = medianThree(nums: nums, left: left, mid: (left + right) / 2, right: right) + let med = medianThree(nums: nums, left: left, mid: left + (right - left) / 2, right: right) // 將中位數交換至陣列最左端 nums.swapAt(left, med) return partition(nums: &nums, left: left, right: right) diff --git a/zh-Hant/docs/chapter_sorting/radix_sort.md b/zh-Hant/docs/chapter_sorting/radix_sort.md index 9698590c3..9cd0377bd 100644 --- a/zh-Hant/docs/chapter_sorting/radix_sort.md +++ b/zh-Hant/docs/chapter_sorting/radix_sort.md @@ -545,9 +545,7 @@ $$ counter[d] -= 1; // 將 d 的數量減 1 } // 使用結果覆蓋原陣列 nums - for i in 0..n { - nums[i] = res[i]; - } + nums.copy_from_slice(&res); } /* 基數排序 */