From b6ac6aa7d79b4739bafafae5908807ece40c33a2 Mon Sep 17 00:00:00 2001 From: nuomi1 Date: Sat, 2 Sep 2023 23:08:37 +0800 Subject: [PATCH] Feature/chapter divide and conquer swift (#719) * feat: add Swift codes for binary_search_recur article * feat: add Swift codes for build_binary_tree_problem article * feat: add Swift codes for hanota_problem article --- codes/swift/Package.swift | 8 +++ .../binary_search_recur.swift | 45 ++++++++++++++ .../build_tree.swift | 47 +++++++++++++++ .../chapter_divide_and_conquer/hanota.swift | 58 +++++++++++++++++++ 4 files changed, 158 insertions(+) create mode 100644 codes/swift/chapter_divide_and_conquer/binary_search_recur.swift create mode 100644 codes/swift/chapter_divide_and_conquer/build_tree.swift create mode 100644 codes/swift/chapter_divide_and_conquer/hanota.swift diff --git a/codes/swift/Package.swift b/codes/swift/Package.swift index 18c0bc219..d6d8f5cf7 100644 --- a/codes/swift/Package.swift +++ b/codes/swift/Package.swift @@ -65,6 +65,10 @@ let package = Package( .executable(name: "bucket_sort", targets: ["bucket_sort"]), .executable(name: "counting_sort", targets: ["counting_sort"]), .executable(name: "radix_sort", targets: ["radix_sort"]), + // chapter_divide_and_conquer + .executable(name: "binary_search_recur", targets: ["binary_search_recur"]), + .executable(name: "build_tree", targets: ["build_tree"]), + .executable(name: "hanota", targets: ["hanota"]), // chapter_backtracking .executable(name: "preorder_traversal_i_compact", targets: ["preorder_traversal_i_compact"]), .executable(name: "preorder_traversal_ii_compact", targets: ["preorder_traversal_ii_compact"]), @@ -155,6 +159,10 @@ let package = Package( .executableTarget(name: "bucket_sort", path: "chapter_sorting", sources: ["bucket_sort.swift"]), .executableTarget(name: "counting_sort", path: "chapter_sorting", sources: ["counting_sort.swift"]), .executableTarget(name: "radix_sort", path: "chapter_sorting", sources: ["radix_sort.swift"]), + // chapter_divide_and_conquer + .executableTarget(name: "binary_search_recur", path: "chapter_divide_and_conquer", sources: ["binary_search_recur.swift"]), + .executableTarget(name: "build_tree", dependencies: ["utils"], path: "chapter_divide_and_conquer", sources: ["build_tree.swift"]), + .executableTarget(name: "hanota", path: "chapter_divide_and_conquer", sources: ["hanota.swift"]), // chapter_backtracking .executableTarget(name: "preorder_traversal_i_compact", dependencies: ["utils"], path: "chapter_backtracking", sources: ["preorder_traversal_i_compact.swift"]), .executableTarget(name: "preorder_traversal_ii_compact", dependencies: ["utils"], path: "chapter_backtracking", sources: ["preorder_traversal_ii_compact.swift"]), diff --git a/codes/swift/chapter_divide_and_conquer/binary_search_recur.swift b/codes/swift/chapter_divide_and_conquer/binary_search_recur.swift new file mode 100644 index 000000000..1128d378a --- /dev/null +++ b/codes/swift/chapter_divide_and_conquer/binary_search_recur.swift @@ -0,0 +1,45 @@ +/** + * File: binary_search_recur.swift + * Created Time: 2023-09-02 + * Author: nuomi1 (nuomi1@qq.com) + */ + +/* 二分查找:问题 f(i, j) */ +func dfs(nums: [Int], target: Int, i: Int, j: Int) -> Int { + // 若区间为空,代表无目标元素,则返回 -1 + if i > j { + return -1 + } + // 计算中点索引 m + let m = (i + j) / 2 + if nums[m] < target { + // 递归子问题 f(m+1, j) + return dfs(nums: nums, target: target, i: m + 1, j: j) + } else if nums[m] > target { + // 递归子问题 f(i, m-1) + return dfs(nums: nums, target: target, i: i, j: m - 1) + } else { + // 找到目标元素,返回其索引 + return m + } +} + +/* 二分查找 */ +func binarySearch(nums: [Int], target: Int) -> Int { + let n = nums.count + // 求解问题 f(0, n-1) + return dfs(nums: nums, target: target, i: 0, j: n - 1) +} + +@main +enum BinarySearchRecur { + /* Driver Code */ + static func main() { + let target = 6 + let nums = [1, 3, 6, 8, 12, 15, 23, 26, 31, 35] + + // 二分查找(双闭区间) + let index = binarySearch(nums: nums, target: target) + print("目标元素 6 的索引 = \(index)") + } +} diff --git a/codes/swift/chapter_divide_and_conquer/build_tree.swift b/codes/swift/chapter_divide_and_conquer/build_tree.swift new file mode 100644 index 000000000..048ffab1a --- /dev/null +++ b/codes/swift/chapter_divide_and_conquer/build_tree.swift @@ -0,0 +1,47 @@ +/** + * File: build_tree.swift + * Created Time: 2023-09-02 + * Author: nuomi1 (nuomi1@qq.com) + */ + +import utils + +/* 构建二叉树:分治 */ +func dfs(preorder: [Int], inorder: [Int], hmap: [Int: Int], i: Int, l: Int, r: Int) -> TreeNode? { + // 子树区间为空时终止 + if r - l < 0 { + return nil + } + // 初始化根节点 + let root = TreeNode(x: preorder[i]) + // 查询 m ,从而划分左右子树 + let m = hmap[preorder[i]]! + // 子问题:构建左子树 + root.left = dfs(preorder: preorder, inorder: inorder, hmap: hmap, i: i + 1, l: l, r: m - 1) + // 子问题:构建右子树 + root.right = dfs(preorder: preorder, inorder: inorder, hmap: hmap, i: i + 1 + m - l, l: m + 1, r: r) + // 返回根节点 + return root +} + +/* 构建二叉树 */ +func buildTree(preorder: [Int], inorder: [Int]) -> TreeNode? { + // 初始化哈希表,存储 inorder 元素到索引的映射 + let hmap = inorder.enumerated().reduce(into: [:]) { $0[$1.element] = $1.offset } + return dfs(preorder: preorder, inorder: inorder, hmap: hmap, i: 0, l: 0, r: inorder.count - 1) +} + +@main +enum BuildTree { + /* Driver Code */ + static func main() { + let preorder = [3, 9, 2, 1, 7] + let inorder = [9, 3, 1, 2, 7] + print("前序遍历 = \(preorder)") + print("中序遍历 = \(inorder)") + + let root = buildTree(preorder: preorder, inorder: inorder) + print("构建的二叉树为:") + PrintUtil.printTree(root: root) + } +} diff --git a/codes/swift/chapter_divide_and_conquer/hanota.swift b/codes/swift/chapter_divide_and_conquer/hanota.swift new file mode 100644 index 000000000..fde869b17 --- /dev/null +++ b/codes/swift/chapter_divide_and_conquer/hanota.swift @@ -0,0 +1,58 @@ +/** + * File: hanota.swift + * Created Time: 2023-09-02 + * Author: nuomi1 (nuomi1@qq.com) + */ + +/* 移动一个圆盘 */ +func move(src: inout [Int], tar: inout [Int]) { + // 从 src 顶部拿出一个圆盘 + let pan = src.popLast()! + // 将圆盘放入 tar 顶部 + tar.append(pan) +} + +/* 求解汉诺塔:问题 f(i) */ +func dfs(i: Int, src: inout [Int], buf: inout [Int], tar: inout [Int]) { + // 若 src 只剩下一个圆盘,则直接将其移到 tar + if i == 1 { + move(src: &src, tar: &tar) + return + } + // 子问题 f(i-1) :将 src 顶部 i-1 个圆盘借助 tar 移到 buf + dfs(i: i - 1, src: &src, buf: &tar, tar: &buf) + // 子问题 f(1) :将 src 剩余一个圆盘移到 tar + move(src: &src, tar: &tar) + // 子问题 f(i-1) :将 buf 顶部 i-1 个圆盘借助 src 移到 tar + dfs(i: i - 1, src: &buf, buf: &src, tar: &tar) +} + +/* 求解汉诺塔 */ +func solveHanota(A: inout [Int], B: inout [Int], C: inout [Int]) { + let n = A.count + // 列表尾部是柱子顶部 + // 将 src 顶部 n 个圆盘借助 B 移到 C + dfs(i: n, src: &A, buf: &B, tar: &C) +} + +@main +enum Hanota { + /* Driver Code */ + static func main() { + // 列表尾部是柱子顶部 + var A = [5, 4, 3, 2, 1] + var B: [Int] = [] + var C: [Int] = [] + print("初始状态下:") + print("A = \(A)") + print("B = \(B)") + print("C = \(C)") + + solveHanota(A: &A, B: &B, C: &C) + + print("圆盘移动完成后:") + print("A = \(A)") + print("B = \(B)") + print("C = \(C)") + } +}