最短摘要生成与多模式匹配(一)

原文地址:http://yishan.cc/blogs/gpww/archive/2009/12/31/1338.aspx

这是一个系列 非常好!!

最短摘要生成与多模式匹配(一)

问题

《编程之美》有一道题目“最短摘要生成”:若输入“微软 亚洲研院 使命”三个关键字,查找最短的摘要:

微软 研究院的使命 是使未来的 计算机 能够看、听、学,能用 自然语言 与 人类 进行交流。 ... 微 软亚洲 工程院将以微软亚洲 研究院的科研成果为依托,创造关键技术、为微软亚洲 研究院核心技术的 孵化 提供有力保证。 ... 微软研院 的科研环境 编辑本段 回目录…

书中给出的解法是基于“分词”后的数组的。

那么,如果是客户端蜘蛛临时抓的网页,或者是在一堆文件中查找,这时候没有分词、没有建立倒排表,如何直接生成呢?再加上有中英文混杂的情况(查找 某种表达的翻译)?

 

冰山一角

这时我想到了基于“多模式匹配”改进原书中算法,因此决定研究下经典的AC_BM算法。查阅了很多文献后,意外的发现:小小的“字符串匹配”居然有 这么多学问~:),引用一段文献——

“String-matching is a very important subject in the wider domain of text processing. String-matching algorithms are basic components used in implementations of practical software existing under most operating systems. Moreover, they emphasize programming methods that serve as paradigms in other fields of computer science (system or software design). Finally, they also play an important role in theoretical computer science by providing challenging problems…”

这段文字出自 http://www-igm.univ-mlv.fr/~lecroq/string/node1.html ,这个网站上竟有35个单模式匹配算法的详细分析、例子、代码、java动画演示…

多模式匹配在:入侵检测、数据挖掘、DNA配对、文本处理(查找替换)等方面都有广泛的应用。

 

算法发展简要回顾

先简要回顾下经典的AC_BM算法是怎么来的:

1. 1977年,这三个人改进Morris-Pratt 算法提出了 Knuth-Morris-Pratt 算法——将“有限状态自动机”+“递归/递推”思想用得很精妙。

2. 同年,Stanford和Palo Alto研究院的两个人提出了经典的Boyer-Moore算法,主要思想为:

a) 提出了从右往左匹配的思路;

b) 通过“坏字符移动”+“好后缀移动”避免无谓的比较;

c) “好后缀移动”借鉴了Knuth-Morris-Pratt 算法。

    题外话:这个BM算法就是大家日常“查找替换”时候用的:)

3. 1980年,Horspool简化了Boyer-Moore算法:用实验证明了只采用“坏字符移动”在一般情况下性能足够了。这是因为“好后缀”出现的概 率并不大,除非是DNA一类的“小字符集”中的匹配,类似AGTCAAGGTTTC…

4. 1975年,Bell Labs的两个人提出了Aho_Corasick算法,主要思想是构造了“多模式”(多关键字)的“有限状态自动机”(是一棵多关键字树,Knuth- Morris-Pratt 算法是单模式的“有限状态自动机”)

5. 2001年,Silicon Defense的三个人将Aho_Corasick算法和Boyer-Moore算法思想结合起来(因为AC算法没有如BM算法一样很好的跳转,还有优化 的空间),就成了AC_BM算法。

由此可以看出,要想搞懂AC_BM算法,得从头一个个来。

 

引用一个题外话:

AC 算法被用于fgrep1.0(在UNIX中通过-f使用)

BM_AC算法在gre中应用,并被fgrep2.0收用。

Knuth-Morris-Pratt 算法

在单模式匹配中,可把要匹配的关键字看成一个“有限状态自动机”:

image

例如上图,如要匹配:GCAGAGAG,遇到G就转状态1,再遇到G还是在状态1,遇到C就转状态2… 到8就成功

这个思路挺不错,问题是跳转的条件比较麻烦,于是Morris-Pratt就将其简化为两个:成功s和失败f,如下图所示:

clip_image004

要匹配ABABABCB,成功了就向前,失败了就退回来,再失败了递归退后…如下表:

那么构造的时候可以递推构造,思路挺好:)

image

那么这个算法最关键就是要构造失败的这些箭头:MP fail links,可以用一个int[]保存。

设要匹配的模式是string pattern; m = pattern.Length; 那么MP fail links可以很简洁地构造:

 int
[] Morris_Pratt()
{
var fails = new int [m];
int i = 0;
int j = fails[0] = -1;
while (i < m - 1)
{
while (j >= 0 && pattern[ i ] != pattern[j]) j = fails[j];
fails[++i] = ++j;
}
return fails;
}

不知道大家有没发现MP fail links 有个问题,假设遇到:

image

设要匹配的文本是 string text; 如果text中出现了“…ABAY…”,那么按照MP fail links跳转换过来的还是B(如上表最后一行),肯定匹配不上的,所以Knuth-Morris-Pratt算法就改进了这个问题(将上面while里 面改了下),构造KMP fail links:

 ……
while (i < m - 1)
  {
        while (j >= 0 && pattern[ i ] != pattern[j]) j = fails[j];
        i++; j++;
        if (pattern[ i ] == pattern[j]) fails[ i ] = fails[j];
        else fails[ i ] = j;
}
…….

就递推地实现了所有首位字符相同的跳转都合并的效果,如下图所示:

clip_image009

那么在查找的时候,就可以利用 KMP fail links 实现跳转,而且思路和构造的时候类似:

 ……
int i = index, j = 0;
while (i < text.Length)
{
while (j >= 0 && pattern[j] != text[ i ]) j = fails[j];
i++; j++;
if (j == pattern.Length) return i - pattern.Length;//找到
}
 return
 –1
 

后记

今天先写到这里,明天咱们继续研究BM算法,感觉挺巧妙的是利用简短的MP fail links可以找到所有的“中缀”和“后缀”。

需要说明的是,直接利用KMP 搜索效率提高并不明显,因此“查找替换”一般用BM算法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值