从具有输入中定义的和的未排序数组中查找两个元素的最佳方法

时间:2018-08-17 07:01:11

标签: arrays ruby

例如,我有一个未排序的整数数组

array = [ 2,5,3,6,33,11,7,23,8,50,9 ]

通过最小的迭代,如何找到两个总和为10的元素?

方法1:我认为

  1. 首先,制作另一个数组作为已定义数组的副本。
  2. 通过使用For循环,通过将第一个元素与其余元素相加来对元素进行迭代,如果我得到10个元素,则中断循环。但这会进行n次,因为我们没有下一个元素的位置。
  3. 在第一次迭代中,如果找不到任何元素,则将删除所选元素以减少第二次迭代的比较。
  4. 以同样的方式,我将处理其余的元素,但再次进行n-1比较。

我尽力找到最好的方法,但没有任何解决办法。

3 个答案:

答案 0 :(得分:6)

通过记住每个值上我们遗漏的金额,您可以使其近似O(n):

<div>
<ul>
<li><span class="disc"></span>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse in pretium mauris. Aliquam ultrices ipsum sit amet auctor porta. Donec et metus quis dolor dignissim euismod non a sem. Sed accumsan risus quis ipsum pellentesque, quis dictum metus porttitor.</li>
<li><span class="disc"></span>Etiam et interdum ipsum, quis venenatis augue. Sed euismod, sem eget tristique molestie, arcu massa scelerisque nunc, eget scelerisque elit sem vitae nulla.</li>
<li><span class="disc"></span>Nulla id</li>
<li><span class="disc"></span>Nam ut</li>
</ul>
</div>

我们还可以使用Set,它具有相同的基本流程:

def foo(array, target = 10)
  h = {}
  array.each do |value|
    return [h[value], value] if h.key?(value)
    h[target - value] = value
  end
  nil
end

foo([ 2,5,3,6,33,11,7,23,8,50,9 ], 10)
=> [3, 7]

这两个选项在后台具有相同的成本(因为Ruby的Set在Hash之上实现);我更喜欢记住我们仍然需要哪个值[以及附带的哪个原始值]的语义,但是取决于您找到哪个更好地阅读。


另一种选择是使用require "set" def foo(array, target = 10) seen = Set.new array.each do |value| return [target - value, value] if seen.include?(target - value) seen << value end nil end foo([ 2,5,3,6,33,11,7,23,8,50,9 ], 10) => [3, 7] 打开-这意味着计算机将进行更多(尽管仍然是线性的)工作(因为它将整个数组转换为集合,而不是仅将元素转换为集合,直到找到一个匹配),但使代码更易于阅读,因为循环只有一项工作:

array.to_set

请注意,它找到了另一个匹配项-先前的算法返回了第一个匹配项以显示其第二个数字;新的将返回第一个匹配项,并显示第一个数字。

答案 1 :(得分:3)

array.combination(2).find { |a,b| a+b == 10 }
  #=> [2, 8]
如果没有两个元素合计为nil,将返回

10。例如,

array.combination(2).find { |a,b| a+b == 1000 }
  #=> nil

请参见Array#combination

这是另一种方式。

def find_pair(arr, tot)
  if tot.even?
    half = tot/2
    return [half, half] if arr.count(half) > 2
  end 
  a = arr.uniq.sort
  p = a.find { |n| a.bsearch { |m| m >= tot-n } }
  p ? [tot-p, p] : nil
end

find_pair(array, 10)
  #=> [8, 2]

答案 2 :(得分:1)

我可以建议一个更详细的嵌套循环,其中数组不包含负值

def find_elements(array, sum)
  array.each_with_index do |x, ix|
    next if x > sum
    array.each_with_index do |y, iy|
      next if ix == iy || y > sum
      return [x, y] if x + y == sum
    end
  end
  nil
end

如果有大套,是否更快?

编辑:在我的基准测试之后,速度与mattewd中的解决方案相当。例如100000.times{array << rand(0..100)}。它会返回另一对加数。