diff --git a/codes/swift/Package.swift b/codes/swift/Package.swift index d6d8f5cf7..ba293d40d 100644 --- a/codes/swift/Package.swift +++ b/codes/swift/Package.swift @@ -93,6 +93,11 @@ let package = Package( .executable(name: "coin_change", targets: ["coin_change"]), .executable(name: "coin_change_ii", targets: ["coin_change_ii"]), .executable(name: "edit_distance", targets: ["edit_distance"]), + // chapter_greedy + .executable(name: "coin_change_greedy", targets: ["coin_change_greedy"]), + .executable(name: "fractional_knapsack", targets: ["fractional_knapsack"]), + .executable(name: "max_capacity", targets: ["max_capacity"]), + .executable(name: "max_product_cutting", targets: ["max_product_cutting"]), ], targets: [ // helper @@ -187,5 +192,10 @@ let package = Package( .executableTarget(name: "coin_change", path: "chapter_dynamic_programming", sources: ["coin_change.swift"]), .executableTarget(name: "coin_change_ii", path: "chapter_dynamic_programming", sources: ["coin_change_ii.swift"]), .executableTarget(name: "edit_distance", path: "chapter_dynamic_programming", sources: ["edit_distance.swift"]), + // chapter_greedy + .executableTarget(name: "coin_change_greedy", path: "chapter_greedy", sources: ["coin_change_greedy.swift"]), + .executableTarget(name: "fractional_knapsack", path: "chapter_greedy", sources: ["fractional_knapsack.swift"]), + .executableTarget(name: "max_capacity", path: "chapter_greedy", sources: ["max_capacity.swift"]), + .executableTarget(name: "max_product_cutting", path: "chapter_greedy", sources: ["max_product_cutting.swift"]), ] ) diff --git a/codes/swift/chapter_greedy/coin_change_greedy.swift b/codes/swift/chapter_greedy/coin_change_greedy.swift new file mode 100644 index 000000000..e6d25c058 --- /dev/null +++ b/codes/swift/chapter_greedy/coin_change_greedy.swift @@ -0,0 +1,54 @@ +/** + * File: coin_change_greedy.swift + * Created Time: 2023-09-03 + * Author: nuomi1 (nuomi1@qq.com) + */ + +/* 零钱兑换:贪心 */ +func coinChangeGreedy(coins: [Int], amt: Int) -> Int { + // 假设 coins 列表有序 + var i = coins.count - 1 + var count = 0 + var amt = amt + // 循环进行贪心选择,直到无剩余金额 + while amt > 0 { + // 找到小于且最接近剩余金额的硬币 + while i > 0 && coins[i] > amt { + i -= 1 + } + // 选择 coins[i] + amt -= coins[i] + count += 1 + } + // 若未找到可行方案,则返回 -1 + return amt == 0 ? count : -1 +} + +@main +enum CoinChangeGreedy { + /* Driver Code */ + static func main() { + // 贪心:能够保证找到全局最优解 + var coins = [1, 5, 10, 20, 50, 100] + var amt = 186 + var res = coinChangeGreedy(coins: coins, amt: amt) + print("\ncoins = \(coins), amount = \(amt)") + print("凑到 \(amt) 所需的最少硬币数量为 \(res)") + + // 贪心:无法保证找到全局最优解 + coins = [1, 20, 50] + amt = 60 + res = coinChangeGreedy(coins: coins, amt: amt) + print("\ncoins = \(coins), amount = \(amt)") + print("凑到 \(amt) 所需的最少硬币数量为 \(res)") + print("实际上需要的最少数量为 3 ,即 20 + 20 + 20") + + // 贪心:无法保证找到全局最优解 + coins = [1, 49, 50] + amt = 98 + res = coinChangeGreedy(coins: coins, amt: amt) + print("\ncoins = \(coins), amount = \(amt)") + print("凑到 \(amt) 所需的最少硬币数量为 \(res)") + print("实际上需要的最少数量为 2 ,即 49 + 49") + } +} diff --git a/codes/swift/chapter_greedy/fractional_knapsack.swift b/codes/swift/chapter_greedy/fractional_knapsack.swift new file mode 100644 index 000000000..357ac6892 --- /dev/null +++ b/codes/swift/chapter_greedy/fractional_knapsack.swift @@ -0,0 +1,57 @@ +/** + * File: fractional_knapsack.swift + * Created Time: 2023-09-03 + * Author: nuomi1 (nuomi1@qq.com) + */ + +// 物品 +struct Item { + var w: Int // 物品重量 + var v: Int // 物品价值 + + init(w: Int, v: Int) { + self.w = w + self.v = v + } +} + +/* 分数背包:贪心 */ +func fractionalKnapsack(wgt: [Int], val: [Int], cap: Int) -> Double { + // 创建物品列表,包含两个属性:重量、价值 + var items = zip(wgt, val).map { Item(w: $0, v: $1) } + // 按照单位价值 item.v / item.w 从高到低进行排序 + items.sort(by: { -(Double($0.v) / Double($0.w)) < -(Double($1.v) / Double($1.w)) }) + // 循环贪心选择 + var res = 0.0 + var cap = cap + for item in items { + if item.w <= cap { + // 若剩余容量充足,则将当前物品整个装进背包 + res += Double(item.v) + cap -= item.w + } else { + // 若剩余容量不足,则将当前物品的一部分装进背包 + res += Double(item.v) / Double(item.w) * Double(cap) + // 已无剩余容量,因此跳出循环 + break + } + } + return res +} + +@main +enum FractionalKnapsack { + /* Driver Code */ + static func main() { + // 物品重量 + let wgt = [10, 20, 30, 40, 50] + // 物品价值 + let val = [50, 120, 150, 210, 240] + // 背包容量 + let cap = 50 + + // 贪心算法 + let res = fractionalKnapsack(wgt: wgt, val: val, cap: cap) + print("不超过背包容量的最大物品价值为 \(res)") + } +} diff --git a/codes/swift/chapter_greedy/max_capacity.swift b/codes/swift/chapter_greedy/max_capacity.swift new file mode 100644 index 000000000..0d75c2771 --- /dev/null +++ b/codes/swift/chapter_greedy/max_capacity.swift @@ -0,0 +1,38 @@ +/** + * File: max_capacity.swift + * Created Time: 2023-09-03 + * Author: nuomi1 (nuomi1@qq.com) + */ + +/* 最大容量:贪心 */ +func maxCapacity(ht: [Int]) -> Int { + // 初始化 i, j 分列数组两端 + var i = 0, j = ht.count - 1 + // 初始最大容量为 0 + var res = 0 + // 循环贪心选择,直至两板相遇 + while i < j { + // 更新最大容量 + let cap = min(ht[i], ht[j]) * (j - i) + res = max(res, cap) + // 向内移动短板 + if ht[i] < ht[j] { + i += 1 + } else { + j -= 1 + } + } + return res +} + +@main +enum MaxCapacity { + /* Driver Code */ + static func main() { + let ht = [3, 8, 5, 2, 7, 7, 3, 4] + + // 贪心算法 + let res = maxCapacity(ht: ht) + print("最大容量为 \(res)") + } +} diff --git a/codes/swift/chapter_greedy/max_product_cutting.swift b/codes/swift/chapter_greedy/max_product_cutting.swift new file mode 100644 index 000000000..ca78832a7 --- /dev/null +++ b/codes/swift/chapter_greedy/max_product_cutting.swift @@ -0,0 +1,43 @@ +/** + * File: max_product_cutting.swift + * Created Time: 2023-09-03 + * Author: nuomi1 (nuomi1@qq.com) + */ + +import Foundation + +func pow(_ x: Int, _ y: Int) -> Int { + Int(Double(truncating: pow(Decimal(x), y) as NSDecimalNumber)) +} + +/* 最大切分乘积:贪心 */ +func maxProductCutting(n: Int) -> Int { + // 当 n <= 3 时,必须切分出一个 1 + if n <= 3 { + return 1 * (n - 1) + } + // 贪心地切分出 3 ,a 为 3 的个数,b 为余数 + let a = n / 3 + let b = n % 3 + if b == 1 { + // 当余数为 1 时,将一对 1 * 3 转化为 2 * 2 + return pow(3, a - 1) * 2 * 2 + } + if b == 2 { + // 当余数为 2 时,不做处理 + return pow(3, a) * 2 + } + // 当余数为 0 时,不做处理 + return pow(3, a) +} + +@main +enum MaxProductCutting { + static func main() { + let n = 58 + + // 贪心算法 + let res = maxProductCutting(n: n) + print("最大切分乘积为 \(res)") + } +}