字符串匹配(KMP)算法及Java实现

一、什么是KMP算法?


维基百科的解释是:在计算机科学中,Knuth-Morris-Pratt字符串查找算法(简称为KMP算法)可在一个主文本字符串S内查找一个词W的出现位置。此算法通过运用对这个词在不匹配时本身就包含足够的信息来确定下一个匹配将在哪里开始,从而避免重新检查先前已经匹配过的字符。


二、字符串的前缀与后缀


前缀:字符串除了最后一个字符的全部头部组合;

后缀:字符串处理第一个字符的全部头部组合;例如

三、字符串部分匹配表


"部分匹配"的实质是,有时候,字符串头部和尾部会有重复。比如,"ABCDAB"之中有两个"AB",那么它的"部分匹配值"就是2("AB"的长度)。搜索词移动的时候,第一个"AB"向后移动4位(字符串长度-部分匹配值),就可以来到第二个"AB"的位置。所以我们需要找到一个字符串中每一个子串的匹配值,即找到字符串的部分匹配值表,这样的话我们在下面匹配字符串的过程中就可以根据匹配表来进行跳跃了,而不必一个一个字符往后移,这就是关键所在。

四、KMP算法实现过程


简单来说,KMP算法就是根据上面我们已经得到的部分匹配表来判断:匹配过程中发现子串的某个字符与待匹配串不对应时,子串应该往后移几位。

移动的位数 = 已经匹配成功的串的总长度 - 已经匹配成功的串的部分匹配值

有些绕,举个栗子,假如我要判断字符串"BBC ABCDAB ABCDABCDABDE"中是否含有串“ABCDABD”,我把前面这个长串叫做待匹配串,把“ABCDABD”叫做子串(有可能叫法不对但明白就行)。

匹配的过程为:

将字符串"BBC ABCDAB ABCDABCDABDE"的第一个字符与搜索词"ABCDABD"的第一个字符,进行比较。因为B与A不匹配,所以搜索词后移一位。直到有匹配的字符位置,如下:

图中当匹配到D时发现不对应了,此时:

已经匹配成功的串为:ABCDAB

已经匹配成功的串的总长度:6

已经匹配成功的串的部分匹配值 :2

移动的位数 = 6 - 2,直接将子串往后移动4位,继续开始匹配

一样的道理,此时已经匹配成功的串为AB,移动的位数 = 2 - 0,往后移动2位继续匹配

没有匹配成功的串,往后移一位

已经匹配成功的串为:ABCDAB,ABCDAB的部分匹配值为2,移动的位数 = 6 - 2,往后移动4位

此时子串所有的字符都被匹配,搜索完成。

五、Java实现

public class KmpAlgo {
    //寻找待匹配串的部分匹配值,放在next数组中
    static void getNext(String pattern,int[] next){
        int j = 0;
        int k = -1;
        next[0] = -1;
        int len = pattern.length();
        while(j < len-1){
            if(k == -1 || pattern.charAt(j) == pattern.charAt(j)){
                j++;
                k++;
                next[j] = k;
            }else{
                k = next[k];
            }
        }
        
    }
    
    static int kmp(String s,String pattern){
        int i = 0;
        int j = 0;
        int slen = s.length();
        int plen = pattern.length();
        int[] next = new int[plen];
        getNext(pattern,next);
        while(i < slen && j < plen){
            if(s.charAt(i) == pattern.charAt(j)){
                i++;
                j++;
                
            }else if(next[j] == -1){
                i++;
                j = 0;
            }else{
                j = next[j];
            }
            if(j == plen){
                return i-j;
            }
        }
        return -1;
        
    }
    /**
     *@param
     */
    public static void main(String[] args){
        String str = "ABCDABDEYGF";
        String pat = "ABCDABD";
        //KmpAlgo.kmp(str, pat);
        System.out.println(KmpAlgo.kmp(str, pat));
    }

}

原文地址:http://blog.51cto.com/acevi/2104820

时间: 2024-08-29 11:33:03

字符串匹配(KMP)算法及Java实现的相关文章

字符串匹配KMP算法C++代码实现

看到了一篇关于<字符串匹配的KMP算法>(见下文)的介绍,地址:http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html,这篇博客对KMP算法的解释很清晰,但缺点是没有代码的实现.所以本人根据这位大神的思路写了一下算法的C++实现. C++代码如下: #include <iostream> #include<string.h> using namesp

字符串匹配--kmp算法原理整理

