Rabin Karp算法寻找目标字符串在原字符串中的位置
前言
注:本文主要作为自己学习的记录,并没有详细介绍算法的每一步骤,如有问题欢迎讨论。
要解决的问题如下例:
在"abcde" 中寻找"bcd",则返回位置:1。
一、使用rabin karp算法寻找目标字符串在原字符串中的位置。
代码如下:在这里插入代码片
public int targetIndex(String source, String target) {
if (source == null || target ==null || source.equals("") || target.equals(""))
return -1;
final int BASE = 1000000;
int tL = target.length();
// 31^tL; power的作用是用于减去原先第一个数,例如: abcd - a;
// 为什么不是31^(tL-1)呢,因为bcd最高次数为31^(tL-1),因此被减去的a的位数只能是31^(tL-1)
int power = 1;
for (int i = 0; i < tL; i++) {
power = (power * 31) % BASE;
}
int targetCode = 0;
for (int i = 0; i < tL; i++) {
targetCode = (targetCode * 31 + target.charAt(i)) % BASE;
}
/*
for (int i = 0; i < source.length(); i++) {
if (i > source.length() - tL)
break;
int hashCode = 0;
for (int j = 0; j < tL; j++) {
hashCode = (hashCode * 31 + source.charAt(i + j)) % BASE;
}
if (hashCode != targetCode)
continue;
else if (source.substring(i, i+tL).equals(target)) {
return i;
}
}
*/
int hashCode = 0;
for (int i = 0; i < source.length(); i++) {
hashCode = (hashCode * 31 + source.charAt(i)) % BASE;
if (i < tL)
continue;
if (i >= tL) {
hashCode = hashCode - (source.charAt(i - tL) * power) % BASE;
// 等式右边的第一个hashCode在上步骤中已经%BASE了,因此只用让减号后面的式子%BASE
if (hashCode < 0) {
hashCode += BASE;
}
}
if (hashCode != targetCode)
continue;
else if(source.substring(i-tL+1, i+1).equals(target))
//无法确定是(i-tL+1)还是(i-tL)还是(i-tL-1),带入一个极端数就可以了,例如 假设i=2,tL=3那么起始位置应该是0,即i-tL+1
return i-tL+1;
}
return -1;
}
(调了半天格式也没调对,暂时放弃了,-_-#)
若采用被注释的部分,实际时间复杂度为O(n*m)跟逐个比较一样,使用非注释部分,则时间复杂度为O(n)。
总结
1.Rabin Karp算法的思想是将字符串转换成一个尽量唯一的hash值,避免逐个比较两个字符串中的每个字符,从而降低时间复杂度。
2.之所以说尽量的原因是,使用a*(31^tL-1) + …的方式仍然有可能照成hash值重复。
3.为什么BASE是10^6,留下一个疑问,和大家一起探讨。