参考KMP算法
主要是看了上面的讲解,自己做一下记录,加深印象
BF算法
t为目标串,p为模式串
暴力解:思想:先从第一个字符开始匹配,如果p[j]==t[i],那么继续向下比较,一旦不相等,即回溯到目标串的下一个字符,重复工作。
成功条件:当循环结束时,判断j的值与模式串p的长度是否相等,如果相等,说明匹配成功到了模式p的最后一个字符。
返回值:返回模式串在目标串中出现的位置。
方式一:
public static int bf(String t,String p){
char[] tchars = t.toCharArray();
char[] pchars = p.toCharArray();
int tlen=tchars.length;
int plen=pchars.length;
for (int i = 0; i <= tlen-plen; i++) {
int j;
for (j = 0; j < plen; j++) {
if(tchars[i+j]!=pchars[j]){
break;
}
}
if(j>=plen){
return i;
}
}
return -1;
}
方式二:
public static int bf1(String t,String p){
char[] tchars = t.toCharArray();
char[] pchars = p.toCharArray();
int tlen=tchars.length;
int plen=pchars.length;
int i=0;
int j=0;
while (i<tlen&&j<plen){
if(tchars[i]==pchars[j]){
i++;
j++;
}else {
i=i-j+1;
j=0;
}
}
if(j>=plen){
return i-j;
}
return -1;
}
KMP算法
公式推出:
利用失效函数进行推,
部分匹配表:
PMT中的值是字符串的前缀集合与后缀集合的交集中最长元素的长度。
由部分匹配表推出next数组:
代码实现:
public static int kmp(String t,String p, int[] next){
char[] tchars = t.toCharArray();
char[] pchars = p.toCharArray();
int tlen=tchars.length;
int plen=pchars.length;
int i=0;
int j=0;
while (i < tlen && j < plen) {
if (j == -1 || tchars[i] == pchars[j]) {
i++;
j++;
} else {
j = next[j];
}
}
if(j>=plen){
return i-j;
}
return -1;
}
核心:如何求取next数组
先给出代码,然后解释为什么这么写;
求解next数组,也就是以模式串p为目标串,找出前面字符串的最长前缀子串;
先理解清楚PMT数组和next数组的关系,PMT数组指的是以当前第i个字符结尾的字符串所拥有的最长前缀子串和最长后缀子串的个数j,也就是第i+1个字符不匹配时,P字符串应该移动到的位置j,继续进行比较;
等同于求解next数组,主要是根据动态规划的思想,假设当前
p0…pk=pj-k…pj;
pmt[j]=k;
若pk+1=pj+1,则pmt[j+1]=k+1=pmt[j]+1;
则对应的next[j+2]=k+1;
对应下面的代码就是当p[i]==p[j]时,说明以i结尾的字符串的最长前缀子串的最后一个字符的下表为j;
则第i+1个字符不匹配的时候,p应该移动的是前面以i结尾的字符串的最长匹配前缀个数j+1,也就是next[i+1]=j+1;也就是对应下面的i++,j++,next[i]=j;
假如p[i]!=p[j],则根据模式串移动的原理,应该继续找第j个字符不匹配时,j应该移动的位置,也就是j=next[j];
以上公式根据教材中的公式,
public static int[] next(String p) {
char[] pchars = p.toCharArray();
int plen = pchars.length;
int[] next = new int[plen];
int i = 0;
int j = -1;
next[0] = -1;
while (i < plen - 1) {
if (j == -1 || pchars[i] == pchars[j]) {
i++;
j++;
next[i] = j;
} else {
j = next[j];
}
}
return next;
}
以上是个人理解的,可以随时交流;