简洁

我相信很多人都听说过KMP算法(PS:在上数据结构的时候,这个算法自始至终都没想明白)

大家也知道KMP算法是用来寻找目标子串的算法,但是都没有真正搞懂KMP。之前,我也是如此,我疑惑的有:

  1. Next数组中的值是如何定下来的?
  2. 得到Next数组以后,又是如何遍历的?

希望这篇文章能对你们有所帮助!

视频推荐

KMP这种算法,单单靠看文章,还是很难弄懂的,结合图像,以及视频的帮助会更容易弄懂。这里我推荐一个视频:KMP算法

个人也是通过这个视频,恍然大悟的。这里还是非常感谢这位作者的分享。

个人总结

通过上述视频,我想大家应该都有一个大概的了解了。该算法我将它划分为两个部分:

  1. 求Next数组
  2. 匹配字符串

我将分这两个部分进行细致讲解

第一部分

求Next数组是KMP算法的重点,也是难点!想搞懂这部分一定要看视频!一定要看视频!一定要看视频!我觉得上述的视频,将这部分说的很清楚了。这里做一个总结:(视频里将目标子串的第i号位置映射到Next指针的第i+1号位置。我这里根据程序员的习惯,将目标子串的第i号位置映射到Next指针的第i号位置)

我将Next[i]做一下定义:

/*Next[i]表示:
* 如果(substr.charAt(i) != str.charAt(j)),这时候,将i = Next[i],再进行字符串匹配。
*/

这种表达虽然不严谨,但是我感觉比较直观hhhh。也即:如果目标子串第i个的值与匹配串第j的值不一致的时候,将目标子串向右滑动,滑动到i = Next[i]。

Next[i]值的定义:

/*Next[i]的值为:
* 第0位为头的字符串s1,与第i-1为尾的字符串中s2,寻找他们的最长真子串。
* 真子串:这个真子串,就是s1的长度要小于i-1。因为这两个子串如果是相同的,就没有意义了
*/

上面这两个定义值得细品,这也是KMP的精髓,也正是Next数组,KMP算法才能更加高效!

其中需要注意的点是:Next[0] = 0,Next[1] = 0,因为从第2个开始,s1和s2才有意义。

看完上述定义,我将求Next数组的函数实现出来。注:该函数求Next数组时间复杂度较高,因为是最原始的思路,大家可以想想有什么简化的思路,可以在评论区留言,之后我有时间进行改进

/**
* 该函数是为了,根据目标子串subStr,求解该子串的Next数
* @param 目标子串substr
* @return subStr的Next数组
*/
static int[] CalculateNext(String substr){
//init
int[] Next = new int[substr.length()];
//求解Next[i]
for(int i = 2; i < substr.length(); i++){
//第0位为头的l字符串,与第i-1为尾的r字符串
int left = 0; int right = i - 1;
String l = Character.toString(substr.charAt(left));
String r = Character.toString(substr.charAt(right));
int maxLen = 0;
//当l与r均为真子串的时候
while(left < i - 1){
//如果两个字符串相同,说明这是目前最长的公共子串
if(l.equals(r)) maxLen = l.length();
left++;
right--;
//继续扩大搜索范围
l = l + Character.toString(substr.charAt(left));
r = Character.toString(substr.charAt(right)) + r;
}
//最终的maxLen即为Next[i]的值
Next[i] = maxLen;
}
return Next;
}

第二部分

这个部分就简单很多了,只要注意一点小细节,整体思路非常清晰直观:

在保证目标子串与匹配串匹配的过程中,不会越界的情况下:进行目标子串的滑动操作

subStr.charAt(i) == str.charAt(j)的时候,i与j同时往右移动即可,当完全匹配的时候,就返回

subStr.charAt(i) != str.charAt(j)的时候,i = Next[i]即可。

这里j需要注意一个细节,如果i == 0,需要j往右移一位,因为第一位都不匹配,前面就再也没有能匹配的字符串了。

/**
* 该函数用于查看目标子串在匹配串中第一次出现的位置
* @param 目标子串subStr
* @param 匹配串str
* @param Next数组
* @return str中,第一次出现subStr的位置
*/
static int findPosition(String subStr,String str,int[] Next){
//初始化两个字符串的指针
int i = 0;
int j = 0;
//保证目标子串与匹配串匹配的过程中,不会越界
while(j + subStr.length() - i <= str.length()){
//当匹配的时候,i与j同时往右移
if(subStr.charAt(i) == str.charAt(j)){
i++;j++;
//当完全匹配的时候,返回
if(i == subStr.length()) return j - subStr.length();
}
//不匹配的时候,匹配串指针j只有在i = 0的时候,才右移动。
else {
if(i == 0) j++;
//i值都需要更新
i = Next[i];
}
}
return -1;
}

总结

这里主要探讨的是Next数组,这个是KMP算法的核心!以前考试都是考Next数组的求解,可见Next数组的重要性。

