简洁

我相信很多人都听说过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. centos安装、升级新火狐最新版 31

    1.登录火狐主页 下载最新版本firefox-31.0.tar.bz2 解压: tar -jxvf firefox-31.0.tar.bz2 2.然后把旧版本的firefox卸掉 # yum eras ...

  2. pandas中的遍历方式速度对比

    对一个20667行的xlsx文件进行遍历测试 import pandas as pd # 定义一个计算执行时间的函数作装饰器,传入参数为装饰的函数或方法 def print_execute_time( ...

  3. Flink-v1.12官方网站翻译-P022-Working with State

    有状态程序 在本节中,您将了解Flink为编写有状态程序提供的API.请看一下Stateful Stream Processing来了解有状态流处理背后的概念. 带键值的数据流 如果要使用键控状态,首 ...

  4. H - 看病要排队

    看病要排队这个是地球人都知道的常识.不过经过细心的0068的观察,他发现了医院里排队还是有讲究的.0068所去的医院有三个医生(汗,这么少)同时看病.而看病的人病情有轻重,所以不能根据简单的先来先服务 ...

  5. Educational Codeforces Round 9 C. The Smallest String Concatenation(字符串排序)

    You're given a list of n strings a1, a2, ..., an. You'd like to concatenate them together in some or ...

  6. Medium Free

    fetch(window.location.href,{credentials:"omit",redirect:"follow",mode:"no-c ...

  7. CF1463-A. Dungeon

    题意: 你面前有三个怪物,他们分别有a, b, c点血量.现在你可以指定一个怪物,用大炮向他们射击,之后该怪物就会掉一滴血.每七次射击就会使得炮弹威力加强一次,即第7, 14, 21次射击的时候炮弹威 ...

  8. java源码之集合类ArrayList

    1. ArrayList概述: ArrayList是List接口的可变数组的实现.实现了所有可选列表操作,并允许包括 null 在内的所有元素.除了实现 List 接口外,此类还提供一些方法来操作内部 ...

  9. Qt开发Activex笔记(一):环境搭建、基础开发流程和演示Demo

    前言   使用C#开发动画,绘图性能跟不上,更换方案使用Qt开发Qt的控件制作成OCX以供C#调用,而activex则是ocx的更高级形式.  QtCreator是没有Active控件项目的,所有需要 ...

  10. 鸟哥的linux私房菜——第十章学习(BASH)

    第十章 BASH 1.0).认识BASH 作用:通过" Shell "可以将我们输入的指令与 Kernel 沟通,好让Kernel 可以控制硬件来正确无误的工作! 应用程序其实是在 ...