krahets 6 months ago
parent e434a3343c
commit 6bac0db1c4

@ -220,7 +220,16 @@ comments: true
=== "Ruby" === "Ruby"
```ruby title="preorder_traversal_i_compact.rb" ```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" === "Zig"
@ -522,7 +531,22 @@ comments: true
=== "Ruby" === "Ruby"
```ruby title="preorder_traversal_ii_compact.rb" ```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" === "Zig"
@ -866,7 +890,23 @@ comments: true
=== "Ruby" === "Ruby"
```ruby title="preorder_traversal_iii_compact.rb" ```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" === "Zig"
@ -1203,7 +1243,27 @@ comments: true
=== "Ruby" === "Ruby"
```ruby title="" ```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" === "Zig"
@ -1843,17 +1903,49 @@ comments: true
=== "Ruby" === "Ruby"
```ruby title="preorder_traversal_iii_template.rb" ```ruby title="preorder_traversal_iii_template.rb"
[class]{}-[func]{is_solution} ### 判断当前状态是否为解 ###
def is_solution?(state)
[class]{}-[func]{record_solution} !state.empty? && state.last.val == 7
end
[class]{}-[func]{is_valid}
### 记录解 ###
[class]{}-[func]{make_choice} def record_solution(state, res)
res << state.dup
[class]{}-[func]{undo_choice} end
[class]{}-[func]{backtrack} ### 判断在当前状态下,该选择是否合法 ###
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" === "Zig"

@ -710,9 +710,45 @@ comments: true
=== "Ruby" === "Ruby"
```ruby title="n_queens.rb" ```ruby title="n_queens.rb"
[class]{}-[func]{backtrack} ### 回溯算法n 皇后 ###
def backtrack(row, n, state, res, cols, diags1, diags2)
[class]{}-[func]{n_queens} # 当放置完所有行时,记录解
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" === "Zig"

@ -506,9 +506,36 @@ comments: true
=== "Ruby" === "Ruby"
```ruby title="permutations_i.rb" ```ruby title="permutations_i.rb"
[class]{}-[func]{backtrack} ### 回溯算法:全排列 I ###
def backtrack(state, choices, selected, res)
[class]{}-[func]{permutations_i} # 当状态长度等于元素数量时,记录解
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" === "Zig"
@ -1032,9 +1059,38 @@ comments: true
=== "Ruby" === "Ruby"
```ruby title="permutations_ii.rb" ```ruby title="permutations_ii.rb"
[class]{}-[func]{backtrack} ### 回溯算法:全排列 II ###
def backtrack(state, choices, selected, res)
[class]{}-[func]{permutations_ii} # 当状态长度等于元素数量时,记录解
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" === "Zig"

@ -470,9 +470,35 @@ comments: true
=== "Ruby" === "Ruby"
```ruby title="subset_sum_i_naive.rb" ```ruby title="subset_sum_i_naive.rb"
[class]{}-[func]{backtrack} ### 回溯算法:子集和 I ###
def backtrack(state, target, total, choices, res)
[class]{}-[func]{subset_sum_i_naive} # 子集和等于 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" === "Zig"
@ -1011,9 +1037,37 @@ comments: true
=== "Ruby" === "Ruby"
```ruby title="subset_sum_i.rb" ```ruby title="subset_sum_i.rb"
[class]{}-[func]{backtrack} ### 回溯算法:子集和 I ###
def backtrack(state, target, choices, start, res)
[class]{}-[func]{subset_sum_i} # 子集和等于 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" === "Zig"
@ -1598,9 +1652,41 @@ comments: true
=== "Ruby" === "Ruby"
```ruby title="subset_sum_ii.rb" ```ruby title="subset_sum_ii.rb"
[class]{}-[func]{backtrack} ### 回溯算法:子集和 II ###
def backtrack(state, target, choices, start, res)
[class]{}-[func]{subset_sum_ii} # 子集和等于 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" === "Zig"

