参考网站:
https://blog.csdn.net/fjssharpsword/article/details/53462292
https://cloud.tencent.com/developer/article/1139653
参考书籍:Algorithm (算法) Robert Sedgewick / Kevin Wayne著 谢路云译
1. 题目描述
查找目标字符串K中是否有与字符串L匹配的子串。
2. 关键词
哈希
3. 思路
- 当子串L的长度为m,目标字符串K的长度为n
- 计算子串L的hash值
- 使用华东窗口,计算目标字符串K中每个长度为m的子串的hash值(共需要计算n-m+1次)
- 依次比较hash值并且对997取余(在不溢出的情况下选择一个尽可能大的值)。
在计算机中,当要表示的数据超出计算机所使用的数据的表示范围时,则产生数据的溢出
- 如果hash值不同,字符串必然不匹配,如果hash值相同,还需要使用朴素算法再次判断。
4. 时间及空间复杂度
时间复杂度:O(M+N)
空间复杂度:O(1)
5. 代码(Java)
public class RabinKarp {
private String pat;
private long patHash;
private int m;
private long q;
private int R;
private long RM;
//字符串hash值计算方法
private long hash(String key, int m) {
long h = 0;
for (int j = 0; j < m; j++)
h = (R * h + key.charAt(j)) % q;
return h;
}
public RabinKarp(String pat) {
this.pat = pat;
R = 256;
m = pat.length();
q = longRandomPrime();
RM = 1;
for (int i = 1; i <= m-1; i++)
RM = (R * RM) % q;
patHash = hash(pat, m);
}
private long hash(String key, int m) {
long h = 0;
for (int j = 0; j < m; j++)
h = (R * h + key.charAt(j)) % q;
return h;
}
private boolean check(String txt, int i) {
for (int j = 0; j < m; j++)
if (pat.charAt(j) != txt.charAt(i + j))
return false;
return true;
}
public int search(String txt) {
int n = txt.length();
if (n < m) return n;
long txtHash = hash(txt, m);
if ((patHash == txtHash) && check(txt, 0))
return 0;
for (int i = m; i < n; i++) {
txtHash = (txtHash + q - RM*txt.charAt(i-m) % q) % q;
txtHash = (txtHash*R + txt.charAt(i)) % q;
int offset = i - m + 1;
if ((patHash == txtHash) && check(txt, offset))
return offset;
}
return n;
}
private static long longRandomPrime() {
BigInteger prime = BigInteger.probablePrime(31, new Random());
return prime.longValue();
}
}