KMP算法-Java

KMP算法

KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt提出的,因此人们称它为克努特—莫里斯—普拉特操作(简称KMP算法)。
KMP算法的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。
具体实现就是通过一个next()函数实现,函数本身包含了模式串的局部匹配信息。KMP算法的时间复杂度O(m+n)

具体实现

x指针:用来做主串索引,y指针:用来做模式串索引。

重点:x不回溯,只通过移动y来匹配。

原理

  1. 开始时x、y都指向各自的第0个位置,当两个索引处字符相等,x、y向后移动。
  2. 当不相等时,y移动到next[y]元素对应的位置,x不变。
  3. 若y移动到-1处,x、y都向后移动。
  4. 当x遍历完成后,若匹配成功,x-y的值即为主串对应模式串开始的第一个字符的索引,若匹配失败,返回-1。

next数组

匹配过模式串前缀的“最长可匹配前缀子串”和“最长可匹配后缀子串”的最长共有元素的长度。

  • 例如:ABABC的next[y]=2。
  • next数组的第一个元素为-1。

前缀和前缀组合、后缀和后缀组合

  1. 前缀:去掉字符串最后一个元素后剩下的字符串
  2. 后缀:去掉字符串第一个元素后剩下的字符串

例如:ABABD前缀就是ABAB后缀就是BABD

  1. 前缀组合:前缀中,带有第一个元素的连续字符串组合
  2. 后缀组合:后缀中,带有最后一个元素的连续字符串组合

例如:ABABD前缀组合有‘A’,‘AB’,‘ABA’,‘ABAB’;后缀组合有:‘D’,‘BD’,‘ABD’,‘BABD’。

Java代码

/**
 * @Projectname: Demo
 * @Filename: KmpTest
 * @Description: TODO
 * @Author: renrongfu
 * @Data:2022/8/17 下午5:49
 **/
import java.util.Arrays;

/**
 * ClassName: KmpTest
 * Description:
 * date: 2021/2/19 10:15
 *
 * @author ZhuQiPeng
 * @since JDK 1.8
 */
public class KmpTest {

    public static void main(String[] args) {
		//主串
        String desStr = "BABABACABABCABAABD";
        //模式串
        String subStr = "ABABCABAAB";
		//y在next[y]继续移动
        int[] next = getNext(subStr);
        System.out.println(Arrays.toString(next));
		//计算模式串在主串开始的位置,有则打印开始时主串的下标,无则打印-1
        int index = kmp(desStr,subStr);
        System.out.println(index);

    }
	//计算next[]数组
    public static int[] getNext(String subStr){
        //数组长度为模式串的长度
        int[] next = new int[subStr.length()];
        //next数组第一个元素为-1
        next[0] = -1;
        //定义len索引记录相邻之间的元素是否相同
        //定义y指针来为数组每一个位置赋值
        int len = -1, y = 0;
		//当y到达模式串长度-1的时候,循环结束,数组赋值完成
        while (y < subStr.length() - 1){
			//当len等于-1的时候,已经在数组的头部,无法在减
            //或者当len位置的数组元素和y位置的数组元素相同,为数组下一个位置赋值
            //否则,len就返回到next[len]的位置,继续循环
            if(len == -1 || subStr.charAt(len) == subStr.charAt(y)) {
                y++;
                len++;
                next[y] = len;
            }else{
                len = next[len];
            }
        }
        //最后,返回next数组
        return next;
    }
	//核心KMP算法代码
    public static int kmp(String desStr, String subStr){
        //定义x、y两个指针,进行遍历
        int x = 0,y = 0;
        //拿到next数组
        int[] next = getNext(subStr);
		//遍历条件,不用多说
        while (x < desStr.length() && y < subStr.length()){
            //y等于-1时,正好在模式串的头部,可以和主串进行对比
            if(y == -1 || subStr.charAt(y) == desStr.charAt(x)){
                x++;
                y++;
            }else{
                y = next[y];
            }
        }
		//遍历完成后,如果y的值刚好等于主串的长度,那么x-y的长度就是模式串在主串中开始的位置
        if (y == subStr.length()){
            return x-y;
        }else{
            return -1;
        }
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值