KMP算法:最长字符串匹配算法

KMP算法:最长字符串匹配算法

查找模式串在目标串中的位置
例如:目标串"asdasdaabbccaabsesdf" 模式串:“aabbccaabse” 则返回6,表示从索引下标是6开始匹配。(假设模式串索引为6‘a’的前缀:(a、aa、aab、aabb、aabbc、aabbcc、ab、abb、…)
后缀也是一样,只不过是以索引6‘a’为分割的后面字符串所有字串类型。(a、aa、aab、aabs、aabse、ab、abs、abse、…))
先讲解下思路:总体官方的话来说每次匹配失败时模式串则回退到n,关键核心思想是n是公共前缀和后缀的匹配个数,定义这个n的算法比较抽象。
模式串从左向右开始移动遍历:如果遍历到前面有相同的公共字串且当前字符和匹配到的字串下一位也相同则n+1,否则回到上一次匹配的地方,这个地方概念比较抽象,还是上图和代码。

示例演示:
设next数组用户保存当前字符公共前缀长度,模式串为pattern。设当前最大匹配前缀为j,向前遍历的索引为i。
模式字符串
设第一位的最大匹配为next[0] = -1,标志从头开始。I = 0,j = -1;最长前缀匹配为next[j] = j + 1;所以next[0] = 0;
I = 1,j = 0;Pattern[i] = a;Pattern[j] = a;最长前缀匹配为next[j] = j + 1;所以next[1] = 1;

I = 2,j = 1;Pattern[i] = b;Pattern[j] = a;因为:Pattern[i] != Pattern[j]; ①J = next[j] = 1; 回到①递归匹配
以上方法一次类推得到next数组。得next = {-1, 0, 1, 0, 0, 0, 1};
求得next数组后就好求了。

代码片段如下:

public static int[] next(String pattern){

    char[] chars = pattern.toCharArray();
    int i = 0;//当前移动指针,-1可以判断开始点
    int j = -1;//当前前缀和后缀匹配度
    int length = pattern.length();
    int[] next = new int[length];
    next[0] = -1;

    while (i < length - 1) {

        if (j == -1 || chars[i] == chars[j]) {
            i++;
            j++;
            next[i] = j;
        }else {
            j = next[j];
        }


    }

    return next;
}

设目标字符串为:
目标字符串
模式字符串为上述字符串:
在目标字符串
一个一个比较:设i为目标串索引,j为模式串索引。I = 0,j = 0;A = a,I = 1,j = 1;Q != a,则模式串回退到next[1];I = 2,j = 0;判断next[j] == -1表示从头开始。则 i = 2,j = 0;A = a;i = 3,j = 1;
A = a;I = 4,j = 2;B = b;I = 5,j = 3;B = b;I = 6,j = 4;C = c;I = 7,j = 5;S!=a;则j = next[5] = 0;…以此类推,求完整个字符串,如果匹配成功则返回。

代码片段如下:

public static int kmp(String msg,String pattern){


    char[] msgs = msg.toCharArray();
    char[] patterns = pattern.toCharArray();
    int[] a = next(pattern);
    int i = 0, j = 0;
    while (i < msgs.length && j < patterns.length) {
        if (a[j] == -1 || msgs[i] == patterns[j]) {
            i++;
            j++;
        } else {
            j = a[j];
        }
    }
    if (j == patterns.length) {
        return i - j;
    }
    return -1;
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值