KMP算法,你想知道的都在这里!的更多相关文章

  1. 扩展KMP算法

    一 问题定义 给定母串S和子串T,定义n为母串S的长度,m为子串T的长度,suffix[i]为第i个字符开始的母串S的后缀子串,extend[i]为suffix[i]与字串T的最长公共前缀长度.求出所 ...

  2. [Algorithm] 字符串匹配算法——KMP算法

    1 字符串匹配 字符串匹配是计算机的基本任务之一. 字符串匹配是什么?举例来说,有一个字符串"BBC ABCDAB ABCDABCDABDE",我想知道,里面是否包含另一个字符串& ...

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

    本文主要的思路都是参考http://kb.cnblogs.com/page/176818/ 如有冒犯请告知,多谢. 一.KMP算法 KMP算法可以在O(n+m)的时间数量级上完成串的模式匹配操作,其基 ...

  4. KMP算法解析(转自图灵社区)

    KMP算法是一个很精妙的字符串算法,个人认为这个算法十分符合编程美学:十分简洁,而又极难理解.笔者算法学的很烂,所以接触到这个算法的时候也是一头雾水,去网上看各种帖子,发现写着各种KMP算法详解的转载 ...

  5. 字符串匹配的KMP算法

    ~~~摘录 来源:阮一峰~~~ 字符串匹配是计算机的基本任务之一. 举例来说,有一个字符串”BBC ABCDAB ABCDABCDABDE”,我想知道,里面是否包含另一个字符串”ABCDABD”? 许 ...

  6. 深入理解KMP算法

    前言:本人最近在看<大话数据结构>字符串模式匹配算法的内容,但是看得很迷糊,这本书中这块的内容感觉基本是严蔚敏<数据结构>的一个翻版,此书中给出的代码实现确实非常精炼,但是个人 ...

  7. 初探KMP算法

            数据结构上老师也没讲这个,平常ACM比赛时我也没怎么理解,只是背会了代码--前天在博客园上看见了一篇介绍KMP的,不经意间就勾起了我的回忆,写下来吧,记得更牢. 一.理论准备      ...

  8. KMP算法 --- 深入理解next数组

    在KMP算法中有个数组,叫做前缀数组,也有的叫next数组. 每一个子串有一个固定的next数组,它记录着字符串匹配过程中失配情况下可以向前多跳几个字符. 当然它描述的也是子串的对称程度,程度越高,值 ...

  9. KMP算法详解 --- 彻头彻尾理解KMP算法

    前言 之前对kmp算法虽然了解它的原理,即求出P0···Pi的最大相同前后缀长度k. 但是问题在于如何求出这个最大前后缀长度呢? 我觉得网上很多帖子都说的不是很清楚,总感觉没有把那层纸戳破, 后来翻看 ...

随机推荐

  1. UML——活动图

    宏观导图 是森马?   活动图,属于UML中动态建模工具图,它描述活动的顺序,展现从一个活动到另一个活动的控制流.活动图着重表现从一个活动到另一个活动的控制流,是内部处理驱动的流程.   其实,说白了 ...

  2. 使用两个FIFO完成流水操作

    一.设计目标 写一个FIFO控制器,控制器里有两个FIFO,输入的数据由串行接收模块(uart_rx_module)送来,一共有86行86列的数据,按0.1.2行,1.2.3行,直到最后83.84.8 ...

  3. ProBuilder快速原型开发技术 ---操作基础

    本篇文章笔者对ProBuilder(以下简称:PB),进行操作基础的介绍. 一:PB大小图标显示方式 PB操作面板有两种显示方式:小图标与大图标.大图标优点是显示清晰操作方便,缺点是没有更加精确的参数 ...

  4. poj3087 Shuffle'm Up

    Description A common pastime for poker players at a poker table is to shuffle stacks of chips. Shuff ...

  5. Codeforces Round #649 (Div. 2) C、Ehab and Prefix MEXs D、Ehab's Last Corollary 找环和点染色

    题目链接:C.Ehab and Prefix MEXs 题意; 有长度为n的数组a(下标从1开始),要求构造一个相同长度的数组b,使得b1,b2,....bi集合中没有出现过的最小的数是ai. mex ...

  6. Docker文件挂载总结

    Docker容器启动的时候,如果要挂载宿主机的一个目录,可以用-v参数指定. 譬如我要启动一个centos容器,宿主机的/test目录挂载到容器的/soft目录,可通过以下方式指定: # docker ...

  7. PTA L1-006 连续因子【暴力模拟】

    一个正整数N的因子中可能存在若干连续的数字.例如630可以分解为3*5*6*7,其中5.6.7就是3个连续的数字.给定任一正整数N,要求编写程序求出最长连续因子的个数,并输出最小的连续因子序列. 输入 ...

  8. 洛谷p1637 三元上升子序列(树状数组

    题目描述 Erwin最近对一种叫"thair"的东西巨感兴趣... 在含有n个整数的序列a1,a2......an中, 三个数被称作"thair"当且仅当i&l ...

  9. Tomcat基本原理

    思考 :怎样让Tomcat具备Web服务的功能呢? 在服务端用HTTP来监听,协议不好写,不妨用Java封装好的Socket作为监听. class MyTomcat{ ServerSocket ser ...

  10. ZOJ 3430 Detect the Virus(AC自动机 + 模拟)题解

    题意:问你主串有几种模式串.但是所有串都是加密的,先解码.解码过程为:先把串按照他给的映射表变成6位数二进制数,然后首尾衔接变成二进制长串,再8位8位取变成新的数,不够的补0.因为最多可能到255,所 ...