@ -331,7 +331,7 @@ comments: true
if i > j { if i > j {
return -1; return -1;
} }
let m: i32 = (i + j) / 2; let m: i32 = i + (j - i) / 2;
if nums[m as usize] < target { if nums[m as usize] < target {
// 递归子问题 f(m+1, j) // 递归子问题 f(m+1, j)
return dfs(nums, target, m + 1, j); return dfs(nums, target, m + 1, j);

@ -2896,7 +2896,7 @@ comments: true
hashMap->capacity = 4; hashMap->capacity = 4;
hashMap->loadThres = 2.0 / 3.0; hashMap->loadThres = 2.0 / 3.0;
hashMap->extendRatio = 2; 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 = (Pair *)malloc(sizeof(Pair));
hashMap->TOMBSTONE->key = -1; hashMap->TOMBSTONE->key = -1;
hashMap->TOMBSTONE->val = "-1"; hashMap->TOMBSTONE->val = "-1";
@ -3015,7 +3015,7 @@ comments: true
int oldCapacity = hashMap->capacity; int oldCapacity = hashMap->capacity;
// 初始化扩容后的新哈希表 // 初始化扩容后的新哈希表
hashMap->capacity *= hashMap->extendRatio; hashMap->capacity *= hashMap->extendRatio;
hashMap->buckets = (Pair **)malloc(sizeof(Pair *) * hashMap->capacity); hashMap->buckets = (Pair **)calloc(hashMap->capacity, sizeof(Pair *));
hashMap->size = 0; hashMap->size = 0;
// 将键值对从原哈希表搬运至新哈希表 // 将键值对从原哈希表搬运至新哈希表
for (int i = 0; i < oldCapacity; i++) { for (int i = 0; i < oldCapacity; i++) {

@ -99,7 +99,7 @@ comments: true
if left >= right: if left >= right:
return # 当子数组长度为 1 时终止递归 return # 当子数组长度为 1 时终止递归
# 划分阶段 # 划分阶段
mid = (left + right) // 2 # 计算中点 mid = (left + right) // 2 # 计算中点
merge_sort(nums, left, mid) # 递归左子数组 merge_sort(nums, left, mid) # 递归左子数组
merge_sort(nums, mid + 1, right) # 递归右子数组 merge_sort(nums, mid + 1, right) # 递归右子数组
# 合并阶段 # 合并阶段
@ -142,7 +142,7 @@ comments: true
if (left >= right) if (left >= right)
return; // 当子数组长度为 1 时终止递归 return; // 当子数组长度为 1 时终止递归
// 划分阶段 // 划分阶段
int mid = (left + right) / 2; // 计算中点 int mid = left + (right - left) / 2; // 计算中点
mergeSort(nums, left, mid); // 递归左子数组 mergeSort(nums, left, mid); // 递归左子数组
mergeSort(nums, mid + 1, right); // 递归右子数组 mergeSort(nums, mid + 1, right); // 递归右子数组
// 合并阶段 // 合并阶段
@ -186,7 +186,7 @@ comments: true
if (left >= right) if (left >= right)
return; // 当子数组长度为 1 时终止递归 return; // 当子数组长度为 1 时终止递归
// 划分阶段 // 划分阶段
int mid = (left + right) / 2; // 计算中点 int mid = left + (right - left) / 2; // 计算中点
mergeSort(nums, left, mid); // 递归左子数组 mergeSort(nums, left, mid); // 递归左子数组
mergeSort(nums, mid + 1, right); // 递归右子数组 mergeSort(nums, mid + 1, right); // 递归右子数组
// 合并阶段 // 合并阶段
@ -229,7 +229,7 @@ comments: true
// 终止条件 // 终止条件
if (left >= right) return; // 当子数组长度为 1 时终止递归 if (left >= right) return; // 当子数组长度为 1 时终止递归
// 划分阶段 // 划分阶段
int mid = (left + right) / 2; // 计算中点 int mid = left + (right - left) / 2; // 计算中点
MergeSort(nums, left, mid); // 递归左子数组 MergeSort(nums, left, mid); // 递归左子数组
MergeSort(nums, mid + 1, right); // 递归右子数组 MergeSort(nums, mid + 1, right); // 递归右子数组
// 合并阶段 // 合并阶段
@ -282,7 +282,7 @@ comments: true
return return
} }
// 划分阶段 // 划分阶段
mid := (left + right) / 2 mid := left + (right - left) / 2
mergeSort(nums, left, mid) mergeSort(nums, left, mid)
mergeSort(nums, mid+1, right) mergeSort(nums, mid+1, right)
// 合并阶段 // 合并阶段
@ -335,7 +335,7 @@ comments: true
return return
} }
// 划分阶段 // 划分阶段
let mid = (left + right) / 2 // 计算中点 let mid = left + (right - left) / 2 // 计算中点
mergeSort(nums: &nums, left: left, right: mid) // 递归左子数组 mergeSort(nums: &nums, left: left, right: mid) // 递归左子数组
mergeSort(nums: &nums, left: mid + 1, right: right) // 递归右子数组 mergeSort(nums: &nums, left: mid + 1, right: right) // 递归右子数组
// 合并阶段 // 合并阶段
@ -381,7 +381,7 @@ comments: true
// 终止条件 // 终止条件
if (left >= right) return; // 当子数组长度为 1 时终止递归 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, left, mid); // 递归左子数组
mergeSort(nums, mid + 1, right); // 递归右子数组 mergeSort(nums, mid + 1, right); // 递归右子数组
// 合并阶段 // 合并阶段
@ -427,7 +427,7 @@ comments: true
// 终止条件 // 终止条件
if (left >= right) return; // 当子数组长度为 1 时终止递归 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, left, mid); // 递归左子数组
mergeSort(nums, mid + 1, right); // 递归右子数组 mergeSort(nums, mid + 1, right); // 递归右子数组
// 合并阶段 // 合并阶段
@ -470,7 +470,7 @@ comments: true
// 终止条件 // 终止条件
if (left >= right) return; // 当子数组长度为 1 时终止递归 if (left >= right) return; // 当子数组长度为 1 时终止递归
// 划分阶段 // 划分阶段
int mid = (left + right) ~/ 2; // 计算中点 int mid = left + (right - left) ~/ 2; // 计算中点
mergeSort(nums, left, mid); // 递归左子数组 mergeSort(nums, left, mid); // 递归左子数组
mergeSort(nums, mid + 1, right); // 递归右子数组 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, left, mid); // 递归左子数组
merge_sort(nums, mid + 1, right); // 递归右子数组 merge_sort(nums, mid + 1, right); // 递归右子数组
@ -574,7 +574,7 @@ comments: true
if (left >= right) if (left >= right)
return; // 当子数组长度为 1 时终止递归 return; // 当子数组长度为 1 时终止递归
// 划分阶段 // 划分阶段
int mid = (left + right) / 2; // 计算中点 int mid = left + (right - left) / 2; // 计算中点
mergeSort(nums, left, mid); // 递归左子数组 mergeSort(nums, left, mid); // 递归左子数组
mergeSort(nums, mid + 1, right); // 递归右子数组 mergeSort(nums, mid + 1, right); // 递归右子数组
// 合并阶段 // 合并阶段
@ -619,7 +619,7 @@ comments: true
// 终止条件 // 终止条件
if (left >= right) return // 当子数组长度为 1 时终止递归 if (left >= right) return // 当子数组长度为 1 时终止递归
// 划分阶段 // 划分阶段
val mid = (left + right) / 2 // 计算中点 val mid = left + (right - left) / 2 // 计算中点
mergeSort(nums, left, mid) // 递归左子数组 mergeSort(nums, left, mid) // 递归左子数组
mergeSort(nums, mid + 1, right) // 递归右子数组 mergeSort(nums, mid + 1, right) // 递归右子数组
// 合并阶段 // 合并阶段
@ -671,7 +671,7 @@ comments: true
# 当子数组长度为 1 时终止递归 # 当子数组长度为 1 时终止递归
return if left >= right return if left >= right
# 划分阶段 # 划分阶段
mid = (left + right) / 2 # 计算中点 mid = left + (right - left) / 2 # 计算中点
merge_sort(nums, left, mid) # 递归左子数组 merge_sort(nums, left, mid) # 递归左子数组
merge_sort(nums, mid + 1, right) # 递归右子数组 merge_sort(nums, mid + 1, right) # 递归右子数组
# 合并阶段 # 合并阶段
@ -725,7 +725,7 @@ comments: true
// 终止条件 // 终止条件
if (left >= right) return; // 当子数组长度为 1 时终止递归 if (left >= right) return; // 当子数组长度为 1 时终止递归
// 划分阶段 // 划分阶段
var mid = (left + right) / 2; // 计算中点 var mid = left + (right - left) / 2; // 计算中点
try mergeSort(nums, left, mid); // 递归左子数组 try mergeSort(nums, left, mid); // 递归左子数组
try mergeSort(nums, mid + 1, right); // 递归右子数组 try mergeSort(nums, mid + 1, right); // 递归右子数组
// 合并阶段 // 合并阶段

