博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
KMP算法详解
阅读量:4878 次
发布时间:2019-06-11

本文共 3015 字,大约阅读时间需要 10 分钟。

KMP算法主要用于解决包含问题,即存在两个字符串str1和str2,判断str1字符串中是否包含字符串str2,包含则返回str2对应在str1中的字符串的首字符的位置,否则返回-1;

例如:str1="abc123def"  str2="123d"   ,str1的长度为N,      str2的长度为M,则返回3;

      那么如何解决这类问题呢?正常的解法所用时间复杂度为O(N*M),即一个一个字符进行匹配,匹配不成功,则str1索引向后移动一位,str2重新从首字符进行匹配。

     使用KMP算法解决这个问题的时间复杂度为O(N),默认M<N,如M>N,则不用匹配。

 

介绍KMP算法之前,我们来先介绍最长前缀和最长后缀:

例如  str="abcabcd"    求字符‘d’ 的最长前缀和最长后缀的匹配长度,先求字符'd'的前缀数组和后缀数组

d的前缀数组:“a”,"ab","abc","abca","abcab"  前缀数组中的字符串中不包含最后一个字符(即‘d’的前一个字符'c')

d的后缀数组:"c", "bc","abc","cabc","bcabc"   后缀数组中的字符串中不包含第一个字符(即首字符‘a’)

从上面可以看出字符‘d’ 的最长前缀和最长后缀的匹配长度为3,即均为"abc",则我们定义'd'字符上的位置(属于位置6)的next[6]=3;

依次我们来求next[0],next[1],next[2],next[3],next[4],next[5].

0位置和1位置上不存在前缀和后缀,因此我们人为定义next[0]=-1,next[1]=0;

针对位置2(字符‘c’),我们可以看出,前缀数组为:"a",后缀数组为:"b",显然最长前缀和最长后缀的匹配长度为0,故next[2]=0;

针对位置3(字符‘a’) ,我们可以看出,前缀数组为:"a","ab",后缀数组为:"c","bc",显然最长前缀和最长后缀的匹配长度为0,故next[3]=0;

针对位置4(字符‘b’) ,我们可以看出,前缀数组为:"a","ab","abc",后缀数组为:"a","ca","bca",显然最长前缀和最长后缀的匹配长度为1,故next[4]=1;

针对位置5(字符‘c’) ,我们可以看出,前缀数组为:"a","ab","abc","abca",后缀数组为:"b","ab","cab","bcab",显然最长前缀和最长后缀的匹配长度为2,故next[5]=2;

上面解释的KMP算法中next数组的来源,那么我们怎么用比较优秀的算法来求这个next数组呢?

1)求next[i],需要根据next[i-1]来求,首先,定义cn = next[i-1],判断str[i-1]是否与str[cn]相等,

    如例子1:str[i-1]==str[cn]=‘c’,则next[i]=cn+1=3,此处cn=next[i-1]=2

   如例子2和3:str[i-1]!=str[cn],即'c'!='t' , 'c'!='a',此处cn =next[i-1]=4,此时将cn前跳,即cn = next[4]=2

                     继续比较str[i-1]是否等于str[cn],如例子2和3所示,例子3显示‘a’=='a',故针对例子3,next[i]=cn+1=3,

                                                                                           例子2显示‘a’!=t,故cn继续前跳,cn=next[cn]=next[2]=0;

               例子2继续比较str[i-1]是否等于str[cn],此时‘a’!='t',cn继续前跳,发现已不能往前跳,故next[i]=0

                     

 求next数组代码如下所示:

//构造str2的next数组,规定next[0]=-1,next[1]=0;    //ababcababtk  ==> ababc ababtk,经过验证,以下代码为正确    public static int[] getNextArrays(String str) {        char[] strs = str.toCharArray();        int[] next = new int[str.length()];        int cn = 0;//为前跳位置        next[0] = -1;        next[1] = 0;        int i = 2;        while (i < next.length) {            if (strs[i - 1] == strs[cn]) {                next[i] = cn+1;                i++;                cn++;            } else if (cn > 0) {                cn = next[cn];//往前跳            } else {                next[i] = 0;                i++;            }        }        return next;    }

求完str2的next数组后,如何求的str2在str1字符串中所在的位置呢?此处是如何利用next数组进行加速处理的呢?

 

public static int getIndexOfString(String str1, String str2) {        int next[] = getNextArrays(str2);        char[] str1s = str1.toCharArray();        char[] str2s = str2.toCharArray();        int j = 0;//代表str1的索引        int i = 0;//代表str2的索引        while (i < str2.length() && j < str1.length()) {            if (str2s[i] != str1s[j]&&j>-1) {
//满足j>=0的要求 //当next[i]=0时,即i前面并没有最长前缀与最长后缀的匹配长度,此时从当前j位置开始比较起 //此处当next[i]=-1,j=0时,自动满足j=j+1。 j = j - next[i];//后退next[i]个字符,, i = 0;//重新开始比较 } else { i++; j++; } } if (i == str2.length()) {
//说明全部比较完,且在str1中找到str2的字符串 return j - i; } else { return -1; } }

 

 

转载于:https://www.cnblogs.com/zjf-293916/p/9221909.html

你可能感兴趣的文章
【转】Android 读取doc文件
查看>>
js 数据绑定
查看>>
jsp的C标签一般使用方法以及js接收servlet中的对象及对象数字
查看>>
H5 简介
查看>>
window.frameElement的使用
查看>>
nl命令
查看>>
如何使用jQuery $.post() 方法实现前后台数据传递
查看>>
Using Flash Builder with Flash Professional
查看>>
jsp/post中文乱码问题
查看>>
C# 插入或删除word分页符
查看>>
数据库数据的查询----连接查询
查看>>
html图片设置fixed消失,为什么fixed后,DIV7消失了,怎么显示出来?
查看>>
html5隐藏自定义控制按钮,用仿ActionScript的语法来编写html5——第七篇,自定义按钮...
查看>>
找不到可安装的ISAM ,asp.net读取数据丢失,解决的一列里有字符与数字的
查看>>
Java学习笔记三(对象的基本思想一)
查看>>
Bezier贝塞尔曲线的原理、二次贝塞尔曲线的实现
查看>>
Java程序(文件操作)
查看>>
Alignment (DP基础--最长上升子序列)
查看>>
KMP算法的Next数组详解
查看>>
Tarjan算法
查看>>