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

How to generate partially repeated permutations in ruby?

我有一个数字范围 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

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

问题等价于:select n 个索引 0L - 1 的元素,用 1n 填充这些元素相应地,并用一些常量字符填充其余部分。

在您的示例中,它从 0..6:

中获取 3 个元素
(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',等等。这种转换的代码很简单。

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

# 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__ == [=10=] 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