BF算法和KMP算法解析

查找字符串无非两种常用的,一是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));

    }
}

东西有点多,还请耐心看完。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值