KMP算法详解

简介

一种高效的字符串匹配算法,算法核心是减少了字符串匹配循环的趟数,字符串匹配本身是无法优化的。

思路

KMP算法分为两个核心部分,一部分是计算next数组,一部分是利用next数组对模式字符串和主字符串的匹配。

假如现在有主字符串

S:A C T G P A C T G K A C T G P A C Y

P:A C T G P A C Y

如何计算next数组:

next数组是针对模式串P而言的,next[i]对应的下标,为P[0…i-1]的最长公共前后缀的长度,令P[0]=-1。下面这个参考leetcode的官网示例,链接地址:力扣

next数组计算过程是这样,如何编程呢:

比如对于前缀字符串ACTGPAC而言,我们定义一个指向主串的下标j,当j等于6时,得到主串的前缀子串ACTGPAC。此时next[j]=1,意味着ACTGPAC的前一个前缀子串ACTGPA存在最长公共前后缀的长度为1,如果ACTGPAC的next下标值为2的话,那ACTGPAC的最后一位C必然和前一个前缀子串ACTGPA的第二位字符相同,如果不同则next下标值为0。

如何利用next数组对模式字符串和主字符串匹配:

从S的第一位开始逐个比较和P的字符,当比较到i位置时,发现二者不匹配,此时P的i位置的字符为Y,next数组值为2,那么这里就是将j置到P的下标为2的位置就是T,接下来从P的j位置开始和S的i位置进行比较,直到S的最后一位。 

代码

public class Solution10 {
    public int match(String p, String s){
        int i = 0;
        int j = 0;
        int s_len = s.length();
        int p_len = p.length();
        int[] next = buildNext(p);
        while(i < s_len && j < p_len){
            if (j == -1 || s.charAt(i) == p.charAt(j)){
                i++;
                j++;
            }
            else {
                j = next[j];
            }
        }
        if (j == p_len){
            return i - j;
        }
        else {
            return -1;
        }
    }

    // 构造模式串P的next表,这里其实就是给定的模式串自己和自己比较,找到真前缀和后缀最大公共部分
    public int[] buildNext(String p){
        int len_p = p.length();
        // 定义next表
        int[] N = new int[len_p];
        N[0] = -1; // 方便编程
        int k = -1; // 模式串的指针
        int j = 0; // “主串”的指针
        while (j < len_p - 1){ // 不包括模式串本身,所以最后一位不考虑
            if (k == -1 || p.charAt(j) == p.charAt(k)){ // 当“主串”的指针对应的字符和模式串的指针对应的字符相同,N[j]的值等于k+1值
                ++k;
                ++j;
                N[j] = k;
            }else {
                k = N[k];
            }
        }
        return N;
    }

    public static void main(String[] args) {
        Solution10 solution10 = new Solution10();
        System.out.println(solution10.match("ACTGPACY", "ACTGPACTGKACTGPACY"));
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值