简洁

我相信很多人都听说过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. 翻译:《实用的Python编程》01_Introduction_00_Overview

    目录 | 下一节 (2 处理数据) 1. Python 简介 本章是第一章,将会从头开始介绍 Python 基础知识,让你从零开始,学会怎么编写.运行.调试一个简单的程序.最后,你可以运用这些 Pyt ...

  2. Educational Codeforces Round 84 E. Count The Blocks

    传送门: 1327- E. Count The Blocks  题意:给你一个整数n,求10^n内(每个数有前导零)长度为1到n的块分别有多少个.块的含义是连续相同数字的长度. 题解:从n=1开始枚举 ...

  3. poj 1696 极角排序(解题报告)

    #include<iostream> #include<cmath> #include<algorithm> using namespace std; double ...

  4. HDU 1173 思路题

    题目大意 有n个地点(坐标为实数)需要挖矿,让选择一个地点,使得在这个地方建造基地,到n个地点的距离和最短,输出基地的坐标. 题解+代码: 1 /* 2 把这个二维分开看(即把所有点投影到x轴上,再把 ...

  5. div 水平居中 内容居左

    <div style="margin:0 auto;width:500px;text-align:left"> </div> https://zhidao. ...

  6. centos 7下设置.net core项目开机自启动

    1.在etc/systemd/system下创建xxx.service文件 例如:vi /etc/systemd/system/ubif.service2.编辑 ubif.service内容如下: [ ...

  7. LSTM - 长短期记忆网络

    循环神经网络(RNN) 人们不是每一秒都从头开始思考,就像你阅读本文时,不会从头去重新学习一个文字,人类的思维是有持续性的.传统的卷积神经网络没有记忆,不能解决这一个问题,循环神经网络(Recurre ...

  8. constexpr 的来龙去脉

    constexpr 是什么? 关键字 constexpr (constant expression) 是在 C++11 中引入的,并且在 C++14 中进行了优化. constexpr 和 const ...

  9. CF1474-C. Array Destruction

    CF1474-C. Array Destruction 题意: 题目给出一个长度为\(2n\)的正整数序列,现在问你是否存在一个\(x\)使得可以不断的进行如下操作,直到这个序列变为空: 从序列中找到 ...

  10. Kubernets二进制安装(8)之部署四层反向代理

    四层反向代理集群规划 主机名 角色 IP地址 mfyxw10.mfyxw.com 4层负载均衡(主) 192.168.80.10 mfyxw20.mfyxw.com 4层负载均衡(从) 192.168 ...