在Ruby中求和数组元素

时间:2015-12-31 03:03:44

标签: arrays ruby

Coderbyte中的练习应该确定数组中某些整数的子集是否与数组中的最大数相加。

以下代码似乎可以在我的计算机上运行,​​但是当我在线提交时,它似乎会导致无休止的循环。 (无论传递的参数如何,都没有任何输出。)

def arr_add?(arr)
  a = arr.sort
  lgst = a.pop
  size = a.size
  result = false
  while size > 1
    a.combination(size) {|c| result |= (c.inject {|r, a| r + a} == lgst)}
    size -= 1
  end
  result.to_s
end

arr_add?([1, 2, 3, 4, 10, 14])

为什么会出现这种情况?

2 个答案:

答案 0 :(得分:2)

我怀疑你实际上正在进入无限循环,而是因为你的算法效率低下,所以只需要花费很长时间

def ArrayAdditionI(arr)
  arr_size         = arr.size
  ary              = arr.sort
  largest          = ary.pop
  ary_size         = arr_size - 1
  combination_size = ary_size
  result           = false

  while combination_size > 1
    ary.combination(combination_size) {|combination| 
      result |= (combination.inject( 
        :+
      ) == largest)
    }
    combination_size -= 1
  end
  result.to_s
end

我引入了一个新变量并重命名了其他变量,以便更容易讨论该算法。我也重新格式化了它,使三个嵌套的#34;循环"更明显。

让我们来看看算法。

外部while循环执行ary_size - 1 == arr_size - 2次,combination_size范围从2ary_size == arr_size - 1

combination"循环"执行 ary_size choose combination_size 次,这是一个非常快速增长的数字。

最里面的"循环" (由combination.inject执行的操作)执行combination_size - 1次。

这给出了最内部操作的总执行次数:

  • 2arr_size - 1的总和
  • arr_size - 1选择combination_size
  • combination_size - 1

在Wolfram语言中,Wolfram Alpha告诉我们的Sum[Binomial[a-1, c]*(c-1), c, 2, a-1]2^(a-2) (a-3)+1,它位于O(2 ^ n)。

稍微使用数字:

  • 对于10个项目,我们执行了inject操作
  • 的1793次
  • 15项,我们已经有98 305
  • 20项,我们有4 456 449
  • 在28项中,我们越过门槛达到十亿次操作:1 677 721 601
  • 1000件物品,我怀疑CoderBytes可能会使用一些合理的输入尺寸,我们有2 670 735 203 411 771 297 463 949 434 782 054 512 824 301 493 176 042 516 553 547 843 013 099 994 928 903 285 314 296 959 198 121 926 383 029 722 247 001 218 461 778 959 624 588 092 753 669 155 960 493 619 769 880 691 017 874 939 573 116 202 845 311 796 007 113 080 079 901 646 833 889 657 798 860 899 142 814 122 011 828 559 707 931 456 870 722 063 370 635 289 362 135 539 416 628 419 173 512 766 291 969操作。糟糕。

尝试使用长度为5,10,15(所有瞬间),20(明显停顿),然后是23,24,25的数组的算法,以便快速感受如何运行时间增长。

假设您可以构建一个可以在单个指令中执行内部循环的CPU。进一步假设单个指令仅采用普朗克时间单位(即,CPU具有大约2000亿000 000 000 000 000 THz的频率)。进一步假设可观察宇宙中的每个粒子都是这样的CPU。对于甚至500个项目的数组执行算法,仍然需要超过当前的宇宙年龄。

请注意,对于大多数这些编程难题,它们不是实际编程难题,它们是数学难题。他们通常需要数学洞察力,以便能够有效地解决它们。或者,在这种情况下,识别它是Subset sum problem,已知它是NP完全的。

顺便说一句,作为一种风格问题,这里是用惯用Ruby风格编写的算法(略有不同)。正如您所看到的,在惯用的Ruby中,它几乎成为英语问题语句到代码的1:1翻译。

虽然它渐渐地和你的算法一样低效,但是一旦答案是true,它就会提前中断(与你的不同,即使它已经找到了解决方案,它也会继续运行)。 (any?会自动为您执行此操作。)

def ArrayAdditionI(arr)
  largest = arr.delete_at(arr.index(arr.max))
  1.upto(arr.size).any? {|combination_size|
    arr.combination(combination_size).any? {|combination|
      combination.inject(:+) == largest
    }
  }.to_s
end

这是对(不清楚)问题陈述的另一种解释:

def ArrayAdditionI(arr)
  2.upto(arr.size).any? {|combination_size|
    arr.combination(combination_size).any? {|combination|
      combination.inject(:+) == arr.max
    }
  }.to_s
end

答案 1 :(得分:0)

上面的代码是有效的ruby代码。

结果是“真实”。

这有点不寻常,因为while循环有点罕见,但是因为它是有效的ruby代码,所以它也可以在远程站点上运行。

联系在Coderbyte运行在线红宝石翻译的人 - 他们的版本似乎与MRI红宝石不兼容。

你的代码似乎倒数了;或许看看10.downto(1) - 适当地替换变量。