如何从后缀树中获取子串中最长的重复字符串

时间:2015-07-16 17:03:48

标签: string algorithm perl tree suffix-tree

我需要在子字符串中找到最长的重复字符串。我们说我有字符串"bannana"

维基百科says以下:

  

在计算机科学中,最长的重复子串问题是   找到发生在的字符串的最长子串的问题   至少两次。在图中带字符串" ATCGATCGA $",最长   重复的子串是" ATCGA"

所以我假设对于字符串"an",有两个同样长的子字符串(如果不正确我请):"na"use strict; use warnings; use Data::Dumper; sub classify { my ($f, $h) = (shift, {}); for (@_) { push @{$h->{$f->($_)}}, $_ } return $h; } sub suffixes { my $str = shift; map { substr $str, $_ } 0 .. length($str) - 1; } sub suffix_tree { return +{} if @_ == 0; return +{ $_[0] => +{} } if @_ == 1; my $h = {}; my $classif = classify sub { substr shift, 0, 1 }, @_; for my $key (sort keys %$classif) { my $subtree = suffix_tree( grep "$_", map { substr $_, 1 } @{$classif->{$key}} ); my @subkeys = keys %$subtree; if (@subkeys == 1) { my $subkey = shift @subkeys; $h->{"$key$subkey"} = $subtree->{$subkey}; } else { $h->{$key} = $subtree } } return $h; } print +Dumper suffix_tree suffixes 'bannana$';

维基百科也says为此目的使用后缀树。更具体的here是引用怎么做(这似乎比wikipedia上的定义更明白):

  

构建一个后缀树,然后找到至少为2的最高节点   后代。

我发现了几种后缀树的实现。以下代码取自here

"bannana"

对于字符串$VAR1 = { '$' => {}, 'n' => { 'a' => { 'na$' => {}, '$' => {} }, 'nana$' => {} }, 'a' => { '$' => {}, 'n' => { 'a$' => {}, 'nana$' => {} } }, 'bannana$' => {} }; ,它返回以下树:

"bannana"

另一个实现是here在线,对于字符串 7: a 5: ana 2: annana 1: bannana 6: na 4: nana 3: nnana |(1:bannana)|leaf tree:| | |(4:nana)|leaf |(2:an)| | |(7:a)|leaf | | |(4:nana)|leaf |(3:n)| | |(5:ana)|leaf 3 branching nodes ,它返回以下树:

"an"

问题:

  1. 如何从这些图表中获取"na"getdate() + 5字符串?
  2. 正如你可以看到树木是不同的,它们是否相同,如果是,为什么它们是不同的,如果不是哪种算法是正确的?
  3. 如果perl实现错误,是否有任何perl / python的工作实现?
  4. 我已经阅读了Ukkonen的算法,这个算法也在第二个例子的页面上提到过(如果在线版本是否使用这个算法我没有抓到),是否有任何提到的例子使用这个算法?如果没有,与Ukkonen相比算法使用算法更慢还是有任何缺点?

1 个答案:

答案 0 :(得分:1)

1。我如何从这些图表中获得""和" na"字符串?

  

构建一个后缀树,然后找到至少有2个后代的最高节点。

string-node是从根到此节点的每个节点的连接字符串。 highest node是最大长度为string-node的节点。

在第二个问题的答案中查看树。 (3:n)有2个后代,节点的路径为(2:a)->(3:n),连接为an。同样适用于(5:a)获取na

2。你可以看到树是不同的,它们是否相同,如果是,为什么它们是不同的,如果不是哪种算法是正确的?

这些树是不同的。为字符串"bannana$"重建第二个树( 和第一棵树一样):

 8: $
 7: a$
 5: ana$
 2: annana$
 1: bannana$
 6: na$
 4: nana$
 3: nnana$

     |(1:bannana$)|leaf
tree:|
     |     |     |(4:nana$)|leaf
     |     |(3:n)|
     |     |     |(7:a$)|leaf
     |(2:a)|
     |     |(8:$)|leaf
     |
     |     |(4:nana$)|leaf
     |(3:n)|
     |     |     |(6:na$)|leaf
     |     |(5:a)|
     |     |     |(8:$)|leaf
     |
     |(8:$)|leaf
5 branching nodes

3。如果perl实现错误,是否有任何perl / python的工作实现?

我不了解Perl,但树构建正确。

4。我已经读过Ukkonen的算法,这个算法也在第二个例子的页面上提到过(如果在线版本是否使用这个算法,我没有抓到),是否有任何一个提到的例子使用这个算法?如果没有,与Ukkonen相比,算法运算速度较慢或有任何缺点吗?

我之前说过,我不知道Perl,但它在第一个algorthim中的意思是它至少有效O(n^2)n它是长度字符串):< / p>

map { substr $str, $_ } 0 .. length($str) - 1;

Ukkonen算法的线性时间为O(n)

第一种算法也是递归的,可能会影响已用内存。