字符串匹配之RabinKarp
说起字符串我们首先想到的就是一个字符一个字符的匹配,失配那么就重新来过
//暴力法
static int indexOf(String s1,String s2){
int i = 0;
int l = i;
int j = 0;
while(i < s1.Length()){
if(s1.charAt(l) == s2.charAt(j)){
l++;
j++;
if(j == s2.Length()){
return i;
}
}else{
i++;
l = i;
j = 0;
}
}
}
这样的话,时间复杂度就是iij
主要就是引用两个概念
①hash
②滚动hash
**时间复杂度:**就是 j * 算哈希值的复杂度
例:ABBAA
转换成 31进制
A * 31 ^ 4
B * 31 ^ 3
B * 31 ^ 2
A * 31 ^ 1
A * 31 ^ 0
全部相加就等于hash值
(((((0 * 31 + A )* 31 + B )* 31 + B) * 31 + A) * 31 + A)
等价于
A * 31 ^ 4
B * 31 ^ 3
B * 31 ^ 2
A * 31 ^ 1
A * 31 ^ 0
代码实现
//求Hash值
static long Hash(String s,int seed){
long hash = 0;
for(int i = 0;i < s.Length();i++){
hash = hash * seed + s.charAt(i);
}
}
//利用哈希值直接对搜索的字符串比对
static int indexOf(String s1,String s2){
long hash = Hash(s2)%Long.MAX_VALUE;
for(int i = 0;i < s1.Length()-s2.Length();i++){
String str = s1.subString(i,i+s2.Length());
if(hash == Hash(str)){
return i;
}
}
return -1;
}
②滚动哈希
将q变成t
实现滚动减去尾巴,加上一个头
代码实现
直接判断
//直接找出搜索值
public static indexOf(String s1,String s2){
int s1Len = s1.Length();
int s2Len = s2.Length();
long s1Hash = Hash(s1.subString(0,s2Len))%Long.MAX_VALUE;
long s2Hash = Hash(s2)%Long.MAX_VALUE;
if(s1Hash == s2Hash){
return 0;
}
for(int i = s2Len;i <= s1.length;i++){
char newchar = s1.charAt(i);
char ochar = s1.charAt(i-s2Len);
s1Hash = long(s1Hash * seed - Math.pow(seed,)*ochar + newchar)%Long.MAX_VALUE;
if(s1Hash == s2Hash){
return i-s2Len;
}
}
return -1;
}
//预处理一下每个位置的哈希值
static long[] Hash(String s1,String s2){
int s1Len = s1.Length();
int s2Len = s2.Length();
long[] hashs = new long[s1Len-s2Len];
hashs[0] = hash(s1.subString(0,s2Len));
for(int i = s2Len;i < s1Len;i++){
char newchar = s1.charAt(i);
char ochar = s1.charAt(i-s2Len);
hashs[i-s2Len+1] = (long)(hashs[i-s2Len] * seed - Math.pow(seed,s2Len) *ochar + newchar)%Long.MAX_VALUE;
}
}
//得到数组就直接用数组中的hash值对比就好了