问题:
我想在lexigraphical中生成一个字符串排列列表,但不包括字符串反转。例如,如果我有以下字符串:abc,我想生成以下列表
abc
acb
bac
而不是典型的
abc
acb
bac
bca
cab
cba
另一个例子看起来像这样:
100
010
而不是
100
010
001
目前,我可以使用perl生成排列,但我不确定如何最好地删除反向重复项。
我曾想过应用以下内容:
create map with the following:
1) 100
2) 010
3) 001
then perform the reversion/inversion on each element in the map and create a new map with:
1') 001
2') 010
3') 100
然后进行比较,如果引用的列表值与原始值匹配,则将其保留在原位,如果它不同,如果它的索引大于中位数索引,则保留它,否则删除。
麻烦的是,我不确定这是否是一种有效的方法。
任何建议都会很棒。
答案 0 :(得分:0)
建议的重复command substitution中的答案并不处理重复的元素(因为那不是该问题的一部分),所以天真地跟随它会包括例如0100和0010.所以这不是完全重复的。但这个想法适用。
生成所有排列,但只对具有$_ le reverse $_
的排名进行过滤。我认为这基本上就是你在问题中的建议,但当应用于每个排列的简单表达式告诉你是否包含它时,不需要计算地图。
答案 1 :(得分:0)
示例表示的两种可能性是所有元素不同的排列(abcd
),或两个符号的变体,其中一个恰好出现一次(1000
)。更一般的案例也得到了解决。
非重复元素(排列)
在这里,我们可以使用Algorithm::Permute,以及特定观察: 第一个元素大于最后一个元素的每个排列都需要排除。它来自this post,在answer by ysth中出现。
此规则如下所示。考虑没有第一个和最后一个元素的字符串的子字符串。对于每个这样的子字符串,字符串的所有排列必须包含其反转。其中一个用最后一个和第一个填充,因此是字符串的反转。通过构造,对于每个子串,恰好有一个逆。因此,需要排除每个字符串交换的第一个和最后一个元素的排列。
use warnings;
use strict;
use feature 'say';
use Algorithm::Permute;
my $size = shift || 4;
my @arr = ('a'..'z')[0..$size-1]; # 1..$size for numbers
my @res;
Algorithm::Permute::permute {
push @res, (join '', @arr) unless $arr[0] gt $arr[-1]
} @arr;
say for @arr;
带有重复元素 (abbcd
)的问题可以用与上面完全相同的方式处理,我们还需要修剪重复项作为b
生成{{1}的排列}和abbcd
(相同)
abbcd
在施工期间这样做不会降低复杂性,也不会加快速度。
到目前为止,use List::MoreUtils 'uniq';
# build @res the same way as above ...
my @res = uniq @res;
被引用为模块中最快的方法。它比我测试的其他模块(下图)快一个数量级,在我的系统上为10个元素花费大约1秒。但请注意,此问题的复杂性在于 factorial 的大小。它爆炸得非常快。
两个符号,其中一个符号恰好出现一次(变体)
这是不同的,上述模块不适用于此,排除标准也不起作用。还有其他模块,最后见。但是,这里的问题很简单。
从列表中的permute
和'walk'(1,0,0,...)
开始,一直到“midpoint” - 这是偶数列表的一半(4-for 8-long),或者是下一半奇数尺寸(5长9长)。以这种方式获得的所有字符串,通过将1
移动一个位置直到中点,形成集合。第二个“半”是他们的反转。
1
我们需要在最后一个索引之前停止,因为它已在上一次迭代中填充。
如果两个符号(use warnings;
use strict;
my $size = shift || 4;
my @n = (1, map { 0 } 1..$size-1);
my @res = (join '', @n); # first element of the result
my $end_idx = ( @n % 2 == 0 ) ? @n/2 - 1 : int(@n/2);
foreach my $i (0..$end_idx-1) # stop one short as we write one past $i
{
@n[$i, $i+1] = (0, 1); # move 1 by one position from where it is
push @res, join '', @n;
}
print "$_\n" for @res;
)可能重复出现,则可以修改此项,但使用模块然后排除反转更简单。 Algorithm::Combinatorics具有满足所有需求的例程。对于长度0,1
的{{1}}和0
的所有变体,两者都可以重复
1
然后可以通过强力搜索排除反向元素,最坏情况下 O(N 2 )复杂度。
另请注意Math::Combinatorics。