RK 算法的思路是这样的:我们通过哈希算法对主串中的 n-m+1 个子串分别求哈希值,然后逐个与模式 串的哈希值比较大小。如果某个子串的哈希值与模式串相等,那就说明对应的子串和模式串匹配了(这 里先不考虑哈希冲突的问题)。
一、RK算法
RK 算法的全称叫 Rabin-Karp 算法,是由它的两位发明者 Rabin 和 Karp 的名字来命名的。
每次检查主串与子串是否匹配,需要依次比对每个字符,所以 BF 算法的时间复杂度就比较高,是 O(n*m)。我们对朴素的字符串匹配算法稍加改造,引入哈希算法,时间复杂度立刻就会降低。
RK 算法的思路是这样的:我们通过哈希算法对主串中的 n-m+1 个子串分别求哈希值,然后逐个与模式 串的哈希值比较大小。如果某个子串的哈希值与模式串相等,那就说明对应的子串和模式串匹配了(这 里先不考虑哈希冲突的问题)。因为哈希值是一个数字,数字之间比较是否相等是非常快速的,所以模 式串和子串比较的效率就提高了。
可以设计一个hash算法: 将字符串转化成整数,利用K进制的方式 数字1-0 :
10进制 123的拆解
100+20+3=123
小写字母a-z:26进制
大小写字母a-Z:52进制
大小写字母+1-0:62进制
以只是小写字母的26进制为例
字符串“abc”转化成hash值的算法是:
a的ASCII码是97
b的ASCII码是98
c的ASCII码是99
65572+2548+99=68219
字符串“abc”转化成hash值是68219
如果觉得计算太麻烦也可以从97开始,
即 字符串“abc”转化成hash值的算法是:
0+26+2=28 代码如下:
/**
* 字符串hash值匹配
*/
public class RKalth {
public static boolean isMatch(String main, String sub) {
//算出子串的hash值
int hash_sub=strToHash(sub);
for (int i = 0; i <= (main.length() - sub.length()); i++) {
// 主串截串后与子串的hash值比较
if (hash_sub==strToHash(main.substring(i, i + sub.length()))) {
return true;
}
}
return false;
}
/**
* 支持 a-z 二十六进制
* 获得字符串的hash值
* @param src
* @return
*/
public static int strToHash(String src) {
int hash = 0;
for (int i = 0; i < src.length(); i++) {
hash *= 26;
hash += src.charAt(i) - 97;
}
return hash;
}
public static void main(String[] args) {
System.out.println(isMatch("abcvdcd","vdcd"));
}
}
时间复杂度
RK 算法的的时间复杂度为O(m+n)
m:为匹配串长度
n:为主串长度
应用
适用于匹配串类型不多的情况,比如:字母、数字或字母加数字的组合 62 (大小写字母+数字)