字符串匹配算法,即在一个字符串中查找另个字符串的位置。如果在字符串A中查找字符串B是否存在,那么字符串A称为主串,字符串B称为模式串。主串长度为m,模式串长度为n。
BF (Brute Force) 暴力匹配算法
充主串A的起始位0开始,检查长度n的子串,是否和模式串相等。如果不相等,将主串的指针往后挪一位,从主串的1,2,3 ... m-n位开始,依次检查长度为n的子串,是否和模式串匹配。
时间复杂度为 O(m*n),但是实际的效率比理论值效率高一些。
RK(Rabin-Karp)算法
和BF算法思想一致,只是在比较A的子串与模式串是否匹配时,使用Hash算法比较hash后的数值,而不是一一比较字符。
其中的Hash算法比较讲究,好的Hash算法可以大大提高效率,而查的Hash算法,可能使得算法效率还比不上BF。
如果字符串只有小写字符,可将字符串作为26进制的数来看待。同时缓存26n,26(n-1) 等预处理的值,可以提高计算速度。
BM(Boyer-Moore)算法
非常高效的算法,据说是KMP算法的3-4倍。算法思路上与BF一致,只是每次往后挪的位数多一些。而且在比较子串与模式串时,是从最后一个字符开始,往前比较。
- 坏字符规则(bad character rule)
- 好后缀规则(good suffix rule)
坏字符规则
从后往前,依次比较主串和模式串的字符,出现不相等的字符时,主串中的那个就是“坏字符”。
如果模式串中有坏字符,将模式串往后移动让两个字符对齐。如果模式串中没有坏字符,直接将模式串移到坏字符后面。
好后缀规则
主串和模式串从后往前,相同的部分称为“好后缀”。
-
模式串中有好后缀,可以后移模式串,让二者对齐。
-
好后缀的后面的子串和模式串前缀子串相同,移动模式串到相应的位置。
- 其他情况,将模式串挪到好后缀后面。
预处理
要想高效实用这两个规则,需要对模式串进行预处理。
坏字符预处理
将模式串的字符位置放到哈希表,在以便快速查找坏字符。
hash[key] = value;
- key - 模式串的字符
- value - 字符在模式串中的位置。
相同的字符,取最后一个位置。
好后缀预处理
处理模式串中后缀子串,检查在模式串中其他位置是否有形同的的子串,使用 int[] A 数组来存储。
A[i] = j;
表示从后往前 i+1 长度的字符串,在模式串中存在,位置是 j。处理模式串的后缀子串,是否与模式串的前缀子串匹配。同样适用 bool[] B 数组来存储。
B[i] = true/false;
表示从后往前 i+1 长度的字符串,true表示和前缀子串匹配,false表示不匹配。
代码实现思路如下图,j从 0 -> n-1 遍历,对于每个j,相应的k指向末尾,同时往前移动,如果指向的字符不同,马上停止。得到值存入A。如果j指针能走到0,那B中设置为true。