使用set,查找num是否存在为数组中2个数字的总和

时间:2017-11-20 22:10:43

标签: ruby set

我需要查找数组中的两个数字是否等于特定数字。

def sum?(array, num)
end

sum?([1, 2, 3], 5) #=> true
sum?([1, 2, 3], 6) #=> false

是否有使用订单小于N ^ 2的集合的解决方案?另外,有没有办法在不使用集合的情况下获得N ^ 2?

3 个答案:

答案 0 :(得分:4)

使用集合,特定数字的查找大致不变。对于数组中的每个数字,只有一个其他数字可以使总和工作。扫描阵列是线性的。

require 'set'

def sum?(array, num)
  set = array.to_set
  array.any? { |x| set.include?(num - x) }
end

集合转换近似为线性(N个插入),any?是线性的,因为最坏情况迭代每个元素一次,并且每个元素在集合中具有近似恒定的查找。所以整体线性。

如果num为偶数且数组包含num/2的单个副本,则此方法失败。这是另一个线性检查,我将把它留作练习。

答案 1 :(得分:0)

这里天真的策略非常简单:

None

使用def sum?(array, n) array.reject do |v| v >= n end.combination(2).any? do |a, b| a + b == n end end 似乎非常严厉,因为你必须计算所有可能总和的整个集合。对于重复测试,它会更有效,您只需要计算一次设置,但对于单次测试,效率较低。这实际上取决于您的使用案例。

例如:

Set

您可以尝试使用基准测试来查看更长的数字列表的性能。

答案 2 :(得分:0)

您要求提供基于设置的解决方案。如果你想避免导入,你可以使用rubys" Enumerable #uniq"而不是函数(也在Array中实现),它创建一个没有dublicate条目的新数组。下一步是确定数组的最小int值,并从您希望的sum值中减去该值。像这样计算的值是您拥有的最大允许值。然后你可以拒绝其他人。到目前为止,根据ruby文档中的C-Code,所有操作似乎都是O(N)。最后你可以使用Enumerable#any?功能,就像你的pereferd解决方案一样。

这里有一些未经测试的代码:

    def sum?(array,num)
       rest = array.uniq
       max_allowed = num - rest.min
       rest.reject! {|value| value > max_allowed}
       rest.any? {|value| rest.include?(num - value)}
    end

用于计算: array.uniq与转换为集合几乎相同,所以让我们跳过这个。 计算最大允许值为O(1)+ O(N) 拒绝是O(N) 任何?应该导致平均O(N * log(N))

得出结果:O(1)+ 2 * O(N)+ O(N * log(N)) 根据大O符号,这是O(N * log(N)),因为它是最小的部分,小于O(N ^ 2)