@ -861,7 +861,7 @@ comments: true
/* 哨兵划分(三数取中值) */ /* 哨兵划分(三数取中值) */
func partitionMedian(nums: inout [Int], left: Int, right: Int) -> Int { 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) nums.swapAt(left, med)
return partition(nums: &nums, left: left, right: right) return partition(nums: &nums, left: left, right: right)

@ -545,9 +545,7 @@ $$
counter[d] -= 1; // 将 d 的数量减 1 counter[d] -= 1; // 将 d 的数量减 1
} }
// 使用结果覆盖原数组 nums // 使用结果覆盖原数组 nums
for i in 0..n { nums.copy_from_slice(&res);
nums[i] = res[i];
}
} }
/* 基数排序 */ /* 基数排序 */

@ -83,7 +83,7 @@ In the implementation code, we declare a recursive function `dfs()` to solve the
return -1; return -1;
} }
// Calculate midpoint index m // Calculate midpoint index m
int m = (i + j) / 2; int m = i + (j - i) / 2;
if (nums[m] < target) { if (nums[m] < target) {
// Recursive subproblem f(m+1, j) // Recursive subproblem f(m+1, j)
return dfs(nums, target, 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; return -1;
} }
// Calculate midpoint index m // Calculate midpoint index m
int m = (i + j) / 2; int m = i + (j - i) / 2;
if (nums[m] < target) { if (nums[m] < target) {
// Recursive subproblem f(m+1, j) // Recursive subproblem f(m+1, j)
return dfs(nums, target, m + 1, j); return dfs(nums, target, m + 1, j);

@ -63,7 +63,7 @@ The code is as follows:
# Loop until the search interval is empty (when i > j, it is empty) # Loop until the search interval is empty (when i > j, it is empty)
while i <= j: 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 # 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: if nums[m] < target:
i = m + 1 # This situation indicates that target is in the interval [m+1, j] i = m + 1 # This situation indicates that target is in the interval [m+1, j]
elif nums[m] > target: 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) i, j = 0, len(nums)
# Loop until the search interval is empty (when i = j, it is empty) # Loop until the search interval is empty (when i = j, it is empty)
while i < j: while i < j:
m = (i + j) // 2 # Calculate midpoint index m m = i + (j - i) // 2 # Calculate midpoint index m
if nums[m] < target: if nums[m] < target:
i = m + 1 # This situation indicates that target is in the interval [m+1, j) i = m + 1 # This situation indicates that target is in the interval [m+1, j)
elif nums[m] > target: elif nums[m] > target:

@ -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)""" """Binary search for insertion point (no duplicate elements)"""
i, j = 0, len(nums) - 1 # Initialize double closed interval [0, n-1] i, j = 0, len(nums) - 1 # Initialize double closed interval [0, n-1]
while i <= j: while i <= j:
m = (i + j) // 2 # Calculate midpoint index m m = i + (j - i) // 2 # Calculate midpoint index m
if nums[m] < target: if nums[m] < target:
i = m + 1 # Target is in interval [m+1, j] i = m + 1 # Target is in interval [m+1, j]
elif nums[m] > target: 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)""" """Binary search for insertion point (with duplicate elements)"""
i, j = 0, len(nums) - 1 # Initialize double closed interval [0, n-1] i, j = 0, len(nums) - 1 # Initialize double closed interval [0, n-1]
while i <= j: while i <= j:
m = (i + j) // 2 # Calculate midpoint index m m = i + (j - i) // 2 # Calculate midpoint index m
if nums[m] < target: if nums[m] < target:
i = m + 1 # Target is in interval [m+1, j] i = m + 1 # Target is in interval [m+1, j]
elif nums[m] > target: elif nums[m] > target:

@ -99,7 +99,7 @@ The implementation of merge sort is shown in the following code. Note that the i
if left >= right: if left >= right:
return # Terminate recursion when subarray length is 1 return # Terminate recursion when subarray length is 1
# Partition stage # 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, left, mid) # Recursively process the left subarray
merge_sort(nums, mid + 1, right) # Recursively process the right subarray merge_sort(nums, mid + 1, right) # Recursively process the right subarray
# Merge stage # Merge stage
@ -142,7 +142,7 @@ The implementation of merge sort is shown in the following code. Note that the i
if (left >= right) if (left >= right)
return; // Terminate recursion when subarray length is 1 return; // Terminate recursion when subarray length is 1
// Partition stage // 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, left, mid); // Recursively process the left subarray
mergeSort(nums, mid + 1, right); // Recursively process the right subarray mergeSort(nums, mid + 1, right); // Recursively process the right subarray
// Merge stage // Merge stage
@ -186,7 +186,7 @@ The implementation of merge sort is shown in the following code. Note that the i
if (left >= right) if (left >= right)
return; // Terminate recursion when subarray length is 1 return; // Terminate recursion when subarray length is 1
// Partition stage // 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, left, mid); // Recursively process the left subarray
mergeSort(nums, mid + 1, right); // Recursively process the right subarray mergeSort(nums, mid + 1, right); // Recursively process the right subarray
// Merge stage // Merge stage

@ -220,7 +220,16 @@ comments: true
=== "Ruby" === "Ruby"
```ruby title="preorder_traversal_i_compact.rb" ```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" === "Zig"
@ -522,7 +531,22 @@ comments: true
=== "Ruby" === "Ruby"
```ruby title="preorder_traversal_ii_compact.rb" ```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" === "Zig"
@ -866,7 +890,23 @@ comments: true
=== "Ruby" === "Ruby"
```ruby title="preorder_traversal_iii_compact.rb" ```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" === "Zig"
@ -1203,7 +1243,27 @@ comments: true
=== "Ruby" === "Ruby"
```ruby title="" ```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" === "Zig"
@ -1843,17 +1903,49 @@ comments: true
=== "Ruby" === "Ruby"
```ruby title="preorder_traversal_iii_template.rb" ```ruby title="preorder_traversal_iii_template.rb"
[class]{}-[func]{is_solution} ### 判斷當前狀態是否為解 ###
def is_solution?(state)
[class]{}-[func]{record_solution} !state.empty? && state.last.val == 7
end
[class]{}-[func]{is_valid}
### 記錄解 ###
[class]{}-[func]{make_choice} def record_solution(state, res)
res << state.dup
[class]{}-[func]{undo_choice} end
[class]{}-[func]{backtrack} ### 判斷在當前狀態下,該選擇是否合法 ###
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" === "Zig"

@ -710,9 +710,45 @@ comments: true
=== "Ruby" === "Ruby"
```ruby title="n_queens.rb" ```ruby title="n_queens.rb"
[class]{}-[func]{backtrack} ### 回溯演算法n 皇后 ###
def backtrack(row, n, state, res, cols, diags1, diags2)
[class]{}-[func]{n_queens} # 當放置完所有行時,記錄解
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" === "Zig"

@ -506,9 +506,36 @@ comments: true
=== "Ruby" === "Ruby"
```ruby title="permutations_i.rb" ```ruby title="permutations_i.rb"
[class]{}-[func]{backtrack} ### 回溯演算法:全排列 I ###
def backtrack(state, choices, selected, res)
[class]{}-[func]{permutations_i} # 當狀態長度等於元素數量時,記錄解
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" === "Zig"
@ -1032,9 +1059,38 @@ comments: true
=== "Ruby" === "Ruby"
```ruby title="permutations_ii.rb" ```ruby title="permutations_ii.rb"
[class]{}-[func]{backtrack} ### 回溯演算法:全排列 II ###
def backtrack(state, choices, selected, res)
[class]{}-[func]{permutations_ii} # 當狀態長度等於元素數量時,記錄解
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" === "Zig"

@ -470,9 +470,35 @@ comments: true
=== "Ruby" === "Ruby"
```ruby title="subset_sum_i_naive.rb" ```ruby title="subset_sum_i_naive.rb"
[class]{}-[func]{backtrack} ### 回溯演算法:子集和 I ###
def backtrack(state, target, total, choices, res)
[class]{}-[func]{subset_sum_i_naive} # 子集和等於 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" === "Zig"
@ -1011,9 +1037,37 @@ comments: true
=== "Ruby" === "Ruby"
```ruby title="subset_sum_i.rb" ```ruby title="subset_sum_i.rb"
[class]{}-[func]{backtrack} ### 回溯演算法:子集和 I ###
def backtrack(state, target, choices, start, res)
[class]{}-[func]{subset_sum_i} # 子集和等於 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" === "Zig"
@ -1598,9 +1652,41 @@ comments: true
=== "Ruby" === "Ruby"
```ruby title="subset_sum_ii.rb" ```ruby title="subset_sum_ii.rb"
[class]{}-[func]{backtrack} ### 回溯演算法:子集和 II ###
def backtrack(state, target, choices, start, res)
[class]{}-[func]{subset_sum_ii} # 子集和等於 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" === "Zig"

@ -331,7 +331,7 @@ comments: true
if i > j { if i > j {
return -1; return -1;
} }
let m: i32 = (i + j) / 2; let m: i32 = i + (j - i) / 2;
if nums[m as usize] < target { if nums[m as usize] < target {
// 遞迴子問題 f(m+1, j) // 遞迴子問題 f(m+1, j)
return dfs(nums, target, m + 1, j); return dfs(nums, target, m + 1, j);

@ -2896,7 +2896,7 @@ comments: true
hashMap->capacity = 4; hashMap->capacity = 4;
hashMap->loadThres = 2.0 / 3.0; hashMap->loadThres = 2.0 / 3.0;
hashMap->extendRatio = 2; 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 = (Pair *)malloc(sizeof(Pair));
hashMap->TOMBSTONE->key = -1; hashMap->TOMBSTONE->key = -1;
hashMap->TOMBSTONE->val = "-1"; hashMap->TOMBSTONE->val = "-1";
@ -3015,7 +3015,7 @@ comments: true
int oldCapacity = hashMap->capacity; int oldCapacity = hashMap->capacity;
// 初始化擴容後的新雜湊表 // 初始化擴容後的新雜湊表
hashMap->capacity *= hashMap->extendRatio; hashMap->capacity *= hashMap->extendRatio;
hashMap->buckets = (Pair **)malloc(sizeof(Pair *) * hashMap->capacity); hashMap->buckets = (Pair **)calloc(hashMap->capacity, sizeof(Pair *));
hashMap->size = 0; hashMap->size = 0;
// 將鍵值對從原雜湊表搬運至新雜湊表 // 將鍵值對從原雜湊表搬運至新雜湊表
for (int i = 0; i < oldCapacity; i++) { for (int i = 0; i < oldCapacity; i++) {

@ -99,7 +99,7 @@ comments: true
if left >= right: if left >= right:
return # 當子陣列長度為 1 時終止遞迴 return # 當子陣列長度為 1 時終止遞迴
# 劃分階段 # 劃分階段
mid = (left + right) // 2 # 計算中點 mid = (left + right) // 2 # 計算中點
merge_sort(nums, left, mid) # 遞迴左子陣列 merge_sort(nums, left, mid) # 遞迴左子陣列
merge_sort(nums, mid + 1, right) # 遞迴右子陣列 merge_sort(nums, mid + 1, right) # 遞迴右子陣列
# 合併階段 # 合併階段
@ -142,7 +142,7 @@ comments: true
if (left >= right) if (left >= right)
return; // 當子陣列長度為 1 時終止遞迴 return; // 當子陣列長度為 1 時終止遞迴
// 劃分階段 // 劃分階段
int mid = (left + right) / 2; // 計算中點 int mid = left + (right - left) / 2; // 計算中點
mergeSort(nums, left, mid); // 遞迴左子陣列 mergeSort(nums, left, mid); // 遞迴左子陣列
mergeSort(nums, mid + 1, right); // 遞迴右子陣列 mergeSort(nums, mid + 1, right); // 遞迴右子陣列
// 合併階段 // 合併階段
@ -186,7 +186,7 @@ comments: true
if (left >= right) if (left >= right)
return; // 當子陣列長度為 1 時終止遞迴 return; // 當子陣列長度為 1 時終止遞迴
// 劃分階段 // 劃分階段
int mid = (left + right) / 2; // 計算中點 int mid = left + (right - left) / 2; // 計算中點
mergeSort(nums, left, mid); // 遞迴左子陣列 mergeSort(nums, left, mid); // 遞迴左子陣列
mergeSort(nums, mid + 1, right); // 遞迴右子陣列 mergeSort(nums, mid + 1, right); // 遞迴右子陣列
// 合併階段 // 合併階段
@ -229,7 +229,7 @@ comments: true
// 終止條件 // 終止條件
if (left >= right) return; // 當子陣列長度為 1 時終止遞迴 if (left >= right) return; // 當子陣列長度為 1 時終止遞迴
// 劃分階段 // 劃分階段
int mid = (left + right) / 2; // 計算中點 int mid = left + (right - left) / 2; // 計算中點
MergeSort(nums, left, mid); // 遞迴左子陣列 MergeSort(nums, left, mid); // 遞迴左子陣列
MergeSort(nums, mid + 1, right); // 遞迴右子陣列 MergeSort(nums, mid + 1, right); // 遞迴右子陣列
// 合併階段 // 合併階段
@ -282,7 +282,7 @@ comments: true
return return
} }
// 劃分階段 // 劃分階段
mid := (left + right) / 2 mid := left + (right - left) / 2
mergeSort(nums, left, mid) mergeSort(nums, left, mid)
mergeSort(nums, mid+1, right) mergeSort(nums, mid+1, right)
// 合併階段 // 合併階段
@ -335,7 +335,7 @@ comments: true
return return
} }
// 劃分階段 // 劃分階段
let mid = (left + right) / 2 // 計算中點 let mid = left + (right - left) / 2 // 計算中點
mergeSort(nums: &nums, left: left, right: mid) // 遞迴左子陣列 mergeSort(nums: &nums, left: left, right: mid) // 遞迴左子陣列
mergeSort(nums: &nums, left: mid + 1, right: right) // 遞迴右子陣列 mergeSort(nums: &nums, left: mid + 1, right: right) // 遞迴右子陣列
// 合併階段 // 合併階段
@ -381,7 +381,7 @@ comments: true
// 終止條件 // 終止條件
if (left >= right) return; // 當子陣列長度為 1 時終止遞迴 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, left, mid); // 遞迴左子陣列
mergeSort(nums, mid + 1, right); // 遞迴右子陣列 mergeSort(nums, mid + 1, right); // 遞迴右子陣列
// 合併階段 // 合併階段
@ -427,7 +427,7 @@ comments: true
// 終止條件 // 終止條件
if (left >= right) return; // 當子陣列長度為 1 時終止遞迴 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, left, mid); // 遞迴左子陣列
mergeSort(nums, mid + 1, right); // 遞迴右子陣列 mergeSort(nums, mid + 1, right); // 遞迴右子陣列
// 合併階段 // 合併階段
@ -470,7 +470,7 @@ comments: true
// 終止條件 // 終止條件
if (left >= right) return; // 當子陣列長度為 1 時終止遞迴 if (left >= right) return; // 當子陣列長度為 1 時終止遞迴
// 劃分階段 // 劃分階段
int mid = (left + right) ~/ 2; // 計算中點 int mid = left + (right - left) ~/ 2; // 計算中點
mergeSort(nums, left, mid); // 遞迴左子陣列 mergeSort(nums, left, mid); // 遞迴左子陣列
mergeSort(nums, mid + 1, right); // 遞迴右子陣列 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, left, mid); // 遞迴左子陣列
merge_sort(nums, mid + 1, right); // 遞迴右子陣列 merge_sort(nums, mid + 1, right); // 遞迴右子陣列
@ -574,7 +574,7 @@ comments: true
if (left >= right) if (left >= right)
return; // 當子陣列長度為 1 時終止遞迴 return; // 當子陣列長度為 1 時終止遞迴
// 劃分階段 // 劃分階段
int mid = (left + right) / 2; // 計算中點 int mid = left + (right - left) / 2; // 計算中點
mergeSort(nums, left, mid); // 遞迴左子陣列 mergeSort(nums, left, mid); // 遞迴左子陣列
mergeSort(nums, mid + 1, right); // 遞迴右子陣列 mergeSort(nums, mid + 1, right); // 遞迴右子陣列
// 合併階段 // 合併階段
@ -619,7 +619,7 @@ comments: true
// 終止條件 // 終止條件
if (left >= right) return // 當子陣列長度為 1 時終止遞迴 if (left >= right) return // 當子陣列長度為 1 時終止遞迴
// 劃分階段 // 劃分階段
val mid = (left + right) / 2 // 計算中點 val mid = left + (right - left) / 2 // 計算中點
mergeSort(nums, left, mid) // 遞迴左子陣列 mergeSort(nums, left, mid) // 遞迴左子陣列
mergeSort(nums, mid + 1, right) // 遞迴右子陣列 mergeSort(nums, mid + 1, right) // 遞迴右子陣列
// 合併階段 // 合併階段
@ -671,7 +671,7 @@ comments: true
# 當子陣列長度為 1 時終止遞迴 # 當子陣列長度為 1 時終止遞迴
return if left >= right return if left >= right
# 劃分階段 # 劃分階段
mid = (left + right) / 2 # 計算中點 mid = left + (right - left) / 2 # 計算中點
merge_sort(nums, left, mid) # 遞迴左子陣列 merge_sort(nums, left, mid) # 遞迴左子陣列
merge_sort(nums, mid + 1, right) # 遞迴右子陣列 merge_sort(nums, mid + 1, right) # 遞迴右子陣列
# 合併階段 # 合併階段
@ -725,7 +725,7 @@ comments: true
// 終止條件 // 終止條件
if (left >= right) return; // 當子陣列長度為 1 時終止遞迴 if (left >= right) return; // 當子陣列長度為 1 時終止遞迴
// 劃分階段 // 劃分階段
var mid = (left + right) / 2; // 計算中點 var mid = left + (right - left) / 2; // 計算中點
try mergeSort(nums, left, mid); // 遞迴左子陣列 try mergeSort(nums, left, mid); // 遞迴左子陣列
try mergeSort(nums, mid + 1, right); // 遞迴右子陣列 try mergeSort(nums, mid + 1, right); // 遞迴右子陣列
// 合併階段 // 合併階段

@ -861,7 +861,7 @@ comments: true
/* 哨兵劃分(三數取中值) */ /* 哨兵劃分(三數取中值) */
func partitionMedian(nums: inout [Int], left: Int, right: Int) -> Int { 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) nums.swapAt(left, med)
return partition(nums: &nums, left: left, right: right) return partition(nums: &nums, left: left, right: right)

@ -545,9 +545,7 @@ $$
counter[d] -= 1; // 將 d 的數量減 1 counter[d] -= 1; // 將 d 的數量減 1
} }
// 使用結果覆蓋原陣列 nums // 使用結果覆蓋原陣列 nums
for i in 0..n { nums.copy_from_slice(&res);
nums[i] = res[i];
}
} }
/* 基數排序 */ /* 基數排序 */

Loading…
Cancel
Save