在Ruby中检查数组中的2个数字是否总和为0

时间:2014-08-08 23:49:28

标签: ruby arrays

我已经解决了这个问题几个小时了,我无法理解为什么我无法让它正常运行。这种方法的最终游戏是在一个数组中有2个数字,当加在一起时等于零。这是我的代码:

def two_sums(nums)
    i = 0
    j = -1
    while i < nums.count
        num_1 = nums[i]
        while j < nums.count
        num_2 = nums[j]
            if num_1 + num_2 == 0
                return "There are 2 numbers that sum to zero & they are #{num_1} and #{num_2}."
            else
                return "Nothing adds to zero."
            end             
        end
    i += 1
    j -= 1
    end
end

我遇到的问题是,除非数组中的第一个和最后一个数字是相同数字的正数和负数,否则它将始终返回false。

例如,如果我有一个[1,4,6,-1,10]的数组,它应该会回来。我确定我的2声明是导致这种情况的原因,但我无法想出解决问题的方法。如果有人能指出我正确的方向,那将会有所帮助。

6 个答案:

答案 0 :(得分:5)

您可以找到第一对加起来为0的对,如下所示:

nums.combination(2).find { |x, y| x + y == 0 }
#=> returns the first matching pair or nil

或者,如果要选择总计为0的所有对:

nums.combination(2).select { |x, y| x + y == 0 }
#=> returns all matching pairs or an empty array

因此,您可以像这样实现您的方法:

def two_sums(nums)
  pair = nums.combination(2).find { |x, y| x + y == 0 }
  if pair
    "There are 2 numbers that sum to zero & they are #{pair.first} and #{pair.last}."
  else
    "Nothing adds to zero."
  end
end    

或者如果你想找到所有对:

def two_sums(nums)
  pairs = nums.combination(2).select { |x, y| x + y == 0 }
  if pairs.empty?
    "Nothing adds to zero."
  else
    "The following pairs sum to zero: #{pairs}..."
  end
end    

答案 1 :(得分:3)

这是另一种方式:

<强>代码

def sum_to_zero(arr)
  arr.group_by { |e| e.abs }
     .values
     .select { |a| (a.size > 1 && a.first == 0) || a.uniq.size > 1 }
end

<强>实施例

sum_to_zero [1, 4, 6, -1, 10]     #=> [[1, -1]]
sum_to_zero [1, 4, 1, -2, 10]     #=> []
sum_to_zero [1, 0, 4,  1,  0, -1] #=> [[1, 1, -1], [0, 0]]

这种方法相对较快。让我们尝试一下200,000个元素的数组,每个元素都是-500,000到500,000之间的随机数。

require 'time'

t = Time.now
arr = Array.new(200_000) { rand(1_000_001) - 500_000 }
arr.size #=> 200000

sum_to_zero(arr).size #=> 16439
Time.now - t
  #=> 0.23 (seconds) 

sum_to_zero(arr).first(6)
  #=> [[-98747, 98747],
  #    [157848, -157848],
  #    [-459650, 459650],
  #    [176655, 176655, -176655],
  #    [282101, -282101],
  #    [100886, 100886, -100886]]

如果您希望将总和为零的非负值和负值分组:

sum_to_zero(arr).map { |a| a.partition { |e| e >= 0 } }.first(6)
  #=> [[[98747], [-98747]],
  #    [[157848], [-157848]],
  #    [[459650], [-459650]],
  #    [[176655, 176655], [-176655]],
  #    [[282101], [-282101]],
  #    [[100886, 100886], [-100886]]]

如果您只需要每个组的单个值(例如非负值):

sum_to_zero(arr).map { |a| a.first.abs }.first(6)
  #=> [98747, 157848, 459650, 176655, 282101, 100886]

答案 2 :(得分:2)

我认为最Ruby的方式是:

nums.combination(2).any? { |x,y| (x+y).zero? }

答案 3 :(得分:2)

这是一种适用于大型数组的方法。上面的方法经历了两个数字的每个可能的组合对于小的情况非常好,但是对于具有大量元素的数组来说将非常慢并且内存很耗力。

def two_sums nums
  h = Hash.new
  nums.each do |n|
    return true if h[-n]
    h[n] = true
  end
  false
end

答案 4 :(得分:1)

好吧,鉴于它标记为#ruby,这里有最多&#34;红宝石的方式&#34;我能想到解决这个问题:

def two_sums(arr)
  numbers = arr.combination(2).select { |a| a.reduce(:+) == 0 }.flatten

  if numbers.empty?
    "Nothing adds to zero."
  else
    "There are 2 numbers that sum to zero & they are #{numbers.first} and #{numbers.last}."
  end
end

答案 5 :(得分:0)

array.combination(2).select{|x|x[0] + x[1] == 0}