算法思想
- 假设子串的长度为M,目标字符串的长度为N
- 计算子串的hash值
- 计算目标字符串中每个长度为M的子串的hash值(共需要计算N-M+1次)
- 比较hash值
- 如果hash值不同,字符串必然不匹配,如果hash值相同,还需要使用朴素算法再次判断
算法关键
- 在计算源串的hash值时若每次都调用hash()方法,则使时间复杂度达到O(mn)级别,与暴力扫描几乎一样,所以在计算源串hash时,可采用对上一组的hash值*seed-多余的部分。
代码
public static void main(String[] args) {
String s="ABABAB";
String p="ABA";
paBinKarp(s,p);
}
private static void paBinKarp(String s, String p) {
long hash_p = hash(p, 500);
int pLength=p.length();
long[] hash_s = hash(s, pLength, 500);
for (int i = 0; i < hash_s.length; i++) {
if(hash_s[i]==hash_p){
System.out.println("match"+i);
}
}
}
public static long[] hash(String s,int patternLength,int seed){
long[] hash=new long[s.length()-patternLength+1];
hash[0]=hash(s.substring(0,patternLength),500);
for (int i = patternLength; i < s.length(); i++) {
char newChar=s.charAt(i);
char oldChar=s.charAt(i-patternLength);
hash[i-patternLength+1]= (long) ((hash[i-patternLength]*seed+newChar-oldChar*Math.pow(seed,patternLength))%Long.MAX_VALUE);
}
return hash;
}
public static long hash(String s,int seed){
long hash=0;
for (int i = 0; i < s.length(); i++) {
hash=hash*seed+s.charAt(i);
}
return hash;
}