在匹配的过程中,直至匹配到不同的字符,主串和模式串之前的字符是相同的。到不匹配字符之前的字符的重复的部分是可以利用的
数组的计算方法
next[j]表示前 j-1 个串中首尾的公共长度+1,一号位(为零)除外
nextval[]在next的基础上,从左至右,第一个不变,从第二个字符开始,如果对应的next的值为c,在next[c-1]的字符如果与之相等,则将nextval的值置为nextval[c-1]
例如:
项目 | A | B | A | B | A | A | A | B | A | B | A | A |
---|---|---|---|---|---|---|---|---|---|---|---|---|
next | 0 | 1 | 1 | 2 | 3 | 4 | 2 | 2 | 3 | 4 | 5 | 6 |
nextval | 0 | 1 | 0 | 1 | 0 | 4 | 2 | 1 | 0 | 1 | 0 | 4 |
next[]中非零数i的表示模式串的第i个字符(arr[i-1]如果是数组的话)与不匹配位置开始比较
有公共前后缀的,前缀直接移动到后缀的位置。
一号位不匹配,与主串下一位进行比较
注意:比较时,从长公共前后缀的长度加1的位置开始与主串比较
模式串比较常用的存储方式是从下标1开始存储的(从零开始存储仍然可行)
递推,next数组的递推计算(长的不能手算的情况):
n e x t [ j + 1 ] = { n e x t [ j ] + 1 pj=pt n e x t [ t ] , 循 环 至 n e x t [ t ] = 0 或 者 满 足 ( 1 ) 为 止 pj!=pt next[j+1]= \begin{cases} next[j]+1& \text{pj=pt}\\ next[t],循环至next[t] = 0或者满足(1)为止& \text{pj!=pt} \end{cases} next[j+1]={next[j]+1next[t],循环至next[t]=0或者满足(1)为止pj=ptpj!=pt
void getNext( Str substr, int next [] )
{
int j=1,t=0;
next[1]=0;
while(j < substr. length){
if(t==0 || substr.ch[j] == substr.ch[t] ) {
next[j+1] = t+1;//***\\\\
++t;
++j ;
}
else
t = next[t] ;//头"指针"t的回溯***,♥下一次比较的位置♥
}
int: KMP (Str str, Str substr, int next[] )
{
int i=1,j=1;//从str.ch[1]开始比较
while(i<r. length && j<=substr.length)//全部遍历(i,j的范围分别为珠串的范围和模式串的范围)
if(j==0||Istr.ch[i]==substr.ch[j])
{++i ;
++j;//一个个字符按顺序比较
}
else
{
j=next[j] ;//如果出现不匹配,直接移动
//比如没有公共前后缀,j值就是1,比较 Istr.ch[i](当前位)==substr.ch[j](模式串的第一位)
}
if (j>substr. length)
return i-substr. length;
else
return 0;
}
GTGTGCF
0111210
ATGTGAGCTGGTGTGCFGTGTG
GTGTGCF
其它相关代码
function getNext() {
var j=1,t=0;/*从前两位开始比较*/
var next= []
var target = [1,2,1,2,1,1,1,2,1,2,1,1];
next[0]=66;
next[1]=0;
while(j < target.length){
if(t==0 || target[j] == target[t] ) {
next[j+1] = t+1;//***\\\\
++t;
++j ;console.log(next);
}
else
{t = next[t] ;//头"指针"t的回溯***
console.log(t);
console.log(next);}
}
console.log(next);
return next;
}
getNext();
function getNext() {
var j=1,t=0;
var next= []
var target = [1,2,1,2,1,1,1,2,1,2,1,1];
next[0]=514;
next[1]=0;
while(j < target.length){
if(t==0 || target[j] == target[t] ) {
next[j+1] = t+1;//***\\\\
++t;
++j ;
}
else
t = next[t] ;//头"指针"t的回溯***
}
console.log(next);
return next;
}
void getNext( Str substr, int next [] )
{
int j=1,t=0;
next[1]=0;
next[2]=1;
while(j < substr. length){
if( substr.ch[j] == substr.ch[t] ) {
next[j+1] = t+1;//***\\\\
++t;
++j ;
}
else {
if(t==0){next[j+1] = 0;}
else { t = next[t] ;}//头"指针"t的回溯***
}
}
可以减少不必要的比较
void getNextval( Str substr, int nextval[],int next [] )
{
int j=1,t=0;
next[1]=0;
Nextval[1]=0;
while(j < substr. length){
if(t==0 || substr.ch[j] == substr.ch[t] ) {
next[j+1] = t+1;
//***
if(substr.ch[j+1]!=substr.ch[substr.ch[j+1]]!)
nextval[j+1]=next[j+1];
else
nextval[j+1] = nextval[next[j+1]];
//***
++t;
++j ;
}
else
t = nextval[t] ;//***
t = next[t] ;
}
void getNextval( Str substr, int nextval[] )
{
int j=1,t=0;
Nextval[1]=0;
while(j < substr. length){
if(t==0 || substr.ch[j] == substr.ch[t] ) {
//***
if(substr.ch[j+1]!=substr.ch[substr.ch[j+1]]!)
nextval[j+1]=next[j+1];
else
nextval[j+1] = nextval[next[j+1]];
//***
++t;
++j ;
}
else
t = nextval[t] ;//***
}
class Untitled {
public static void main(String[] args) {
System.out.println("hello https://tool.lu/");
String str="ATGTGAGCTGGTGTGCFGTGTG";
String pattern="GTGTGCF";
int index=kmp(str ,pattern);
System.out.println("首次出现位置:"+index);
}
// KMP算法主体逻辑。str是主串,pattern是模式串
public static int kmp(String str, String pattern) {
//预处理,生成next数组
int[] next = getNexts (pattern);
intj=0;
//主循环,遍历主串字符
for (int i = 0; i < str.1ength(); i++) {
while (j >0 && str.charAt(i) != pattern. charAt(j)) {
//遇到坏字符时,查询next数组并改变模式串的起点
j = next[j];
}
if (str .charAt(i) == pattern. charAt(j)) {
j++;
}
if (j == pattern. length()) {
//匹配成功,返回下标
return i-pattern. length()+1;
}
}
}
//生成Next数组
private static int[] getNexts(String pattern) {
int[] next = new int[pattern. length()];
intj=0;
for (int i=2; i<pattern.1ength(); i++) {
while (j !=0&& pattern.charAt(j) != pattern.charAt(i-1)) {
//从next[i+1]的求解回溯到next[j]
j = next[j] ;
}
if (pattern. charAt(j) == pattern. charAt(i-1)) {
j++;
}
next[i] = j;
}
return next;
}
}