字符串匹配的暴力算法和KMP算法总结

6 篇文章 1 订阅

问题描述:
母串:BBC ABCDAB ABCDABCDABDE
子串:ABCDABD
在母串中寻找完全跟子串匹配的子串的起始终止位置。
暴力匹配法:

public class Violence_Match {
    public void violence(String str1,String str2){
        int i=0,j=0;//两个字符数组的指针
        char[] s1=str1.toCharArray();
        char[] s2=str2.toCharArray();
        for(;i<s1.length&&j<s2.length;){
            if(s1[i++]==s2[j++]){
            }else{
            //这里是从第一次匹配的下一个位置再次比较,实际上存在一些无效比较,所以效率不高
                i=i-(j-1);
                j=0;
            }
        }
        if(j==s2.length){
            System.out.println("子串str2在母串str1中的起始与终止位为:【"+(i-j+1)+","+(i)+"】");
        }else{
            System.out.println("子串str2在母串str1中无匹配!");
        }
    }  
}

KMP法:

public class KMP {
    public void kmp(String str1,String str2){
        int i=0,j=0;
        //1.先求部分匹配值表:前后缀的重合元素的长度
        char[] s1=str1.toCharArray();
        char[] s2=str2.toCharArray();
        //获取子串的部分匹配值表
        int[] temp=getTable(str2);

        for(;i<s1.length;){
        //这一步是滤除母串中刚开始与子串不匹配的情况
            if(s1[i++]==s2[j]){
                for(j=1;j<s2.length;){
                    if(s1[i]==s2[j]){
                        i++;
                        j++;
                    }else{
                    //KMP核心操作:即当部分匹配之后出现不一致字符时,只需向前移动到在母串中与子串首字符相同的位置再次比较,减少了暴力匹配时的无效比较操作
                        i=i-temp[j-1];
                        j=0;
                        break;
                    }
                }
            }
            if(j==s2.length){
                break;
            }
        }
        if(j==s2.length){
            System.out.println("子串str2在母串str1中的起始与终止位为:【"+(i-j+1)+","+(i)+"】");
        }else{
            System.out.println("子串str2在母串str1中无匹配!");
        }
    }
    //获取子串的部分匹配值表
    public int[] getTable(String str){
        char[] s=str.toCharArray();
        int len=s.length;
        int[] temp=new int[len];
        temp[0]=0;
        for(int i=1,j=0;i<len;i++){
            //下面的代码是KMP的核心操作
            //当子串的后一个元素与前一个元素不相同时,比较再前的一个元素
            while(j>0&&s[i]!=s[j]){j=temp[j-1];}
            //当后一个元素与前一个相同时,j++
            if(s[i]==s[j]){
                j++;
            }
            temp[i]=j;
        }
        return temp;
    }
}

测试代码:

public class Test {
    public static void main(String[] args) {
        String str1="BBC ABCDAB ABCDABCDABDE";
        String str2="ABCDABD";
        Violence_Match violenceMatch=new Violence_Match();
        long t1=System.currentTimeMillis();
        violenceMatch.violence(str1,str2);
        long t2=System.currentTimeMillis();

        KMP k=new KMP();
        k.kmp(str1,str2);
        long t3=System.currentTimeMillis();
        System.out.println("暴力匹配时间:"+(t2-t1)+",KMP匹配时间:"+(t3-t2));

    }
}

结果:

子串str2在母串str1中的起始与终止位为:【16,22】
子串str2在母串str1中的起始与终止位为:【16,22】
暴力匹配时间:1,KMP匹配时间:3

分析:
可以看到暴力法所需的时间较少,而KMP的时间较多。这是由于KMP算法需要生成一个部分匹配值表,在小样本情况下,用时会比暴力法长,但当样本量较大时,其效率必然会比暴力法高的多。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值