Если я правильно понимаю алгоритм и вы хотите вычислить сумму самых длинных общих префиксов, ваша реализация неверна, поскольку вам не хватает восходящей лексикографической сортировки.
Вот один из способов решения вашей проблемы:
#!/usr/bin/perl
use strict;
use warnings;
chomp(my $ipstr = <>);
my @subipstrs = map [split//], sort map{substr $ipstr, $_} 0 .. length($ipstr) - 1;
my $sum = 0;
for my $i (1 .. $#subipstrs) {
my @last = @{$subipstrs[$i-1]};
my @this = @{$subipstrs[$i]};
my $j = 0;
$sum++ while $j < @last && $j < @this && $last[$j] eq $this[$j++];
}
Для строки примера ababaa
в вопросе, на который вы ссылаетесь, будет получен массив суффиксов
5 | a
4 | aa
2 | abaa
0 | ababaa
3 | baa
1 | babaa
представлен @subipstrs
@subipstrs = (
['a'],
['a', 'a'],
['a', 'b', 'a', 'a'],
['a', 'b', 'a', 'b', 'a', 'a'],
['b', 'a', 'a'],
['b', 'a', 'b', 'a', 'a']
);
Это делает вычисление lcp
s вопросом сравнения соседнего массива refs элемент за элементом, пока пары совпадают, и суммирования общего количества совпадений. Результат
5 | a | 0
4 | aa | 1
2 | abaa | 1
0 | ababaa | 3
3 | baa | 0
1 | babaa | 2
Всего 7 , а не 11.
РЕДАКТИРОВАТЬ: Это решает проблему, в которой вы заинтересованы:
#!/usr/bin/perl
use strict;
use warnings;
chomp(my $ipstr = <>);
my $len = my $sum = length($ipstr);
for my $i (1 .. $len -1) {
my $substr = substr $ipstr, $i;
chop $substr while $substr ne substr $ipstr, 0, length($substr);
$sum += length($substr);
}
И это немного быстрее, чем ваше решение с примером строки и 1M итераций:
trinity 80906/s -- -32%
flesk 119332/s 47% --
EDIT2: Это быстрее, потому что оно работает с самого начала строк и может быстрее отбрасывать отрицательные совпадения:
#!/usr/bin/perl
use strict;
use warnings;
chomp(my $ipstr = <>);
my $len = my $sum = length($ipstr);
for my $i (1 .. $len - 1) {
my $ipstrcopy = reverse $ipstr;
my $substr = reverse substr $ipstr, $i;
my ($slen, $j) = (length($substr), 0);
$sum++ while $j++ <= $slen && chop $ipstrcopy eq chop $substr;
}
ababaa
и 100 000 итераций:
trinity 81967/s -- -24%
flesk 107527/s 31% --
abcdefghijklmnopqrstuvwxyz
и 100 000 итераций:
trinity 26178/s -- -15%
flesk 30769/s 18% --
aaaaaaaaaaabbbaaaaaaaaaaaaaaaabbbaaaaaaaaa
и 100K итераций:
trinity 5435/s -- -30%
flesk 7800/s 44% --
Алгоритм, вероятно, можно улучшить, изменив $ipstr
перед циклом или просто используя substr
s вместо chop
.