今天看到一道趣味数学题:
在数字 123456789 之间填加减号(也可以不填,这个时候就任务相邻的数字拼成了多位数),使得运算结果等于100。例如:
- 12 + 3 - 4 + 5 + 67 + 8 + 9 = 100
- 1 + 2 + 3 - 4 + 5 + 6 + 78 + 9 = 100
- 1 + 23 - 4 + 56 + 7 + 8 + 9 = 100
你能找出多少个这样的等式?
看完之后,真心觉得这道题有点意思,好奇心和好胜心马上就上来了。作为一名程序员,这种问题怎么可能难得住我呢!经过深入思考,觉得这道题完全可以用 JS 进行暴力枚举,因为:
1~9 之间总共有8个位置,可以填入+号,-号,或者空字符串,也就是说最多有 3 的 8 次方种可能性。
用 JS 算了一下:
console.log(Math.pow(3, 8)) // 用内置的 Math 库提供的函数计算得到 6561
console.log(3 ** 8) // 用 ** 运算符计算得到 6561
心想:总数才这么一点大,简直不要太简单,我只要拼好公式字符串,然后用强大的 eval
函数计算一下不就行了么?如下图所示:
说干就干!首先定义两个数组变量:
const numbers = '123456789'.split('') // 保存数字序列
const symbols = ['+', '-', ''] // 保存数字之间的连接符号
再定义一个全局 formulas 数组保存所有的计算公式:
let formulas = [] // 保存公式
然后从 1 开始逐步累加到 9,什么意思呢?例如 formulas 的初始值是 ['1']
,那么下一步就会变成:
['1+2']
['1-2']
['12']
那再下一步就会变为:
['1+2+3']
['1+2-3']
['1+23']
['1-2+3']
['1-2-3']
['1-23']
['12+3']
['12-3']
['123']
第 1 步数组里面是 1 个元素,第 2 步就是 3 个,第 3 步就是 9 个元素,以此类推,第 N 步就是 3^(N-1) 个元素,我们只需要走 8 步就行了,也就是 3^8 = 6561 个元素,打印结果如下:
控制台打印数组的时候,默认最多打印 100 个元素,剩下的在点点点(…)里面
按照上面的解题思路,最终的代码如下:
const numbers = '123456789'.split('')
const symbols = ['+', '-', '']
let formulas = []
function increase(number) {
if (number === '1') return (formulas = ['1'])
let arr = []
for (let i = formulas.length; i; i--) {
const lastFormula = formulas[i - 1]
for (let j = symbols.length; j; j--) {
let symbol = symbols[j - 1]
arr.push(lastFormula + symbol + number)
}
}
formulas = arr
}
numbers.forEach((number) => increase(number))
// 打印全部公式
// console.log(formulas)
// 打印和为100的公式
console.log(formulas.filter((it) => eval(it) === 100))
最后得到 11 个这样的等式:
1 + 23 - 4 + 5 + 6 + 78 - 9
1 + 23 - 4 + 56 + 7 + 8 + 9
1 + 2 + 3 - 4 + 5 + 6 + 78 + 9
1 + 2 + 34 - 5 + 67 - 8 + 9
123 + 45 - 67 + 8 - 9
123 + 4 - 5 + 67 - 89
123 - 45 - 67 + 89
123 - 4 - 5 - 6 - 7 + 8 - 9
12 - 3 - 4 + 5 - 6 + 7 + 89
12 + 3 + 4 + 5 - 6 - 7 + 89
12 + 3 - 4 + 5 + 67 + 8 + 9
是不是很有意思呢?大家自己动手试一下吧,如果有更简单优雅的代码,可以直接分享到评论里面!
本文正在参加「金石计划 . 瓜分6万现金大奖」