如何提高嵌套循环的算法效率

时间:2018-10-25 05:05:12

标签: ruby algorithm loops iteration

给出一个整数列表和一个总和值,返回前两个值(从左开始),它们加起来形成总和。

例如,给定:

sum_pairs([10, 5, 2, 3, 7, 5], 10)

[5, 5](在[1, 5]的索引[10, 5, 2, 3, 7, 5]处)总计10[3, 7](在索引[3, 4]处)总计10。其中,整个[3, 7]对都比较早,因此是正确的答案。

这是我的代码:

def sum_pairs(ints, s)
  result = []
  i = 0
  while i < ints.length - 1
    j = i+1
    while j < ints.length
      result << [ints[i],ints[j]] if ints[i] + ints[j] == s
      j += 1
    end
    i += 1
  end
  puts result.to_s
  result.min
end

它可以工作,但是效率太低,需要12000毫秒才能运行。嵌套循环是效率低下的问题。我该如何改善算法?

4 个答案:

答案 0 :(得分:6)

  • 您有Set个数字,从空开始
  • 查看输入列表中的每个数字
  • 计算您需要添加到哪个数字以构成总和
  • 查看该号码是否在集合中
  • 如果是,请返回它,并返回当前元素
  • 如果没有,则将当前元素添加到集合中,然后继续循环
  • 当循环结束时,您确定没有这样的配对。该任务未指定,但是返回nil可能是最佳选择

应该超快,因为只有一个循环。一旦找到第一个匹配对,它也会终止,因此通常在得到答案之前,您甚至不会遍历每个元素。

作为一种风格,以这种方式使用while是非常不符合Ruby的。在实施上述操作时,建议您使用ints.each do |int| ... end而不是while

编辑:正如Cary Swoveland所评论的那样,出于一种奇怪的原因,我认为您需要索引,而不是值。

答案 1 :(得分:4)

require 'set'

def sum_pairs(arr, target)
  s = Set.new
  arr.each do |v|
    return [target-v, v] if s.include?(target-v)
    s << v
  end
  nil
end

sum_pairs [10, 5, 2, 3, 7, 5], 10
  #=> [3, 7]
sum_pairs [10, 5, 2, 3, 7, 5], 99
  #=> nil

我使用了Set方法来加快include?的查找速度(而且,次要的是,仅保存唯一的值)。

答案 2 :(得分:1)

请尝试以下操作,因为它更具可读性。

def sum_pairs(ints, s)
  ints.each_with_index.map do |ele, i|
    if ele < s
      rem_arr = ints.from(i + 1)
      rem = s - ele
      [ele, rem] if rem_arr.include?(rem)
    end
  end.compact.last
end

答案 3 :(得分:0)

一支班轮(最快?)

ary = [10, 0, 8, 5, 2, 7, 3, 5, 5]
sum = 10

def sum_pairs(ary, sum)
  ary.map.with_index { |e, i|  [e, i] }.combination(2).to_a.keep_if { |a| a.first.first + a.last.first == sum }.map { |e| [e, e.max { |a, b| a.last <=> b.last }.last] }.min { |a, b| a.last <=> b.last }.first.map{ |e| e.first }
end

是的,它不是很可读,但是如果您从ary.map.with_index { |e, i| [e, i] }开始逐步添加方法,就很容易理解它的工作原理。