但是,我想问一下,这是最好的移动方式吗?有没有更好的移动方法呢?接下来我就和大家介绍一种更好的方法,这种方法就是根据好后缀来移动位数。首先我们先介绍下啥的好后缀。
在上面的例子中,我们发现 "mple" 是能够成功匹配的
我们把这些能够成功匹配的子串,称之为好后缀,所以呢,e,le,elp,mple 都是好后缀
因为 e, le, elp在之前的步骤中,也是能够成功匹配。不过 mple 是最长的好后缀。
接下来我们要在模式串的前面寻找与好后缀匹配的子串,这句话的意思就是说,我们要在模式串中寻找这样一个子串s:s 与好后缀匹配,并且s中的字符不能与好后缀有重叠。
我举个例子吧,例如有模式串 abcddab,然后好后缀分别是 b, ab, dab。那么与好后缀匹配的字串有 b,ab。(因为abcddab前面中的b可以与好后缀 b 匹配,前面的 ab 与好后缀 ab 匹配)。不过,没有与好后缀 dab 匹配的子串。
那么问题来了,如果我们找到了多个这样的子串的话,我们要选择哪一个呢?例如上面我们找到了两个,分别是 a,ab。
这个时候,我们选择与比较长的那个好后缀匹配的子串,例如,上面的例子中,我们会选择 ab,我们把这个被选中的子串(ab)称之为好前缀吧(我是为了后面方便描述,才给它这个一个称呼)。
找出了好后缀和好前缀之后 ,我们就可以知道要移动几位了,公式如下:
移动的位数 = 好后缀的下标 - 好前缀的下标。
当然,好后缀有多个,我们是选择和好前缀匹配的那一个。那么好后缀的下标怎么算呢?,计算方法是按照好后缀的最后一个字符的下标为准,例如模式串 abcddab 中好后缀 ab 的下标为 6(下标从 0 开始算起)。好前缀下标的方法也是一样,以最后一个字符的下标位准,例如模式串 abcddab 中,好前缀 ab 的下标为 1。
这里可能有人会问,那如果不存在这样的好前缀呢?如果不存在的话,就用 -1 充当好前缀的下标。
知道了移动位数之后,我们继续来匹配我们上面的例子
10、
好后缀是 e, le, ple, mple,但是模式串中只有一个子串能够与好后缀 e 匹配,所以好前缀为 e。
显然,这个时候好前缀 e 的下标为 0,好后缀 e 的下标为 6,所以移动的位数为 6。如果按照我们最开始坏字符的移动规则的话,只能移动 3 位,而用好后缀可以移动 6 位。
选择坏字符的规则还是好后缀?11、
可能有人会问,两个规则我们应该要选择哪一个呢?
答案很简单,把两个规则的移动位数都算出来,选择移动位数多的就是了。
这里 p 是坏字符,并且不存在好后缀,所以采用坏字符的规则,移动 2 位。
12、
这个时候,我们可以发现,模式串的字符全部都匹配了,这也意味着匹配结束了。 总结
这篇文章我是采用直接举例子的方式来讲,我觉得这样反而容易懂,并且在讲的过程中,可能没有讲的那么全,这是因为我不想说的太全,因为把所有情况都罗列处理的话,相信你容易晕。所以我才用这种方式,让你先懂了这个 BM 的算法思想,之后的细节,你可以再去琢磨。
为了讲清楚这个算法,也算是绞尽脑汁,特别是为了能够以最简单的方式来讲解好后缀的规则,停笔思索了好久,最后也百度搜索了几篇文章,看看别人都怎么讲,还翻开了我之前购买的数据结构与算法的专栏,,,最后结合自己的想法写了出来。希望这篇文章,能够让你读懂给 BM 算法,这个算法的核心就是坏字符和好后缀了,相信你一定能够搞懂!后面会连续讲解几篇与树有关的文章。
如果你觉得这篇内容对你挺有启发,为了让更多的人看到这篇文章:不妨
1、点赞,让更多的人也能看到这篇内容(收藏不点赞,都是耍流氓 -_-)
2、关注我和专栏,让我们成为长期关系
3、关注公众号「苦逼的码农」,主要写算法、计算机基础之类的文章,里面已有100多篇原创文章