查找字符串无非两种常用的,一是BF(宝宝算法)二是天阶算法KMP。
主串:ABCDABCE
模式串ABCE
问题:找出模式串在主串的位置
先说简单的BF算法:
BF是通过先比较,匹配的话就模式串指针和主串指针向前移动,不匹配的回溯。
代码:
public class T {
public static int indexof(String target,String pattern,int beg)
{
int m=target.length();//主串
int n=pattern.length();//子串,模式串
int i=beg;//主串指针
int j=0;//模式串指针
if (m==0||m<n||beg>m)
{
return -1;
}
while (i<m&&j<n)
{
if (target.charAt(i)==pattern.charAt(j))//匹配的话指针后移
{
i++;
j++;
}
else {
i++;//不匹配的话主串指针前移
j=0;//模式串回溯
}
}
if (j==n)//循环结束后,如果模式串指针指向模式串最后一个元素的话,就说明主串存在
{
return i-j;//返回
}
return -1;
}
public static void main(String[] args) {
String target="abcdabce";
String pattern="bce";
System.out.println(indexof(target,pattern,0));
for (int i=indexof(target,pattern,0);i<target.length();i++)
{
System.out.print(target.charAt(i));
}
}
}
简单的BF算法就解决了
下面是KMP算法:
KMP不是一个一个向前移,而是前移模式串匹配的
例如:
i
target: ababacaeabac
pattern: abac
j
发现i指针对应的与j只针对应的不一样:他所采取的是:
i
target: ababacaeabac
pattern: abac
j
直接移动到这儿,为什么呢?应为模式串存在这样的第一个和第三个同样是a,第三个a和主串的a是匹配的,那么第一个a必然也是匹配的。所以我们直接把第一个a移动到第三个a那个位置。后面的以此类推。
那么它是怎么精准的实现的呢?
那就得益于next[]数组了每次回退依靠next数组进行精准定位
abac它的next数组为:
-1,0,0,1
它是看当前模式串的指针前面的数据有多少个相同的就记录下来,下次会退的时候不会直接回溯,
i
target: ababacaeabac
pattern: abac
j
此时不匹配,j=next[j];
j=1;
pattern: abac
j
j就在这儿了,继续检索,匹配;
而不是回到第一个a那。
那么为什么会移动那儿,而不是其他位置呢?
原因是:next数组是专门处理模式串数组的,他记录有多少个重复元素,下次回退就回退重复元素后一个,继续比较,就不用BF那样繁琐的一个一个移动了。
拿上面那个pattern串来说:
匹配到了,c那个位置时,发现不匹配了,但是c前面有两个相同的元素a就可以直接把j指针移到第一a下面那个元素,就相当于下面这个操作,模式串往后移,使主串的第二个a与模式串第一个a匹配。
i
target: ababacaeabac
pattern: abac
j
代码如下:
public class kpm3 {
private static int next[];//定义一个next数组
public static int[] getNext(String pattern) {获取next数组
int next[]=new int[pattern.length()];//开辟空间
int j=0;
int k=-1;
next[0]=-1;//很重要,不能忘了
while (j<pattern.length()-1)//小心越界
{
if (k==-1||pattern.charAt(j)==pattern.charAt(k)){//如果处理第一或者是相同元素的时候,我们把指针往后移动
j++;
k++;
next[j]=k;//标记相同个数
}
else
{
k=next[k];回退回去
}
}
return next;
}
public static int indexOf(String target,String pattern,int beg){
int length = target.length()//保存target长度
int length1 = pattern.length();//保存pattern长度
next=getNext(pattern);//生成数组
int i=beg;//对标target
int j=0;//对标patt
if (beg>length||length<length1||length==0)//处理不合理的参数
{
return -1;
}
while (i<length&&j<length1){//循环条件是i没检索完,j也没检索完,这与BF算法条件一致
if (j==-1||target.charAt(i)==pattern.charAt(j))//判断,相同,相同的话就或移动
{
i++;
j++;
}
else
{//不同的话就回退回去
j=next[j];
if(length-i<length1-j)//额外终止条件,当主仅剩下的长度小于模式串的长度,就默认后面没了,就退出循环。
{
break;
}
}
}
if (j== length1)//指针对应的是模式串最后一个
{
return i-j;
}
return -1;
}
public static int indexOf(String target,String pattern)
{
return indexOf(target,pattern,0);
}
public static void main(String[] args) {
String m="asdfgfd";
String n="gfd";
System.out.println(indexOf(m,n));
System.out.println(indexOfBF(m,n,2));
}
}
东西有点多,还请耐心看完。