前言
字符串匹配(String Match)是计算机行业笔试面试常见的题型,无论是在大公司的笔试真题中,还是在面试中,都是大公司和面试官们津津乐道的话题。
当然字符串匹配也具有一定的难度,特别是讲到后面一些比较复杂难懂的算法例如KMP算法,BM算法等,初学者可能一时之间没办法全部理解,多看几遍,总会孰能生巧的。
字符串匹配的博客,理论讲解部分我分为两篇来写,分别是单模式字符串匹配和多模式字符串匹配。后续有时间 会针对一些习题 应用场景加以表述。
现在开始南国这篇博客的正文,本篇博文内容比较多,但是爱学习的你看完一定会有所收获,Just trust me~
单模式匹配
单模式字符串匹配就是一个字符串a和另一个字符串b进行匹配,一般而言,a的长度远大于b,我们在a中查找是否包含b。我们将字符串a称为主串,字符串b称为模式串。
1.暴力匹配的算法BF算法
BF算法成为暴力匹配算法,又叫做朴素匹配算法。也是最简单的,我们经常用到的算法。最简单的方法就是每次比对m个字符,最坏情况下比较n-m+1次,BF算法的最坏情况时间复杂度为O(n*m)。
BF算法的Java代码实现:
int Search(String S, String T) {
int i = 0;
int j = 0;
while(i<S.length()&&j<T.length()) {
if(S[i] == T[j]) {
++ i;
++ j;
} else {
i = i - j + 1;
j = 0;
}
}
if(j ==T.length() )
return i - j;
return -1;
}
2.RK算法(基于哈希算法的BF算法优化方案)
RK算法是在BF算法的基础上进行改进,在字符串匹配时加入哈希算法的思想。
RK 算法的思路:我们通过哈希算法对主串中的 n-m+1 个子串分别求哈希值,然后逐个与模式串的哈希值比较大小。如果某个子串的哈希值与模式串相等,则说明对应的子串和模式串匹配了。
不过,对于这种在字符串中加入哈希算法的思想在具体的实现方案上还有一些地方需要考虑。
问题1.通过哈希算法计算子串的哈希值时候,我们需要遍历子串中的每个字符。尽管模式串与子串比较的效率提高了,但是算法整体的效率并没有提高。有没有方法可以提高哈希算法计算子串哈希值的效率呢??
问题2:利用到哈希算法,我们就会自然想到哈希函数和散列冲突。前面问题1的解答中南国讲述了一种哈希函数的处理放肆。但是如果字符串中包含的字符不仅仅限于小写字母,还包含大写字母 数字等等ASCII码中的其他字符了。况且当模式串b特别长时,计算的哈希值操作Int的数值范围了。
解决方法是:极端情况下(万一包含的字符是ASCII中126个有效字符),将哈希值的类型设置为Long型 或者Long Long型,那字符串中每个字符对应的ACII码值相加的和作为哈希值。
- 如果两个子串的哈希值不等,则两个子串肯定不相同。
- 如果两个子串的哈希值相同,则在比较目标子串本身(避免哈希冲突带来的误报)
性能分析
整个RK算法的时间复杂度分析我们分为两个部分,计算每个子串的哈希值和子串的哈希值之间的比较。代码中循环复杂度O(n),hash结果相等时的逐字符匹配复杂度为O(m),整体时间复杂度为O(m+n)。空间复杂度为O(1)
结论:RK算法的时间复杂度时O(n+m)
RK算法java代码实现:
package StringMatch;
/**
* RK算法
* @author xjh 2018.12.29
*/
public class RK {
public static final int HASHSIZE=100001;
public