KMP 字符串匹配算法

KMP字符串匹配算法

          KMP 是由三个计算机科学家首字母命名的字符串匹配算法,主要实现思路是

           出现第1个不匹配的坏味道字符时,记录模式串匹配的前缀,计算出匹配前缀,需要移动到 “不匹配字符” 的位置;

          减少主串和模式串 一一对应 比较的次数。

           KMP 算法空间复杂度为: O(n+m); 其中主串长度:n, 模式串长度为:m

   实现思路:       

             主串:    G T G T G A G C T G
            模式串: G T G T G C F          对应数组下标为 0 1 2 3 4 5 6

          第一轮比较,标识第1个不匹配坏味道字符,如下;

             主串:     G T G T G A G C T G
             模式串: G T G T G C F

            可以看到模式字符串的匹配前缀为: G T G T G,根据匹配前缀,前3个字符的和后3个字符是一样的,这样就可以进行如下操作:

                模式串下标为3的字符 移动到 主串 A(不匹配字符) 的位置

          第二轮比较,标识第1个不匹配坏味道字符,如下;

                  主串:     G T G T G A G C T G
                  模式串:        G T G T G C F

                  可以看到模式串 匹配前缀为: G T G,  根据匹配前缀,可以进行如下操作: 

                      模式串下标为1的字符  移动到 主串 A(不匹配字符) 的位置

          第三轮比较,标识第1个不匹配坏味道字符,如下;

                 主串:     G T G T G A G C T G
                  模式串:              G T G T G C F

          根据这三轮的比较和移动,我们可以总结出KMP 算法的核心:

                   当出现第1个不匹配坏字符的时候,根据“匹配前缀” 计算出 移动 “模式串” 的下标为i的字符 到 坏字符的位置,

                   并且保证 “模式串” 中小于下标i的字符串和主串是匹配的。

          从中我们可以指定:移动“模式串”下标i到 主串 坏字符位置,只和 “匹配前缀”有关;“匹配前缀” 只和 “模式串” 有关

         这样就可以引入一个 next 数组,来记录 “匹配前缀”的移动“模式串”的下标位置,next 数组是kmp算法的灵魂,理解了next数组的

        计算逻辑,就能完全理解 kmp 算法;以下先给出 next 数组:

           next 数组:   

值(移动模式串下标)0001230
下标(模式串下标)0123456
字符GTGTGCF


                                

        模式串数组:p                     

GTGTGCF
下标0123456

             next 数组的计算过程如下:

                     步骤1 :开始时: i=2,j = 0, i>j; next[0] = 0;next[1]=0

                      步骤2 :如果 p[i-1] = p[j] 时,next[i] = ++j, 否则到步骤3

                      步骤3 :当j=0 时 next[i] = 0;j 不为0,则取 j=next[j] 回溯 步骤2 

                      步骤4: i++

                      步骤1-4 重复,直到i达到模式串最大长度

     JAVA 代码实现:

public class KMP {
    public static int kmp(String str,String pattern) {
        int[] next = getNext(pattern);
        int j = 0;
        for(int i =0; i< str.length(); i++) {
            while (j!=0 && str.charAt(i) != pattern.charAt(j)) {
                //遇到坏字符时,查询next数组并改变模式串的起点
                j = next[j];
            }
            if(str.charAt(i) == pattern.charAt(j)) {
                j++;
            }
            if(j == pattern.length()) {
                return i - j + 1;
            }
        }
        return -1;
    }

    public static int[] getNext(String pattern) {
        int[] next = new int[pattern.length()];
        int j = 0;
        next[0] = 0;
         for(int i=2; i<pattern.length(); i++) {
             //从next[i+1]的求解回溯到next[j]
             while (j>0 && pattern.charAt(i-1) != pattern.charAt(j)) {
                 j = next[j];
             }
             if(pattern.charAt(i-1) == pattern.charAt(j)) {
                 j++;
             }
             next[i] = j;
         }

         return next;
    }
}

参考文章:https://baijiahao.baidu.com/s?id=1659735837100760934&wfr=spider&for=pc

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值