KMP算法-Java实现

目的:

为了解决字符串模式匹配

历程:

朴素模式匹配:逐次进行比较

KMP算法:利用匹配失败得到的信息,来最大限度的移动模式串,以此来减少比较次数提高性能

概念:

m:是目标串长度

n:是模式串长度

j:某次匹配时,第一次出现的不同的索引位置(有的称为:失配位

k:最长首尾串长度(有的称为:最长公共前后缀

核心思想:

S   S0 S...... Si-j-1 Si-j Si-j+1 Si-j+2 ...... Si-2 Si-1 Si ...... Sn-1

||     ||      ||            ||   ||   ×

P                            P0    P1      P2              Pj-2 Pj-1 Pj

有Si-j-1Si-jSi-j+1 Si-j+2 ...... Si-2 Si-1=P0P1 P2 ...... Pj-2 Pj-1

如果  P0P1 P2 ...... Pj-2 ≠ P1 P2 ...... Pj-2Pj-1

则可以立即断定 P0P1 P2 ...... Pj-2 ≠ Si-j+1 Si-j+2 ...... Si-2 Si-1,即:朴素模式匹配的下一次移动一定不匹配,则可以跳过这一次

如果  P0P1 P2 ...... Pj-3 ≠ P2 ...... Pj-2Pj-1

则可以立即断定 P0P1 P2 ...... Pj-2 ≠ Si-j+1 Si-j+2 ...... Si-2 Si-1,即:朴素模式匹配的下一次移动一定不匹配,则可以跳过这一次

直到第一次出现相等的情况终止:P0P1 P2 ...... Pk-1 = Pj-k ...... Pj-2Pj-1

得到的k就是最长的首尾串长度,然后通过 j-k 得到了我们需要移动的位数,这样我们就利用了匹配失败的结果,得到了我们可以移动的步数,提升了性能

关于k:

其实肉眼就直接能看出来,k是最长首尾串长度,比如:

11111 k=4(前缀:1111,后缀:1111)

12112 k=2(前缀:12,后缀:12)

12345 k=0(无相同前缀后缀)

例子:

S=ababababababb

P=abababb

重申一下原理:朴素模式匹配效率低的原因是一位一位的比较,丢弃了之前失败的信息。而KMP算法从匹配失败的信息中得到可以最大移动的步数,以此来减少比较的次数,来提升性能。

这里并没有提及,next数组及newnext数组,模式串的特征向量N,其实不用管它,思想理解了,只是别人起了个叫法而已。

Java代码:

    /**
     * 朴素模式匹配
     *
     * @param source 目标串
     * @param pattern 模式串
     */
    private static void plain(String source, String pattern) {
        int res=0;
        int sourceLength=source.length();
        int patternLength=pattern.length();
        for(int i=0;i<=(sourceLength-patternLength);i++){
            res++;
            String str=source.substring(i, i+patternLength);
            if(str.equals(pattern)){
                p("朴素模式:匹配成功");
                break;
            }
        }
        p("朴素模式:一共匹配"+res+"次数");
    }
    //KMP算法实现   private static void KMP(String source, String pattern) {
        int[] N=getN(pattern);
        int res=0;
        int sourceLength=source.length();
        int patternLength=pattern.length();
        for(int i=0;i<=(sourceLength-patternLength);){
            res++;
            String str=source.substring(i, i+patternLength);//要比较的字符串
            p(str);
            int count=getNext(pattern, str,N);
            p("移动"+count+"步");
            if(count==0){
                p("KMP:匹配成功");
                break;
            }
            i=i+count;
        }
        p("KMP:一共匹配"+res+"次数");
    }
    /**
     * 得到下一次要移动的次数
     *
     * @param pattern
     * @param str
     * @param N
     * @return 0,字符串匹配;
     */
    private static int getNext(String pattern,String str,int[] N) {
        int n = pattern.length();
        char v1[] = str.toCharArray();
        char v2[] = pattern.toCharArray();
        int x = 0;
        while (n-- != 0) {
            if (v1[x] != v2[x]){
                if(x==0){
                    return 1;//如果第一个不相同,移动1步
                }
                return x-N[x-1];//x:第一次出现不同的索引的位置,即j
            }
            x++;
        }
        return 0;
    }
    private static int[] getN(String pattern) {
        char[] pat=pattern.toCharArray();
        int j=pattern.length()-1;
        int[] N=new int[j+1];
        for(int i=j;i>=2;i--){
            N[i-1]=getK(i,pat);
        }
        for(int a:N)
            p(a);
        return N;
    }
    private static int getK(int j, char[] pat) {
        int x=j-2;
        int y=1;
        while (x>=0 && compare(pat, 0, x, y, j-1)) {
            x--;
            y++;
        }
        return x+1;
    }
    private static boolean compare(char[] pat,int b1,int e1,int b2,int e2){
        int n = e1-b1+1;
        while (n-- != 0) {
            if (pat[b1] != pat[b2]){
                return true;
            }
            b1++;
            b2++;
        }
        return false;
    }
    public static void p(Object obj) {
        System.out.println(obj);
    }

next数组:

KMP能提高性能原因是减少了比较次数,也就是知道k

而k从只和j有关,这就意味着移动的次数只和模式串有关,和目标串无关

简单来说,就是我们得到模式串后就能立马知道移动的次数,这就是next数组。里面储存的就是k值。

时间: 2024-10-29 19:11:48

KMP算法-Java实现的相关文章

KMP算法java实现

/** * 假设现在文本串S匹配到 i 位置,模式串P匹配到 j 位置 如果j = -1,或者当前字符匹配成功(即S[i] == * P[j]),都令i++,j++,继续匹配下一个字符: 如果j != -1,且当前字符匹配失败(即S[i] != P[j]),则令 i 不变,j = * next[j],此举意味着模式串P相对于文本串S向右移动了至少1位(换言之,当匹配失败时,模式串向右移动的位数为:失配字符所在位置 - * 失配字符对应的next 值,即移动的实际位数为:j - next[j],且

KMP 算法 java实现

KMP算法讲解 我的Java代码实现 package jj4_6; public class KMP { public static boolean contains(String a,String b){ /* * 第一步,对b字符串做一个预处理 */ Integer[] fuzhu = new Integer[b.length()]; for(Integer i= 0;i<b.length();i++){ // i == 3 时 // nowstr = "abab" Stri

Kmp算法Java代码实现

public class KMP { public static void main(String[] args) { String str="ababxbababcadfdsss"; String subStr="abcad"; int[] next=getNext(subStr.toCharArray()); int p=kmp(next,str.toCharArray(),subStr.toCharArray()); System.out.println(p)

hdu 2594 java实现字符串KMP算法

Problem Description Homer: Marge, I just figured out a way to discover some of the talents we weren't aware we had. Marge: Yeah, what is it? Homer: Take me for example. I want to find out if I have a talent in politics, OK? Marge: OK. Homer: So I tak

【数据结构&amp;&amp;算法系列】KMP算法介绍及实现(c++ &amp;&amp; java)

KMP算法如果理解原理的话,其实很简单. KMP算法简介 这里根据自己的理解简单介绍下. KMP算法的名称由三位发明者(Knuth.Morris.Pratt)的首字母组成,又称字符串查找算法. 个人觉得可以理解为最小回溯算法,即匹配失效的时候,尽量少回溯,从而缩短时间复杂度. KMP算法有两个关键的地方,1)求解next数组,2)利用next数组进行最小回溯. 1)求解next数组 next数组的取值只与模式串有关,next数组用于失配时回溯使用. 在简单版本的KMP算法中,每个位置 j 的 n

经典KMP算法C++与Java实现代码

前言: KMP算法是一种字符串匹配算法,由Knuth,Morris和Pratt同时发现(简称KMP算法).KMP算法的关键是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的.比较流行的做法是实现一个next()函数,函数本身包含了模式串的局部匹配信息.由于next函数理解起来不太容易,本文同样是基于空间换时间的做法,但将采用另一种代码实现,希望可以更方便读者理解! 测试数据 aseeesatba esat as330kdwejjl_8 jjl_ faw4etoesting

Java实现KMP算法

转自:http://blog.csdn.net/tkd03072010/article/details/6824326 —————————————————————————————————— package arithmetic; /** * Java实现KMP算法 * * 思想:每当一趟匹配过程中出现字符比较不等,不需要回溯i指针, * 而是利用已经得到的“部分匹配”的结果将模式向右“滑动”尽可能远 * 的一段距离后,继续进行比较. * * 时间复杂度O(n+m) * * @author xqh

KMP算法详解及其Java实现

KMP算法,又称作"看猫片"算法(误),是一种改进的字符串模式匹配算法,可以在O(n+m)的时间复杂度以内完成字符串的匹配操作,其核心思想在于:当一趟匹配过程中出现字符不匹配时,不需要回溯主串的指针,而是利用已经得到的"部分匹配",将模式串尽可能多地向右"滑动"一段距离,然后继续比较. KMP(看猫片)算法 1. 朴素的字符串模式匹配算法 求一个字符串(模式串)在另一个字符串(主串)中的位置,称为字符串模式匹配. 在朴素的字符串模式匹配算法中,我

Java数据结构之字符串模式匹配算法---KMP算法

本文主要的思路都是参考http://kb.cnblogs.com/page/176818/ 如有冒犯请告知,多谢. 一.KMP算法 KMP算法可以在O(n+m)的时间数量级上完成串的模式匹配操作,其基本思想是:每当匹配过程中出现字符串比较不等时,不需回溯指针,而是利用已经得到的"部分匹配"结果将模式向右"滑动"尽可能远的一段距离,继续进行比较.显然我们首先需要获取一个"部分匹配"的结果,该结果怎么计算呢? 二.算法分析 在上一篇中讲到了BF算法,