Chinaunix首页 | 论坛 | 博客
  • 博客访问: 470177
  • 博文数量: 142
  • 博客积分: 4126
  • 博客等级: 上校
  • 技术积分: 1545
  • 用 户 组: 普通用户
  • 注册时间: 2008-02-22 10:03
文章分类

全部博文(142)

文章存档

2011年(8)

2010年(7)

2009年(64)

2008年(63)

我的朋友

分类:

2008-12-14 22:43:24

自己用perl写的一个lcs(最大公共子串)算法的程序:

我这个算法,用的是一个比较老套的lcs算法。以前用c写过,在perl下又模仿实现了一下。

算法大概描述就是,分别用两个字符串作为横坐标和纵坐标建一个矩阵,遇到横竖字符相同的时候把这点的值设成1,否则设成零,最后矩阵中最长的不为零的对角线就是最大子字串。
例如:

m a c h i
a 0 1 0 0 0
b 0 0 0 0 0
m 1 0 0 0 0
a 0 1 0 0 0
c 0 0 1 0 0



这样有点问题:建完矩阵还要去找最长对角线,麻烦。
解决方案是:相等时不只把矩阵元素设为“1”,而是设成它左上角的元素值加一。
例如:
m a c h i
a 0 1 0 0 0
b 0 0 0 0 0
m 1 0 0 0 0
a 0 2 0 0 0
c 0 0 3 0 0


所以矩阵建好后,找到矩阵中最大的元素就ok了。

#!/usr/bin/perl

sub max_mutual_str {
  my($str1,$str2) = @_;
  my %cmp;
  my $max;
  my @list1=split '',$str1;
  my @list2=split '',$str2;
  for my $i (0..$#list1) {

    for my $j (0..$#list2) {

       $cmp{$i.$j}=($list1[$i] eq $list2[$j]) ? (1+$cmp{($i-1).($j-1)}) : 0;
       $max=$cmp{$i.$j} if ($cmp{$i.$j}>$max);
       print "$cmp{$i.$j}";
    }
    print "\n";
  }
  for (keys %cmp){
      if ($cmp{$_} == $max ){
         my $offset=substr($_,0,1)+1-$max;
         return substr($str1,$offset,$max);
      }
  }
}

my ($str1,$str2) = @ARGV;
my $str= max_mutual_str($str1,$str2);
print "$str\n";

后来发现,既然都找到最大的公共字符串了,干嘛还要在遍历一遍散列呢,真的够傻的,惭愧啊:

 

#!perl


sub max_mutual_str {
  my($str1,$str2) = @_;
  my %cmp;
  my $max;
  my $beginning_station; #beginning station of the common string in $str1

  my @list1=split '',$str1;
  my @list2=split '',$str2;
  for my $i (0..$#list1){
    for my $j (0..$#list2){
  $cmp{$i.$j}=($list1[$i] eq $list2[$j]) ? (1+$cmp{($i-1).($j-1)}) : 0;
        if ($cmp{$i.$j}>$max){
           $max=$cmp{$i.$j};
           $beginning_station=$i+1-$max;
         }
       print "$cmp{$i.$j}";
    }
    print "\n";
  }

  return substr($str1,$beginning_station,$max);

}

my ($str1,$str2) = @ARGV;
my $str= max_mutual_str($str1,$str2);
print "$str\n";

阅读(1267) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~