如何在ruby中生成部分重复的排列?

时间:2015-09-18 06:54:07

标签: ruby algorithm permutation

我有一系列数字R = (1..n)。我还有另一个角色'a'。我想生成长度为L(L> n + 2)的字符串,其中所有数字的顺序相同,但要经过'a'的每个重复排列以填充长度L.例如,如果n = 3L = 7,那么一些有效的字符串将是:

"123aaaa",
"1a23aaa",
"1aa2a3a",
"aaaa123"

而以下字符串无效:

"213aaaa", # invalid, because 1,2,3 are not in order
"123a", #invalid, because length < L
"1123aaa", # invalid because a number is repeated

我目前正在这样做,效率太低:

n = 3
L = 7
all_terms = (1..n).to_a + Array.new(L - n, 'a')
all_terms.permutation.each do |permut|
  if(valid_permut? permut) # checks if numbers are in their natural order
    puts permut.join
  end
end

如何更有效地直接生成有效字符串?

2 个答案:

答案 0 :(得分:4)

问题相当于:从索引n0选择L - 1元素,相应地将1填充到n,然后填写其余内容有一些恒定的性格。

在您的示例中,它从3中获取0..6个元素:

(0..6).to_a.combination(3).to_a
 => [[0, 1, 2], [0, 1, 3], [0, 1, 4], [0, 1, 5], [0, 1, 6], [0, 2, 3], [0, 2, 4],
 [0, 2, 5], [0, 2, 6], [0, 3, 4], [0, 3, 5], [0, 3, 6], [0, 4, 5], [0, 4, 6], [0, 5, 6], 
 [1, 2, 3], [1, 2, 4], [1, 2, 5], [1, 2, 6], [1, 3, 4], [1, 3, 5], [1, 3, 6], [1, 4, 5],
 [1, 4, 6], [1, 5, 6], [2, 3, 4], [2, 3, 5], [2, 3, 6], [2, 4, 5], [2, 4, 6], [2, 5, 6],
 [3, 4, 5], [3, 4, 6], [3, 5, 6], [4, 5, 6]]

此处的每个子阵列都代表可能的结果。例如,[0, 2, 3]对应'0a12aaa'[3, 5, 6]对应'aaa0a12',等等。此转换的代码是直截了当的。

答案 1 :(得分:2)

您可以将其建模为两个字符串的所有可能交错,其中保留输入元素的相对顺序。这是一个递归解决方案。它的工作原理是从一个列表中选择一个元素,然后将其添加到所有可能的子问题中,然后再次从第二个列表中选择一个元素,并在最后组合两个解决方案集。

# Returns an array of all possible interleaving of two strings
# Maintains relative order of each character of the input strings
def interleave_strings_all(a1, a2)
    # Handle base case where at least one input string is empty
    return [a1 + a2] if a1.empty? || a2.empty?

    # Place element of first string, and prepend to all subproblems
    set1 = interleave_strings_all(a1[1..-1], a2).map{|x| a1[0] + x}
    # Place element of second string and prepend to all subproblems
    set2 = interleave_strings_all(a1, a2[1..-1]).map{|x| a2[0] + x}

    # Combine solutions of subproblems into overall problem
    return set1.concat(set2)    
end


if __FILE__ == $0 then
    l = 5
    n = 3
    a1 = (1..n).to_a.map{|x| x.to_s}.join()
    a2 = 'a' * (l - n)
    puts interleave_strings_all(a1, a2)
end

输出是:

 123aa
 12a3a
 12aa3
 1a23a
 1a2a3
 1aa23
 a123a
 a12a3
 a1a23
 aa123