前几天bbs上看到这样一个问题:

现在有一系列的字符串S=S1, S2, ..., Sn,另外还有一系列的正则表达式或者模式P=P1, P2, ..., Pm。

有什么比较好的算法来让每一个字串对应到一个模式上去吗?(如果有多个对应的则要求对应到最前面出现的模式)

现在用的是最显而易见的算法:遍历S,把每一个字串Si,尝试匹配P中的每一个直到成功则记下它Pj。

这样时间复杂度是n*m,有点慢。。不知道有没有更好的算法。


我的回答是这样的:

实际上,这个问题的本质取决于你的需要匹配的字符串的模式的分布情况。

因为你的所有的字符串都需要匹配,因此n是需要全部遍历一遍的。最好的情况是每次都第一个匹配成功。因为假设这些字符串又是全完独立的随机字符串,所以也可能产生每次都是最后一个匹配到的情况。


这只是初步分析。进一步分析是:

一.这些字符串究竟是不是完全随机的。因为一般来说,输入的序列往往会呈现出某种特征。

典型的特征有两种:

1.局部性:就是出现过的字符串模式很快又会出现。

2.互斥性:出现过的字符串模式不会再出现。

应对这个特征的解决方案是把匹配模式做成一个链表,从头到尾遍历。如果是局部性的,每次匹配成功后把这个模式放到链表头,如果是互斥性的,就把他放到链表尾。

可以证明的是,这种方式不会比运气最好的情况(准确说是运气最坏情况下的最好算法)差到哪里去。也就是所谓的竞争分析。


二.这些匹配特征内部是不是有某种特别的联系。

我所说的条件是否宽松是其中一条。

举个例子,假设一共两个匹配条件:字符串包含a,字符串包含ab。

显然包含a要比包含ab宽松,也就是被匹配到的概率要更大。并且这其中包含了一个重要的特征,就是如果第一条不匹配,那么第二条肯定也是不匹配的。因此下一个匹配比较就可以省略了。把类似的匹配条件放在一个链表节点里。比如把宽松的放在这个节点子链表的前面,把严格的放在链表的后面。(实际上严格的策略永远也不会被匹配到)