前几天bbs上看到这样一个问题:
现在有一系列的字符串S=S1, S2, ..., Sn,另外还有一系列的正则表达式或者模式P=P1, P2, ..., Pm。
有什么比较好的算法来让每一个字串对应到一个模式上去吗?(如果有多个对应的则要求对应到最前面出现的模式)
现在用的是最显而易见的算法:遍历S,把每一个字串Si,尝试匹配P中的每一个直到成功则记下它Pj。
这样时间复杂度是n*m,有点慢。。不知道有没有更好的算法。
我的回答是这样的:
实际上,这个问题的本质取决于你的需要匹配的字符串的模式的分布情况。
因为你的所有的字符串都需要匹配,因此n是需要全部遍历一遍的。最好的情况是每次都第一个匹配成功。因为假设这些字符串又是全完独立的随机字符串,所以也可能产生每次都是最后一个匹配到的情况。
这只是初步分析。进一步分析是:
一.这些字符串究竟是不是完全随机的。因为一般来说,输入的序列往往会呈现出某种特征。
典型的特征有两种:
1.局部性:就是出现过的字符串模式很快又会出现。
2.互斥性:出现过的字符串模式不会再出现。
应对这个特征的解决方案是把匹配模式做成一个链表,从头到尾遍历。如果是局部性的,每次匹配成功后把这个模式放到链表头,如果是互斥性的,就把他放到链表尾。
可以证明的是,这种方式不会比运气最好的情况(准确说是运气最坏情况下的最好算法)差到哪里去。也就是所谓的竞争分析。
二.这些匹配特征内部是不是有某种特别的联系。
我所说的条件是否宽松是其中一条。
举个例子,假设一共两个匹配条件:字符串包含a,字符串包含ab。
显然包含a要比包含ab宽松,也就是被匹配到的概率要更大。并且这其中包含了一个重要的特征,就是如果第一条不匹配,那么第二条肯定也是不匹配的。因此下一个匹配比较就可以省略了。把类似的匹配条件放在一个链表节点里。比如把宽松的放在这个节点子链表的前面,把严格的放在链表的后面。(实际上严格的策略永远也不会被匹配到)