diff --git a/codes/swift/Package.swift b/codes/swift/Package.swift index f05608c71..b57e7839c 100644 --- a/codes/swift/Package.swift +++ b/codes/swift/Package.swift @@ -48,6 +48,7 @@ let package = Package( .executable(name: "graph_dfs", targets: ["graph_dfs"]), // chapter_searching .executable(name: "binary_search", targets: ["binary_search"]), + .executable(name: "binary_search_insertion", targets: ["binary_search_insertion"]), .executable(name: "binary_search_edge", targets: ["binary_search_edge"]), .executable(name: "two_sum", targets: ["two_sum"]), .executable(name: "linear_search", targets: ["linear_search"]), @@ -91,6 +92,7 @@ let package = Package( // helper .target(name: "utils", path: "utils"), .target(name: "graph_adjacency_list_target", dependencies: ["utils"], path: "chapter_graph", sources: ["graph_adjacency_list_target.swift"], swiftSettings: [.define("TARGET")]), + .target(name: "binary_search_insertion_target", path: "chapter_searching", sources: ["binary_search_insertion_target.swift"], swiftSettings: [.define("TARGET")]), // chapter_computational_complexity .executableTarget(name: "time_complexity", path: "chapter_computational_complexity", sources: ["time_complexity.swift"]), .executableTarget(name: "worst_best_time_complexity", path: "chapter_computational_complexity", sources: ["worst_best_time_complexity.swift"]), @@ -134,7 +136,8 @@ let package = Package( .executableTarget(name: "graph_dfs", dependencies: ["utils", "graph_adjacency_list_target"], path: "chapter_graph", sources: ["graph_dfs.swift"]), // chapter_searching .executableTarget(name: "binary_search", path: "chapter_searching", sources: ["binary_search.swift"]), - .executableTarget(name: "binary_search_edge", path: "chapter_searching", sources: ["binary_search_edge.swift"]), + .executableTarget(name: "binary_search_insertion", path: "chapter_searching", sources: ["binary_search_insertion.swift"]), + .executableTarget(name: "binary_search_edge", dependencies: ["binary_search_insertion_target"], path: "chapter_searching", sources: ["binary_search_edge.swift"]), .executableTarget(name: "two_sum", path: "chapter_searching", sources: ["two_sum.swift"]), .executableTarget(name: "linear_search", dependencies: ["utils"], path: "chapter_searching", sources: ["linear_search.swift"]), .executableTarget(name: "hashing_search", dependencies: ["utils"], path: "chapter_searching", sources: ["hashing_search.swift"]), diff --git a/codes/swift/chapter_searching/binary_search_edge.swift b/codes/swift/chapter_searching/binary_search_edge.swift new file mode 100644 index 000000000..439760899 --- /dev/null +++ b/codes/swift/chapter_searching/binary_search_edge.swift @@ -0,0 +1,51 @@ +/** + * File: binary_search_edge.swift + * Created Time: 2023-08-06 + * Author: nuomi1 (nuomi1@qq.com) + */ + +import binary_search_insertion_target + +/* 二分查找最左一个 target */ +func binarySearchLeftEdge(nums: [Int], target: Int) -> Int { + // 等价于查找 target 的插入点 + let i = binarySearchInsertion(nums: nums, target: target) + // 未找到 target ,返回 -1 + if i == nums.count || nums[i] != target { + return -1 + } + // 找到 target ,返回索引 i + return i +} + +/* 二分查找最右一个 target */ +func binarySearchRightEdge(nums: [Int], target: Int) -> Int { + // 转化为查找最左一个 target + 1 + let i = binarySearchInsertion(nums: nums, target: target + 1) + // j 指向最右一个 target ,i 指向首个大于 target 的元素 + let j = i - 1 + // 未找到 target ,返回 -1 + if j == -1 || nums[j] != target { + return -1 + } + // 找到 target ,返回索引 j + return j +} + +@main +enum BinarySearchEdge { + /* Driver Code */ + static func main() { + // 包含重复元素的数组 + let nums = [1, 3, 6, 6, 6, 6, 6, 10, 12, 15] + print("\n数组 nums = \(nums)") + + // 二分查找左边界和右边界 + for target in [6, 7] { + var index = binarySearchLeftEdge(nums: nums, target: target) + print("最左一个元素 \(target) 的索引为 \(index)") + index = binarySearchRightEdge(nums: nums, target: target) + print("最右一个元素 \(target) 的索引为 \(index)") + } + } +} diff --git a/codes/swift/chapter_searching/binary_search_insertion.swift b/codes/swift/chapter_searching/binary_search_insertion.swift new file mode 100644 index 000000000..44d2e85cf --- /dev/null +++ b/codes/swift/chapter_searching/binary_search_insertion.swift @@ -0,0 +1,67 @@ +/** + * File: binary_search_insertion.swift + * Created Time: 2023-08-06 + * Author: nuomi1 (nuomi1@qq.com) + */ + +/* 二分查找插入点(无重复元素) */ +func binarySearchInsertionSimple(nums: [Int], target: Int) -> Int { + var i = 0, j = nums.count - 1 // 初始化双闭区间 [0, n-1] + while i <= j { + let m = i + (j - i) / 2 // 计算中点索引 m + if nums[m] < target { + i = m + 1 // target 在区间 [m+1, j] 中 + } else if nums[m] > target { + j = m - 1 // target 在区间 [i, m-1] 中 + } else { + return m // 找到 target ,返回插入点 m + } + } + // 未找到 target ,返回插入点 i + return i +} + +/* 二分查找插入点(存在重复元素) */ +public func binarySearchInsertion(nums: [Int], target: Int) -> Int { + var i = 0, j = nums.count - 1 // 初始化双闭区间 [0, n-1] + while i <= j { + let m = i + (j - i) / 2 // 计算中点索引 m + if nums[m] < target { + i = m + 1 // target 在区间 [m+1, j] 中 + } else if nums[m] > target { + j = m - 1 // target 在区间 [i, m-1] 中 + } else { + j = m - 1 // 首个小于 target 的元素在区间 [i, m-1] 中 + } + } + // 返回插入点 i + return i +} + +#if !TARGET + +@main +enum BinarySearchInsertion { + /* Driver Code */ + static func main() { + // 无重复元素的数组 + var nums = [1, 3, 6, 8, 12, 15, 23, 26, 31, 35] + print("\n数组 nums = \(nums)") + // 二分查找插入点 + for target in [6, 9] { + let index = binarySearchInsertionSimple(nums: nums, target: target) + print("元素 \(target) 的插入点的索引为 \(index)") + } + + // 包含重复元素的数组 + nums = [1, 3, 6, 6, 6, 6, 6, 10, 12, 15] + print("\n数组 nums = \(nums)") + // 二分查找插入点 + for target in [2, 6, 20] { + let index = binarySearchInsertion(nums: nums, target: target) + print("元素 \(target) 的插入点的索引为 \(index)") + } + } +} + +#endif diff --git a/codes/swift/chapter_searching/binary_search_insertion_target.swift b/codes/swift/chapter_searching/binary_search_insertion_target.swift new file mode 120000 index 000000000..3f1a7b761 --- /dev/null +++ b/codes/swift/chapter_searching/binary_search_insertion_target.swift @@ -0,0 +1 @@ +binary_search_insertion.swift \ No newline at end of file