我是编程新手,也是Ruby新手。我在业余时间处理这个问题,因为我刚接触ruby并且很难让我的代码遍历每个创建的子集。
这是我的代码:
#Given a set of integers, and a value sum, i.e. value sum of 0
#determine if there is a subset of the given set with sum equal to given sum.
class Array
def SubSetSumtoZero
if self.collect{|sum,x| sum + x == 0}
detected = self.select {|sum,x| sum + x == 0}
puts "\r\n #{detected} Sums to Zero \r\n"
else self.collect{|sum,x| sum + x -= 0}
notdetected = self.select {|sum, x| sum + x -= 0}
puts "\r\n#{notdetected} Does not sum to Zero\r\n"
end
end
end
originalSet = [-9, -7, -2, 2, 7, 9]
arr = []
for i in 2..(originalSet.length) do
arr = arr + originalSet.combination(i).to_a
arr.SubSetSumtoZero
end
以下是我的结果:
[[-9, 9], [-7, 7], [-2, 2]] Sums to Zero
[[-9, 9], [-7, 7], [-2, 2], [-7, 7, 9], [-2, 2, 7], [-2, 2, 9]] Sums to Zero
[[-9, 9], [-7, 7], [-2, 2], [-7, 7, 9], [-2, 2, 7], [-2, 2, 9], [-2, 2, 7, 9]] Sums to Zero
[[-9, 9], [-7, 7], [-2, 2], [-7, 7, 9], [-2, 2, 7], [-2, 2, 9], [-2, 2, 7, 9]] Sums to Zero
[[-9, 9], [-7, 7], [-2, 2], [-7, 7, 9], [-2, 2, 7], [-2, 2, 9], [-2, 2, 7, 9]] Sums to Zero
[Finished in 0.1s]
我知道在某些时候整个阵列总和为零。任何想法为什么会发生这种情况?
答案 0 :(得分:3)
我知道你特意要求一个递归解决方案,但是由于@hjing提供了一个解决方案,我想通过使用Ruby&的强大内置方法向您展示如何以更紧凑和直接的方式回答您的问题。 #39; s Enumerable
模块和Array
类。
<强>代码强>
def find_it(array, tot)
(1..array.size).each_with_object([]) { |n,arr|
array.combination(n).each { |a| arr << a if a.reduce(:+) == tot } }
end
示例强>
find_it([-9, -7, -2, 2, 7, 9], 0) #=> [-9, 9]
#=> [[-9, 9], [-7, 7], [-2, 2],
# [-9, 2, 7], [-7, -2, 9],
# [-9, -7, 7, 9], [-9, -2, 2, 9], [-7, -2, 2, 7],
# [-9, -7, -2, 2, 7, 9]]
<强>解释强>
array = [-9, -7, -2, 2, 7, 9]
tot = 0
r = 1..array.size #=> 1..6 (Range object)
此范围的每个值都是要考虑的子集的大小。我们将首先检查大小为1的子集,然后检查大小为2的子集,依此类推,直到大小为6的子集,其中只有一个(array
)。
enum1 = r.each_with_object([]) # => #<Enumerator: 1..6:each_with_object([])>
要查看枚举器enum1
将传递给其块的值,我们可以将其转换为数组:
enum1.to_a #=> [[1, []], [2, []], [3, []], [4, []], [5, []], [6, []]]
Enumerable#each_with_object创建一个最初为空的数组,由块变量arr
表示。第一个值enum
传递给它的块是数组[0, []]
,导致块变量按如下方式分配:
n => 1
arr => []
enum2 = array.combination(n) #=> array.combination(1)
#=> #<Enumerator: [-9, -7, -2, 2, 7, 9]:combination(1)>
此处Array#combination生成array
中一个元素的所有组合。因此,enum2
会将以下元素传递给其块:
enum2.to_a
#=> [[-9], [-7], [-2], [2], [7], [9]]
第一个元素enum2
传递给它的块是[-9]
,导致bloc块变量被赋值如下:
a => [-9]
所以块表达式变为:
arr << a if a.reduce(:+) == tot #=> arr << [-9] if [-9].reduce(:+) == 0
Enumerable#reduce(aka,inject
)带有参数:+
(加法)只是对其接收器[-9]
的元素求和,显然是{{1} }。由于-9
,-9 != 0
未附加到[-9]
。显然,唯一包含总和为零的单个元素的数组是arr
,但该示例中不存在该数组。因此,[0]
枚举其所有元素后,arr
仍为空。
enum2
现在将元素enum1
传递给它的块,将块变量设置为:
[2, []]
导致:
n => 2
arr => []
我们发现元素enum2 = array.combination(n) #=> array.combination(2)
#=> #<Enumerator: [-9, -7, -2, 2, 7, 9]:combination(2)>
enum2.to_a
#=> [[-9, -7], [-9, -2], [-9, 2], [-9, 7], [-9, 9], [-7, -2], [-7, 2],
# [-7, 7], [-7, 9], [-2, 2], [-2, 7], [-2, 9], [ 2, 7], [ 2, 9], [7, 9]]
,[-9, 9]
和[-7, 7]
各自为零,因此[-2, 2]
变为:
arr
在枚举了两个元素的所有组合之后。考虑下三种组合,依此类推。
答案 1 :(得分:2)
一个简单的递归解决方案是编写一个计算数组powerset的函数。然后,选择powerset中满足所需谓词的所有元素。
示例实现:
def powerset(array)
if array.empty?
[[]]
else
first_elem, *rest_elems = array
subsets = []
powerset(rest_elems).each do |subset|
subsets.push(subset)
subsets.push(subset.clone.push(first_elem))
end
subsets
end
end
def sums_to_zero?(array)
array.reduce(0, :+) == 0
end
def subsets_that_sum_to_zero(array)
powerset(array).select { |subset| sums_to_zero?(subset) }
end
original_set = [-9, -7, -2, 2, 7, 9]
subsets_that_sum_to_zero(original_set).each do |subset|
puts "The subset #{subset} sums to zero!"
end
# The subset [] sums to zero!
# The subset [2, -2] sums to zero!
# The subset [7, -7] sums to zero!
# The subset [7, 2, -9] sums to zero!
# The subset [7, 2, -2, -7] sums to zero!
# The subset [9, -9] sums to zero!
# The subset [9, -2, -7] sums to zero!
# The subset [9, 2, -2, -9] sums to zero!
# The subset [9, 7, -7, -9] sums to zero!
# The subset [9, 7, 2, -2, -7, -9] sums to zero!
有关powerset算法的解释,请参阅wikipedia。
答案 2 :(得分:0)
这是零和的直接递归解决方案:
def find_subsets(arr)
return arr if arr.empty?
result = (0...arr.length).flat_map do |i|
find_subsets(arr[0...i] + arr[i+1..-1])
end
result << arr if arr.inject(:+) == 0
result.uniq
end
它收集了从数组中删除单个元素的所有结果(这是递归),如果它符合要求(总和为零),则将数组本身添加到其中。
它不是最有效的解决方案,因为它可能重复来自多个路径的子阵列的计算(这就是为什么最后一行uniq
的结果) - 但这是最简单的实现。