【数据结构与算法】字符串匹配 - RK算法
RK(Rabin-Karp)算法是由Rabin
和Karp
两个大佬发明,RK算法的产生是因为发明者觉得BF算法那样每个字符一一比较太慢了,他们引入了哈希算法,哈希算法对主串中N - M + 1
个字符串分别求哈希值,然后逐个与模式串的哈希值进行比较。
与暴力算法使用一致的思想,通过滑动窗口(每次滑动一位)的方式计算N - M + 1
个子串的哈希值,依然以主串=AABABCDEF
,模式串=ABCD
为例,N = 9
, M = 4
,那么N - M + 1 = 6
个字串,这6个字串分别是:
有了上面这些字串的哈希值,之后就可以与模式串的哈希值hash(ABCD)
进行比较,如果哈希值相等,那么说明字符串可能匹配了。
通过上面的分析,我们就能得到一个大概的代码,如下:
public class Solution {
/**
* RK算法
*
* @param text 文本串
* @param pattern 模式串
* @return
*/
private static int rk(String text, String pattern) {
// 文本串长度
int N = text.length();
// 模式串长度
int M = pattern.length();
if (M > N) {
return -1;
}
// 模式串的hash值
int patternHash = hash(pattern);
for (int i = 0; i < N - M + 1; i++) {
// 获取与模式串等长的子串
String subText = text.substring(i, i + M);
// 获取子串的哈希值
int subTextHash = hash(subText);
if (subTextHash == patternHash) {
// 返回匹配的开始索引
return i;
}
}
return -1;
}
private static int hash(String text) {
// TODO获取字符串的哈希值
return 0;
}
}
在上面的代码中,通过循环加上截取字符串的方式肯定能获取到文本串中所有跟模式串长度一样的字串,然后通过hash算法,计算哈希值,与模式串的哈希值比较。
hash值如何实现呢?
比如模式串是ABCD
,它的哈希值如何算呢?我们可以将每个字符的Unicode编码值相加就是hash(“ABCD”)的值。
A
的Unicode编码值是65
B
的Unicode编码值是66
C
的Unicode编码值是67
D
的Unicode编码值是68
所有ABCD
的哈希值就是65 + 66 + 67 + 68 = 266
。
所有hash方法的实现如下:
private static int hash(String text) {
int hashcode = 0