一个问题:
我的计划是获得范围的总和,然后使用组合枚举器创建一个数组以获得范围的所有可能对,然后检查该对的乘积是否等于范围的总和减去总和这对。这个解决方案有效,但耗时太长了:
def removNb(n)
arr = [*1..n]
sum = arr.inject(:+)
ab = []
[*(n/2)..n].combination(2).to_a.each do |pair|
if pair.inject(:*) == sum - pair.inject(:+)
ab << pair
ab << [pair[1],pair[0]]
end
end
ab
end
我找到了一个解决方案:
def removNb(n)
res = []
total = (n*n + n) / 2
range = (1..n)
(1..n).each do |a|
b = ((total - a) / (a * 1.0 + 1.0))
if b == b.to_i && b <= n
res.push([a,b.to_i])
end
end
return res
end
但无法理解它是如何运作的。我理解总数背后的等式。
答案 0 :(得分:4)
你可以形成一个等式
a * b =(从1到n的序列之和) - (a + b)
来自此声明
a和b 的产品应该等于 所有数字的总和 序列,不包括a和b
从1到n的序列之和(表示为总数)= n(n + 1)/ 2 =(n * n + n)/ 2
重新排序上面的等式,你得到
b =(总 - a)/(a + 1)
剩下的工作是测试是否存在与该等式匹配的整数a和b
答案 1 :(得分:0)
代码返回序列中具有所需属性的所有数字对的数组。让我们一步一步。
初始化要返回的数组。
res = []
计算序列中元素的总和。任何算术序列的元素总和等于第一个元素加上最后一个元素,乘以序列中元素的数量,乘以除以2.这是total = n*(1+n)/2
,可以表示为
total = (n*n + n) / 2
range = (1..n)
是不必要的,因为后来没有引用range
。
循环遍历序列的元素
(1..n).each do |a|
对于a
的每个值,我们寻找序列b
的另一个元素,以便
a*b = total - a - b
解决b
:
b = (total - a)/ (a * 1.0 + 1.0)
如果b
在范围内,请保存对[a, b]
if b == b.to_i && b <= n
res.push([a,b.to_i])
end
返回数组res
res
此方法包含两个错误:
[a,b]
添加到res
,则会将其添加两次[a,a]
可以添加到res
(例如n=5
,a=b=3
)我会写如下。
def remove_numbers(n)
total = n*(n+1)/2
(1..n-1).each_with_object([]) do |a,res|
next unless (total-a) % (a+1) == 0
b = (total-a)/(a+1)
res << [a,b] if (a+1..n).cover?(b)
end
end
例如,
remove_numbers 10
#=> [[6, 7]]
remove_numbers 1000
#=> []
出于诽谤:
(2..10_000).map { |x| [x, remove_numbers(x).size] }.max_by(&:last)
#=> [3482, 4]
remove_numbers 3482
#=> [[1770, 3423], [2023, 2995], [2353, 2575], [2460, 2463]]