kmp算法原理:求出P0···Pi的最大相同前后缀长度k: 字符串匹配是计算机的基本任务之一.举例,字符串"BBC ABCDAB ABCDABCDABDE",里面是否包含另一个字符串"ABCDABD"? 许多算法可以完成这个任务,Knuth-Morris-Pratt算法(简称KMP)是最常用的之一. KMP算法搜索如下: 1.首先,字符串"BBC ABCDAB ABCDABCDABDE"的第一个字符与搜索词"ABCDABD"的

字符串匹配 - KMP算法

首先大致的学习一下有限自动机字符匹配算法,然后在讨论KMP算法. 有限自动机 一个有限自动机M是一个五元组(Q,q0,A,Σ,δ),其中: Q是状态的集合, q0∈Q是初始状态, A是Q的字集,是一个接受状态集合, Σ是一个有限的输入字母表, δ是一个从Q×Σ到Q的函数,叫做转移函数. 下面定义几个相关函数: φ(w)是M在扫描字符串w后终止时的状态.函数φ有下列递归关系定义:φ(ε) = q0,φ(wa) = δ(φ(w),a), σ(x)是x的后缀中,关于P的最长前缀的长度. 字符串匹配自动

字符串匹配KMP算法的理解(详细)

1. 引言 本KMP原文最初写于2年多前的2011年12月,因当时初次接触KMP,思路混乱导致写也写得混乱.所以一直想找机会重新写下KMP,但苦于一直以来对KMP的理解始终不够,故才迟迟没有修改本文. 然近期因开了个算法班,班上专门讲解数据结构.面试.算法,才再次仔细回顾了这个KMP,在综合了一些网友的理解.以及算法班的两位讲师朋友曹博.邹博的理解之后,写了9张PPT,发在微博上.随后,一不做二不休,索性将PPT上的内容整理到了本文之中(后来文章越写越完整,所含内容早已不再是九张PPT 那样简单

字符串匹配KMP算法

1. 字符串匹配的KMP算法 2. KMP算法详解 3. 从头到尾彻底理解KMP

字符串匹配-KMP算法学习笔记

参考文章: 1.字符串匹配的KMP算法 2.KMP算法详解 3.从头到尾彻底理解KMP 版权声明:本文为博主原创文章,未经博主允许不得转载.

数据结构与算法简记--字符串匹配KMP算法

KMP算法 比较难理解,准备有时间专门啃一下. 核心思想与BM算法一样:假设主串是 a,模式串是 b.在模式串与主串匹配的过程中,当遇到不可匹配的字符的时候,我们希望找到一些规律,可以将模式串往后多滑动几位,跳过那些肯定不会匹配的情况. 不同的是:在模式串和主串匹配的过程中,把不能匹配的那个字符仍然叫作坏字符,把已经匹配的那段字符串叫作好前缀. 关键找相等的最长匹配前缀和最长匹配后缀.有两种情况,(1)如果b[i-1]的最长前缀下一个字符与b[i]相等,则next[i]=next[i-1]+1.

字符串匹配KMP算法实现

由于KMP算法比较难,所以建议初学者分两个阶段学习. 第一个阶段先理解算法思想,可以参考这篇文章:点击打开链接 第二个阶段,理解算法的具体实现,本文主要讲解这部分,需要注意的地方都在程序里了,自己看吧 程序(调试通过): #include <stdio.h> #include <string.h> int KMP(char* s, char* pattern, int start, int next[]); void get_new_next(char* pattern, int

【数据结构与算法】字符串匹配KMP算法

首先需要了解一下BF暴力匹配算法,这个算法为每一个串设置一个指针,然后两个指针同时后移,出现不匹配的情况后,主串指针回到开始后移之前的位置的下一位,模式串指针回到最开始. 对比一下KMP算法,同样是设置两个指针,然后两个指针同时后移,出现不匹配的情况后,主串指针不变,模式串指针回溯一定的距离.具体模式串指针回溯多少,是第一次看KMP算法的人比较难以理解的,其实仔细想想,模式串的前缀和后缀其实也是在做匹配,当P[K]!=P[J]时就是失配,那么前缀的指针就需要回溯,所以后k=next[k]. 代码

字符串匹配——KMP算法(C++)

源代码: #include<cstdio> #include<cstring> #include<iostream> using namespace std; string s1,s2; int m,n,k(0),next[1001]; //在Next数组中,存储的是匹配失败后,上一位应该跳跃到的节点编号. int main() { getline(cin,s1); getline(cin,s2); m=s1.size(); n=s2.size(); next[0]=0