Chỉnh sửa: Tôi rất tiếc vì đã xảy ra lỗi. Điều đáng tiếc của tôi rằng tôi giám sát việc sử dụng biến số my
bên trong countit(x, q{})
là sai lầm lớn. Chuỗi này được đánh giá bên trong mô-đun Điểm chuẩn và @str bị bỏ trống ở đó. Giải pháp này không nhanh như tôi đã trình bày. Xem chỉnh sửa bên dưới. Tôi xin lỗi lần nữa.
Perl có thể được nhanh chóng:
use strict;
use warnings;
package LCP;
sub LCP {
return '' unless @_;
return $_[0] if @_ == 1;
my $i = 0;
my $first = shift;
my $min_length = length($first);
foreach (@_) {
$min_length = length($_) if length($_) < $min_length;
}
INDEX: foreach my $ch (split //, $first) {
last INDEX unless $i < $min_length;
foreach my $string (@_) {
last INDEX if substr($string, $i, 1) ne $ch;
}
}
continue { $i++ }
return substr $first, 0, $i;
}
# Roy's implementation
sub LCP2 {
return '' unless @_;
my $prefix = shift;
for (@_) {
chop $prefix while (! /^\Q$prefix\E/);
}
return $prefix;
}
1;
Kiểm tra bộ:
#!/usr/bin/env perl
use strict;
use warnings;
Test::LCP->runtests;
package Test::LCP;
use base 'Test::Class';
use Test::More;
use Benchmark qw(:all :hireswallclock);
sub test_use : Test(startup => 1) {
use_ok('LCP');
}
sub test_lcp : Test(6) {
is(LCP::LCP(), '', 'Without parameters');
is(LCP::LCP('abc'), 'abc', 'One parameter');
is(LCP::LCP('abc', 'xyz'), '', 'None of common prefix');
is(LCP::LCP('abcdefgh', ('abcdefgh') x 15, 'abcdxyz'),
'abcd', 'Some common prefix');
my @str = map { chomp; $_ } <DATA>;
is(LCP::LCP(@str),
'file:///home/gms8994/Music/', 'Test data prefix');
is(LCP::LCP2(@str),
'file:///home/gms8994/Music/', 'Test data prefix by LCP2');
my $t = countit(1, sub{LCP::LCP(@str)});
diag("LCP: ${\($t->iters)} iterations took ${\(timestr($t))}");
$t = countit(1, sub{LCP::LCP2(@str)});
diag("LCP2: ${\($t->iters)} iterations took ${\(timestr($t))}");
}
__DATA__
file:///home/gms8994/Music/t.A.T.u./
file:///home/gms8994/Music/nina%20sky/
file:///home/gms8994/Music/A%20Perfect%20Circle/
Kiểm tra bộ kết quả:
1..7
ok 1 - use LCP;
ok 2 - Without parameters
ok 3 - One parameter
ok 4 - None of common prefix
ok 5 - Some common prefix
ok 6 - Test data prefix
ok 7 - Test data prefix by LCP2
# LCP: 22635 iterations took 1.09948 wallclock secs (1.09 usr + 0.00 sys = 1.09 CPU) @ 20766.06/s (n=22635)
# LCP2: 17919 iterations took 1.06787 wallclock secs (1.07 usr + 0.00 sys = 1.07 CPU) @ 16746.73/s (n=17919)
Điều đó có nghĩa rằng giải pháp Perl tinh khiết sử dụng substr
là khoảng 20% nhanh hơn hơn Roy's solution trong trường hợp thử nghiệm của bạn và một lần tìm kiếm tiền tố mất khoảng 50us. Không cần sử dụng XS trừ khi dữ liệu của bạn hoặc kỳ vọng hiệu suất lớn hơn.
Liệu sự tương tự phải bắt đầu ở đầu chuỗi? Nếu vậy, thật dễ dàng để giải quyết. Nếu không, nó hơi phức tạp hơn. – cletus
ditto truy vấn đó - và tôi sẽ thêm - bằng 'tương tự' có nghĩa là 'chính xác' không? –
Sự cố bạn đang trình bày không rõ ràng. Đầu tiên, có nghĩa là tương tự chính xác. Ngoài ra, ví dụ, nếu 10 chuỗi là phổ biến cho 15 ký tự đầu tiên, 5 chuỗi khác trong số 10 chuỗi này là phổ biến cho thêm 7 ký tự khác, bạn muốn sửa lỗi nào trước? –