Boyer–Moore 算法 是用来在字符串中搜索一个子字符串的算法,也简称 BM 算法。
问题
在长度为 n
的字符串 s
中搜索长度为 m
的子串 p
的位置。
本文以 ABCDABEABDCBCDDBBCDBACD
为主串 ,BCDBACD
为子串,作为用例。
算法过程
首先将两个字符串左对齐,对子串 p
进行 自右向左 的逐一比对。
第一次比对,即在字符 E
失配。 由于 E
不在子串 p
中,因此,可以直接把整个子串右移到其右边。
继续向前匹配,此时在下图中的红色部分失配。
但是,失配的 B
在子串 p
中,就在当前位置靠左一位的位置。 要想子串和主串在附近匹配成功,至少字符 B
要对的齐。 为了避免错过 B
的匹配,只能找到靠的最近的 B
对齐,也就是右移一位。
回到子串的尾部,自右向左,继续匹配,在下图中的红色部分失配。
沿用刚才上面的思路,失配的 D
也在子串中,右移 p
,让它们对齐
总结规律: 当失配的时候,右移子串,使得主串中失配的字符和子串中左边最近的相同字符对齐。如果不存在相同字符,就把整个子串右移到失配字符的右侧。
坏字符的办法
常把失配处主串中的字符叫做「坏字符」,每次右移,就要把 坏字符和子串中最近的坏字符对齐。
Boyer–Moore 算法和 KMP 算法 的思路类似,都是在失配处动脑筋,跳过无必要的比对,以加快搜索。
按这个思路,可以继续匹配下去,直到命中。
好后缀的办法
上面坏字符的办法,还不够快。
比如下面这次对齐:
此时,已知的信息是,主串中有已经匹配好的 CD
,它同时也是子串 p
的后缀,常叫做「好后缀」。
要想子串在附近和主串匹配成功,它们的共同子串 CD
就要对的齐,所以,把对齐坏字符的办法应用到好后缀上, 找到最近的好后缀进行右移对齐。
如此一来,右移的更多了些。
好后缀的办法就是, 失配时,右移子串,使得主串中的好后缀和子串中左边最近的重复串对齐 。 同样的,如果存在好后缀,而左边没有重复串时,那么直接把 p
右移到整个好后缀右边就好了。
综合两个办法后,整个搜索过程优化为下面的样子,总体上比只用坏字符的办法,少了两步。