如何创建一个Perl子例程,该子例程将接收一个数组并找到2个或更多元素的最长公共前缀? (字符串)
我有这段代码:
sub longest_common_prefix {
$prefix = shift;
for (@_) {
chop $prefix while (! /^\Q$prefix\E/);
}
return $prefix;
}
但只有在您寻找所有字符串的最长公共前缀时,它才有效。
例如,如果我传递一个包含以下字符串的数组:
aaaBGFB
aaaJJJJ
jjfkBBB
aaaHGHG
我希望它返回aaa
作为答案。
谢谢!
答案 0 :(得分:5)
我使用修改后的trie。
通常,可以使用以下内容添加到trie:
sub add {
my $p = \shift;
my $s = shift;
$p = \( $$p->{$_} ) for split(//, $s);
$$p->{''} = 1;
}
但我们需要两次修改:
abc
也应该将a
和ab
添加到特里。所以我们需要:
sub add {
my $p = \shift;
my $s = shift;
my $cp_len = 0;
for (split(//, $s)) {
$p = \( $$p->{$_} );
++$cp_len if $$p->{$_}{''};
$$p->{''} = 1;
}
return $cp_len;
}
将此算法(与其优化版本)结合使用算法以查找列表中最长的字符串,并使用算法从列表中删除重复的字符串以获得以下解决方案:
use strict;
use warnings;
use feature qw( say );
sub add {
my $p = \shift;
my $s = shift;
my $cp_len = 0;
for (split(//, $s)) {
++$cp_len if exists($$p->{$_});
$p = \( $$p->{$_} );
}
return $cp_len;
}
my $t;
my $lcp_len = 0; # lcp = longest common prefix
my %lcps;
while (<>) {
chomp;
my $cp_len = add($t, $_)
or next;
if ($cp_len >= $lcp_len) {
if ($cp_len > $lcp_len) {
$lcp_len = $cp_len;
%lcps = ();
}
$lcps{ substr($_, 0, $cp_len) } = 1;
}
}
my @lcps = sort keys %lcps;
if (@lcps) {
say "Longest common prefix(es): @lcps";
} else {
say "No common prefix";
}
数据:
abc
abc
abcd
abcde
hijklx
hijkly
mnopqx
mnopqy
输出:
Longest common prefix(es): hijkl mnopq
上述时间与输入字符数成正比。
答案 1 :(得分:0)
一种方法是将信息存储在散列中。在此示例中,我将散列键设置为每个前缀的长度,并且值是找到的实际前缀。
请注意,如果存在相同长度的前缀,此方法将覆盖键和值,因此您始终可以获得最长的 last 前缀(sort()
处理找到最长的一个)。
正则表达式说“找到字符串中的第一个字符并捕获它,并使用在第二次捕获中找到的字符,并捕获尽可能多的字符”。然后将此字符串join()
编入标量并放入哈希值。
use warnings;
use strict;
my %prefixes;
while (<DATA>){
my $prefix = join '', /^(.)(\1+)/;
$prefixes{length $prefix} = $prefix;
}
my $longest = (sort {$b <=> $a} keys %prefixes)[0];
print "$prefixes{$longest}\n";
__DATA__
aaBGFB
aaaJJJJ
jjfkBBB
aaaHGHG
输出:
aaa
答案 2 :(得分:0)
您可以保留由第一个字符键入的单词数组的哈希值。根据定义,如果您有以相同字母开头的单词,则这些单词至少共享该单个字母的一个字符共同前缀。然后通过按字符逐步遍历来减少到单个最长前缀:
use strict; use warnings;
sub lcp {
(join("\0", @_) =~ /^ ([^\0]*) [^\0]* (?:\0 \1 [^\0]*)* $/sx)[0];
}
my %HoA;
my $longest='';
while (my $line=<DATA>){
$line =~ s/^\s+|\s+$//g ;
push @{ $HoA{substr $line, 0, 1} }, $line if $line=~/^[a-zA-Z]/;
}
for my $key ( sort (keys %HoA )) {
if (scalar @{ $HoA{$key} } > 1){
my $lon=lcp(@{ $HoA{$key} });
my $s = join ', ', map { qq/"$_"/ } @{ $HoA{$key} };
print "lcp: \"$lon\" for ($s)\n";
if (length($lon) > length($longest)) {
$longest=$lon;
}
}
else{
print "$key: no common prefix\n";
}
}
print "\nlongest common prefix is \"$longest\"\n";
__DATA__
aardvark
aaaBGFB
aaaJJJJ
jjfkBBB
aaaHGHG
interspecies
interstellar
interstate
打印:
lcp: "aa" for ("aardvark", "aaaBGFB", "aaaJJJJ", "aaaHGHG")
lcp: "inters" for ("interspecies", "interstellar", "interstate")
j: no common prefix
longest common prefix is "inters"