字符串匹配算法加速-KMP

数据结构学习总结:

一、KMP简介

kmp算法,也就是用于字符串匹配中的一种算法。(即解决一个主串中是否包含给定子串)

  • 普通暴力解法:在两个字符串匹配过程中,当遇到不匹配时,匹配串需要往后挪一位,从头开始重新再匹配。时间复杂度为O(N*M) (N为主串的长度,M为匹配串的长度)
  • 而KMP算法,是为了在不匹配的时候,能让匹配串多往后挪几位。加速匹配。将时间复杂度降为O(N)
    在这里插入图片描述

二、代码实现

2.1 思路:

(1) 首先要理解一个概念。
即=》某一个字符的前缀和后缀匹配的最长长度。
假设子串为abcabck,那么k字符位置之前的字符串的前缀和后缀匹配的最长长度为3.在这里插入图片描述
同理,如果字符串为aaaaaab。那么b位置时的前缀和后缀匹配时的最长长度为5.

(2) 假设要在abcdedfdfdg中查找能匹配abkm的子串。那么我们就对abkm中的每一个字符建立刚刚1中所说的最长匹配长度。
即分别在a,b, k, m各个位置建立各个字符的前缀和后缀匹配的最长长度。最后的结果就会对应一个数组。先叫它next[4] 数组。假设字符串为aabad。那么该对应的next数组就是[-1,0,1,0,1];(最前面的a字符前没有字符,人为规定它的前缀和后缀匹配时的最长长度为-1).
(3) 现在我们有next[]数组(具体求解算法,稍后再详细说。现在只需要先理解next[]所包含的信息是什么意思即可)。那么如何利用next[]数组来加速匹配过程,即 在不匹配时可以一次性往后多挪几位。
用next[] 数组加速实现原理如下:
在这里插入图片描述
KMP解法下:

在这里插入图片描述

2.2 代码

(1)主串和子串匹配过程的代码

 /**
     * 两个字符串的匹配过程
     *
     * @param s 主串
     * @param m 模式串
     * @return 返回匹配的第一个字符位置
     */
    public int getRes(String s,String m){
        if(s==null || m==null || m.length()>s.length()){
            return -1;
        }
        char[] str = s.toCharArray();
        char[] match =m.toCharArray();
        int x=0;//表示str中当前比对的位置
        int y=0;//表示match中当前比对的位置
        int[] next = getNextArray(match);//表示match中第i个字符前的前缀和后缀匹配的最大长度
        while(x<str.length && y<match.length){
            if(str[x] == match[y]){
                x++;
                y++;
            }else if(next[y] ==-1){ //说明match数组在第一个位置的字符就不匹配
                x++;
            }else{//主串中当前比对位置不变,子串的比对位置变动
                y=next[y];
            }
        }
        return y==match.length?x-y:-1;
    }

(2) next数组的生成
在这里插入图片描述

 private int[] getNextArray(char[] match) {
        int[] next =new int[match.length];
        if(match.length==0){
            return new int[]{-1};
        }
        next[0] =-1;//人为规定
        next[1] =0;
        int i =2;
        int cn =0;//和当前i-1位置比对的位置.初始值为0.因为当前i在2.i-1就为1.那么与1位置比较的位置就是0位置
        while(i<match.length){
            if(match[i-1]==match[cn]){
                next[i] =cn;
                i++;//求下一个next i
                cn++;
            }else if(cn>0){
                cn = next[cn];
            }else{
                next[i++] =0;
            }
        }

        return next;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值