RK算法( 时间复杂度: O(n) )
对暴力匹配算法进行了一定的优化,不再是逐个比较模式串和主串子串的每个字符,而是比较他们的Hash值,基本步骤如下:
- 生成模式串的hash code:
常见的方法有两种:
I. 转换为26进制数,eg:
bce = (62-60) * (26^2) + (63-60) * 26 + 65-60 = 1435
优点:大幅减少了哈希冲突
缺点:计算量大,超出整形范围
II. 按位相加
bce = (62-60) + (63-60) + (65-60) = 10 - 根据模式串的hash code生成方法,生成主串当中第一个等长子串的hash code
- 比较两个hash code,如果不匹配,将主串当中等长子串的初始位置加一,跳转到步骤2继续执行,直到找到两个hash code值相等
- 逐个比较模式串和主串当中等长子串的每一个字符,如果匹配,输出位置,如果不匹配,将主串当中等长子串的初始位置加一,跳转到步骤2继续执行
在执行过程中,会发现需要多次计算子串的hash code,并没有达到优化的目的,其实从第二个子串开始,每个子串的hash code都可以由上一个子串进行简单的增量计算:
abbce 1+2+2+3 = 8
abbce 8-1+5 = 12
function RK_algorithm(){
var mainString = "GTTATAGCTGGTAGCGGCGAA";
var patternString = "GTAGCGGCG";
var patternLength = patternString.length;
var mainLength = mainString.length;
var patternHash = hashCode(patternString);
var mainHash = hashCode(mainString.substring(0,patternLength));
for(var i = 0 ; i <= mainLength - patternLength; i++){
if(i !== 0){
mainHash = mainHash - (mainString.charCodeAt(i-1)-64) + (mainString.charCodeAt(i+patternLength-1)-64);
}
if(patternHash === mainHash && compareHashValue(patternString,mainString.substring(i,i+patternLength))){
console.log(i);
return i;
}
}
console.log(-1);
return -1;
}
function hashCode(subString){
var hashcode = 0;
for(var i = 0; i < subString.length; i++){
hashcode += subString.charCodeAt(i)-64;
}