KMP模式匹配算法--未优化

字符串的比配是一个很重要的点,去年参加校园招聘的时候考了这个,今天翻开以前的教程看到了KMP,就总结一下吧,其思想还是挺好的。

对于字符串匹配,最简单、最笨、最低效的方法就是循环匹配,也就是:从主串的第一个字符开始,依次与字串进行比较,即把主串的每一个字符当作字串的首字符,直到匹配成功或者遍历完主串(失败)。

可想而知其中包含了很多冗余的操作,因为某次匹配失败便要回滚主串到上次开始的下一个字符,开始下一轮匹配,然而有些回滚是不需要的,如:

1,字串中没有重复字符的时候:

主串:efgrabcdefgadad       用i循环

字串:efga                              用j循环

第一轮匹配(i=0):当i循环到3(主串的r位置)时,匹配失败(r和a不相同),便要开始下一轮匹配,即i回滚到1,j回滚到0

观察字串可以发现,e和后面的所有字符都不相同,同样,字串的e和主串的fg也不相同,所以不比较知道不相同,所以第二轮和第三轮比较可以直接跳过,即i不需要回滚

即下一轮比较只需要从i不变,j变为0开始;

2,字串中有重复字符的时候:

主串:abdfgabefaexababdfgabxggadad       用i循环

字串:abdfgabx                                                  用j循环

可以知道,第一轮匹配失败后,因为字串的a和bdfg都不相同,所以都不用比较,而ab和ab相同,不比较也知道,所以也不需要比较,所以下一轮比较只需要把j回滚到d的位置开始匹配即可,I不需要回滚;

从上面的分许可以看出,无论字串有没有重复,i都不需要回滚,只需要回滚j,而且重复和不重复的时候j的回滚是不相同的。

以上就是KMP算法的思想,旨在消除不必要的回滚,其最重要的就是next()方法(用于求出j下一次需要回滚到的位置)


例子:

1,main方法:

      public static void main(String[] args) {

       String sub = "abefr";
       String str = "dfabfeabefrfef";
       int[] next = next(sub);
       pattern(str,sub,next);
       

   }

输出:6

2,next()方法:
public static int[] next(String sub) {
         int[] next = new int[sub.length()];
         char[] subs = sub.toCharArray();
         int length = sub.length();
         
         int i,j;
         next[0] = -1;
         i = 0;
         for(j = 1;j < length;j++) {
            i = next[j - 1];
            while(i >= 0 && subs[j] != subs[i+1]) {
                i = next[i];    
            }
            
           if(subs[j] == subs[i+1]) {
          next[j] = i+1;
           }
           else {
          next[j] = -1;
           }
         }
         return next;

    }


3,匹配方法:
    public static void pattern(String str,String sub,int[] next) {
        char[] ch1 = str.toCharArray();
        char[] ch2 = sub.toCharArray();
        int i = 0,j = 0;  //i控制ch1,j控制ch2;
        for(;i < ch1.length; ) {
            if(ch1[i] == ch2[j]) {//匹配就自动递增,往后匹配。
                if(j == ch2.length-1) {
                    System.out.println(i-ch2.length+1);
                    break;
                }
                j++;
                i++;
            }
            else if(j == 0) {
                 i++;
            }
            else {
                j = next[j-1]+1;
            }
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值