这种递归方法直接生成排列,而不是生成大量排列并丢弃不满足规范的排列。
代码
def all_perms(arr_size, nbr_false)
return nil if nbr_false > arr_size/2
return [true]*arr_size if nbr_false.zero?
recurse(arr_size, nbr_false, true)
end
def recurse(arr_size, nbr_false, full_arr)
last_first = arr_size + 1 - 2*nbr_false
(0..last_first).each_with_object([]) do |i,a|
pre = [true]*i << false
case nbr_false
when 1
a << pre + [true]*(arr_size-pre.size)
else
pre << true
sub_arr_size = arr_size - pre.size - (i.zero? && full_arr ? 1 : 0)
post = [true]*(arr_size-pre.size-sub_arr_size)
recurse(sub_arr_size, nbr_false-1, false).each { |aa| a << pre + aa + post }
end
end
end
示例
arr_size = 5
nbr_false = 2
b = all_perms(arr_size, nbr_false)
#=> [[false, true, false, true, true],
# [false, true, true, false, true],
# [true, false, true, false, true],
# [true, false, true, true, false],
# [true, true, false, true, false]]
b == b.uniq
#=> true
b.any? { |a| a.each_cons(2).any? { |x,y| x == false && y == false} }
#=> false
b.any? { |a| a.first == false && a.last == false }
#=> false
arr_size = 8
nbr_false = 3
b = all_perms(arr_size, nbr_false)
#=> [[false, true, false, true, false, true, true, true],
# [false, true, false, true, true, false, true, true],
# [false, true, false, true, true, true, false, true],
# [false, true, true, false, true, false, true, true],
# [false, true, true, false, true, true, false, true],
# [false, true, true, true, false, true, false, true],
# [true, false, true, false, true, false, true, true],
# [true, false, true, false, true, true, false, true],
# [true, false, true, false, true, true, true, false],
# [true, false, true, true, false, true, false, true],
# [true, false, true, true, false, true, true, false],
# [true, false, true, true, true, false, true, false],
# [true, true, false, true, false, true, false, true],
# [true, true, false, true, false, true, true, false],
# [true, true, false, true, true, false, true, false],
# [true, true, true, false, true, false, true, false]]
b == b.uniq
#=> true
b.any? { |a| a.each_cons(2).any? { |x,y| x == false && y == false} }
#=> false
b.any? { |a| a.first == false && a.last == false }
#=> false
备注
- 对于包含相同数量
false 元素的给定大小的所有数组,有效排列是相同的。因此,我将all_perms 的参数设置为所需数组的大小和它要包含的false 元素的数量(其他元素都是true)。
-
recurse 的第三个参数full_arr 是一个布尔值,当recurse 从all_perms 调用时等于true,但当recurse 从recurse 调用时等于false。这对于避免以false 开头和结尾的排列是必要的(要避免的循环条件)。当full_arr 是true 和i #=> 0 时,正在构造的子数组的最后一个元素必须是true。在所有其他情况下,它可能是true 或false。
- 索引
i 是指正在构造的第一个false 所在的子数组的索引。例如,如果arr_size #=> 4、nbr_false #=> 2 和full_arr #=> false,则第一个false 的索引i 可以是0 或1。它不能是2,因为这要求最后两个元素是false。