这是一个有趣的问题,让您可以使用 Swift 的自定义枚举、可选、集合、高阶函数 (map) 以及从函数返回多个值的能力。
144 个方程!即使我们有代码,也很难确认您已经涵盖了所有内容。除以零是一个棘手的情况,需要特别注意。
这是我对这个问题的看法。我的解决方案的目标是:
- 将其分解为易于验证的步骤
- 避免被零除
- 避免小数计算
- 避免负数
- 以人类可读的形式显示方程
- 找出最接近目标的所有方程
// Generate all 6 permuations of the 3 numbers.
// Use Set() to remove duplicates
func permuteNumbers(_ a: Int, _ b: Int, _ c: Int) -> [(Int, Int, Int)] {
return Set([[a, b, c],
[a, c, b],
[b, a, c],
[b, c, a],
[c, a, b],
[c, b, a]]).map { ($0[0], $0[1], $0[2]) }
}
enum Operation: String, CaseIterable {
case addition = "+"
case subtraction = "-"
case multiplication = "*"
case division = "/"
}
// Generate all 16 combinations of the 4 operations
func allOperations() -> [(Operation, Operation)] {
var all = [(Operation, Operation)]()
for op1 in Operation.allCases {
for op2 in Operation.allCases {
all.append((op1, op2))
}
}
return all
}
// Return nil on divide by zero.
// Return nil when the result would be a negative number.
// Return nil when the result would be a fraction (not a whole number).
func performOperation(_ a: Int, _ b: Int, _ op: Operation) -> Int? {
switch op {
case .addition: return a + b
case .subtraction: return (b > a) ? nil : a - b
case .multiplication: return a * b
case .division: return ((b == 0) || (a % b != 0)) ? nil : a / b
}
}
// Perform (a op1 b) op2 c
// return (result, equation)
func performOp1First(a: Int, b: Int, c: Int, op1: Operation, op2: Operation) -> (Int?, String) {
let str = "(\(a) \(op1.rawValue) \(b)) \(op2.rawValue) \(c)"
if let r1 = performOperation(a, b, op1) {
if let r2 = performOperation(r1, c, op2) {
return (r2, str)
}
}
return (nil, str)
}
// Perform a op1 (b op2 c)
// return (result, equation)
func performOp2First(a: Int, b: Int, c: Int, op1: Operation, op2: Operation) -> (Int?, String) {
let str = "\(a) \(op1.rawValue) (\(b) \(op2.rawValue) \(c))"
if let r1 = performOperation(b, c, op2) {
if let r2 = performOperation(a, r1, op1) {
return (r2, str)
}
}
return (nil, str)
}
// Perform a op1 b op2 c - order doesn't matter for (+, +), (+, -), (*, *), and (*, /)
// return (result, equation)
func performNoParens(a: Int, b: Int, c: Int, op1: Operation, op2: Operation) -> (Int?, String) {
let str = "\(a) \(op1.rawValue) \(b) \(op2.rawValue) \(c)"
if let r1 = performOperation(a, b, op1) {
if let r2 = performOperation(r1, c, op2) {
return (r2, str)
}
}
return (nil, str)
}
// Search all permutations of the numbers, operations, and operation order
func findBest(a: Int, b: Int, c: Int, target: Int) -> (diff: Int, equations: [String]) {
let numbers = permuteNumbers(a, b, c)
var best = Int.max
var equations = [String]()
for (a, b, c) in numbers {
for (op1, op2) in allOperations() {
// Parentheses are not needed if the operators are (+, +), (+, -), (*, *), (*, /)
let noparens = [["+", "+"], ["+", "-"],["*", "*"], ["*", "/"]].contains([op1.rawValue, op2.rawValue])
for f in (noparens ? [performNoParens] : [performOp1First, performOp2First]) {
let (result, equation) = f(a, b, c, op1, op2)
if let result = result {
let diff = abs(result - target)
if diff == best {
equations.append(equation)
} else if diff < best {
best = diff
equations = [equation]
}
}
}
}
}
return (best, equations)
}
示例:
print(findBest(a: 8, b: 6, c: 4, target: 10))
(diff: 0, equations: ["8 + 6 - 4", "6 + 8 - 4", "(6 - 4) + 8", "(8 - 4) + 6"])
print(findBest(a: 8, b: 6, c: 4, target: 12))
(diff: 0, equations: ["6 * 8 / 4", "8 * 6 / 4", "(8 / 4) * 6"])
print(findBest(a: 8, b: 6, c: 4, target: 4))
(diff: 0, equations: ["6 - (8 / 4)", "8 / (6 - 4)"])
print(findBest(a: 8, b: 6, c: 4, target: 5))
(diff: 1, equations: ["6 - (8 / 4)", "4 + 8 - 6", "(8 - 6) + 4", "8 - (6 - 4)", "8 / (6 - 4)", "8 + 4 - 6"])
print(findBest(a: 8, b: 6, c: 4, target: 7))
(diff: 1, equations: ["(8 - 6) + 4", "8 - (6 - 4)", "(8 - 6) * 4", "6 + (8 / 4)", "4 + 8 - 6", "4 * (8 - 6)", "8 + 4 - 6", "(8 / 4) + 6"])
Kotlin 版本
这是一个从 Swift 版本手动翻译的 Kotlin 版本。这是我的第一个 Kotlin 程序,所以我确信我没有以最惯用的方式做所有事情。我在Online Kotlin Playground测试了这个程序
import kotlin.math.abs
// Generate all 6 permuations of the 3 numbers.
// Use Set() to remove duplicates
fun permuteNumbers(a: Int, b: Int, c: Int): Set<List<Int>> {
return setOf(
listOf(a, b, c),
listOf(a, c, b),
listOf(b, a, c),
listOf(b, c, a),
listOf(c, a, b),
listOf(c, b, a)
)
}
enum class Operation(val string: String) {
ADDITION("+"),
SUBTRACTION("-") ,
MULTIPLICATION("*"),
DIVISION("/")
}
fun allOperations(): List<Pair<Operation, Operation>> {
val result = mutableListOf<Pair<Operation, Operation>>()
for (op1 in Operation.values()) {
for (op2 in Operation.values()) {
result.add(Pair(op1, op2))
}
}
return result
}
fun performOperation(a: Int, b: Int, op: Operation): Int? {
return when (op) {
Operation.ADDITION -> (a + b)
Operation.SUBTRACTION -> if (b > a) { null } else { a - b }
Operation.MULTIPLICATION -> a * b
Operation.DIVISION -> if ((b == 0) || (a % b != 0)) { null} else { a / b }
}
}
// Perform (a op1 b) op2 c
// return (result, equation)
fun performOp1First(a: Int, b: Int, c: Int, op1: Operation, op2: Operation): Pair<Int?, String> {
val str = "($a ${op1.string} $b) ${op2.string} $c"
performOperation(a, b, op1)?.also { r1 ->
performOperation(r1, c, op2)?.also { r2 ->
return Pair(r2, str)
}
}
return Pair(null, str)
}
// Perform a op1 (b op2 c)
// return (result, equation)
fun performOp2First(a: Int, b: Int, c: Int, op1: Operation, op2: Operation): Pair<Int?, String> {
val str = "$a ${op1.string} ($b ${op2.string} $c)"
performOperation(b, c, op2)?.also { r1 ->
performOperation(a, r1, op1)?.also { r2 ->
return Pair(r2, str)
}
}
return Pair(null, str)
}
// Perform a op1 b op2 c - order doesn't matter for (+, +), (+, -), (*, *), and (*, /)
// return (result, equation)
fun performNoParens(a: Int, b: Int, c: Int, op1: Operation, op2: Operation): Pair<Int?, String> {
val str = "$a ${op1.string} $b ${op2.string} $c"
performOperation(a, b, op1)?.also { r1 ->
performOperation(r1, c, op2)?.also { r2 ->
return Pair(r2, str)
}
}
return Pair(null, str)
}
// Search all permutations of the numbers, operations, and operation order
fun findBest(a: Int, b: Int, c: Int, target: Int): Pair<Int, List<String>> {
val numbers = permuteNumbers(a, b, c)
var best = Int.MAX_VALUE
var equations = mutableListOf<String>()
for ((a1, b1, c1) in numbers) {
for ((op1, op2) in allOperations()) {
// Parentheses are not needed if the operators are (+, +), (+, -), (*, *), (*, /)
val noparens = listOf(listOf("+", "+"), listOf("+", "-"), listOf("*", "*"), listOf("*", "/"))
.contains(listOf(op1.string, op2.string))
for (f in if (noparens) { listOf(::performNoParens) } else { listOf(::performOp1First, ::performOp2First) }) {
val (result, equation) = f(a1, b1, c1, op1, op2)
result?.also { result2 ->
val delta = abs(target - result2)
if (delta == best) {
equations.add(equation)
} else if (delta < best) {
best = delta
equations = mutableListOf(equation)
}
}
}
}
}
return Pair(best, equations)
}
fun main() {
println(findBest(4, 6, 8, 4))
}