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

我一直在解决这个问题几个小时,我不明白为什么我不能让它运行正常。 这种方法的最终游戏是在一个数组中有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]的数组,那么它应该会返回true。 我确定我的2声明就是这个原因,但我想不出办法解决它。 如果有人能指出我正确的方向,那将会有所帮助。

您可以找到第一对加起来为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 

这是另一种方式:

 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] 

我认为最Ruby的方式是:

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

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

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

好吧,鉴于它标记为#ruby,这是我能想到解决这个问题的最“ruby方式”:

 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 
 array.combination(2).select{|x|x[0] + x[1] == 0}