题目: 题目的本质是给定两个字符串str1,str2,求str1中的str2串开始的地方,即字符串的匹配,KMP算法

思路:时间复杂度为O(m + n),空间复杂度为O(n),原串的长度为m,子串的长度为n

KMP算法的本质是根据子串的next值求解的,所以首先讲解next值得求法:

字串的Next值的求解方法:

next[i]的含义是:以i-1位置结尾的字符串与以0位置开始的字符串的最长匹配

1. 创建一个与子串大小相同长度的int型数组next

2. next值中的next[0] = -1, next[1] = 0,这是一定的。下来求2 - 串尾的每个位置的next值。假设此时求next[i]的值:由于next[i]的含义是以i-1位置结尾的字符串与以0位置开始的字符串的最长匹配,而此时我们已经求除了i-1位置的next值,next[i - 1]含义是以i-2位置结尾的字符串与以0位置开始的字符串的最长匹配。我们使用cn表示与以i-2结尾的字符串的匹配长度所以next[i - 1] = cn

a)如果i-1位置的值等于cn+ 1位置的值,则next[i] = next[i -1] + 1;由于next[i - 1]匹配的是0~cn和某个地方到i - 2, 因此如果cn + 1位置的值和i -1位置的值相等,则next[i] = cn + 1;

b)  否则 ,判断next[i - 1]的值是不是大于0,大于0表示前面有某个位置还有匹配的可能性,即next值回退过程,cn =  next[cn]

c) 否则,表示cn = 0,即回退到第一个位置了,则next[i] = 0;

如上图所示: 我们来回顾一下next值的定义:next[i] = 以i-1位置结尾的字符串与以0位置开始的字符串的最长匹配

假设此时需要求i位置的next值,而我们已经知道next[i-1]的值,是从[0,z]和[i-2 - z, i-2]的匹配,长度为z,即next[i -1] = z;此时:

1)如果z的下一个位置w的值和i-1的值相等,则就有了[0, z + 1] 和[i-2-z, i - 1]的匹配,该匹配就是next[i] 的值;

2)如果w = z + 1位置的值不等于i-1位置的值,则表示匹配的长度会比z短,而next[i - 1] = z, 此时我们要求的是next[z]的值:假设next[z] 的匹配为[0, x]和[z - 1- x, z-1], 同理,若y = x + 1位置的值与i - 1位置的值相等,则next[i] = next[z] + 1,若y位置的值与i-1位置的值不相等,则继续向前回退,直到next[i] = 0;

证明过程:

此时next[i] = [0, x]长度,next[i]的长度为什么不可能长于x?

[0, z] = [i -2 - z, i - 2], [0, x] = [z - 1 - x, z - 1], 由于[0, x] ∈[0, z], 因此[0, x]∈[i -2 - z, i - 2],再回想一下next[i]的定义,因此只要x+ 1位置的值与i-1位置的值相等,则可以计算出next[i]的值;

我们此时假设next[i]的长度为[0, q]的匹配,q > z + 1,则 i-1和q位置,i-2和q- 1位置的值.....都是相等的,那么next[i -1] 的值就为[0, q]的匹配,q > z , 显然与”最长匹配原则“不一致;

我们再假设next[i] 的长度为[0, x]的匹配,z > q > x + 1, 则 i-1和q位置,i-2和q- 1位置的值.....都是相等的,那么next[i - 1]的值就是[0, q]的匹配,而q < z,因此与”最长匹配不相等“

KMP的匹配过程:

1. 从头开始匹配,如果相等,则子串和原串都继续向后

2.如果在子串的某个位置i不相等,则表示i-1前面的都已经匹配上了,所以子串和原串都不要回退,由于next[i] 表示的是i-1位置结尾的字符串和以0位置开始的字符串的最长匹配,所以,如果next[i] = -1,则表示原串与子串的第一个字符否没有匹配,则原串位置向后移动,否则 只需要从子串的next[i]位置与原串继续比较即可。

假设此时比较到子串的i位置,对应主串的s+ 1位置不匹配,表明[t,s]和[0, i -1]是匹配的,则根据next[i]的含义,可以得出子串中[0, x1]与主串[s1,s]是匹配的,因此下一次只需要从字串的x1+1位置和s+ 1位置进行比较即可;

代码如下:

 public class Solution {
// KMP算法
public int strStr(String haystack, String needle) {
if(haystack == null || needle == null || haystack.length() < needle.length())
return -1;
if(haystack.length() == 0 || needle.length() == 0)
return 0;
int[] next = calNext(needle);
int hlen = haystack.length();
int nlen = needle.length();
int hindex = 0;
int nindex = 0;
while(hindex < hlen && nindex < nlen)
{
if(haystack.charAt(hindex) == needle.charAt(nindex)) // 从头开始,若匹配就一直继续比较
{
hindex ++;
nindex ++;
}
else if(next[nindex] == -1) // 表示与子串的第一个字符就没有匹配上,则主串自己向后移动
{
hindex ++;
}
else // 直到nindex - 1都匹配上了,所以子串不需要从头继续,只需要从next[nindex]位继续匹配即可
{
nindex = next[nindex];
}
}
return nindex == nlen ? hindex - nindex : -1; // 如果匹配到子串的结尾,则返回此时主串与子串的位置差,即为开始匹配的地方
}
public int[] calNext(String needle)
{
if(needle.length() == 1)
return new int[]{-1};
int[] next = new int[needle.length()];
next[0] = -1;
next[1] = 0;
int cn = 0;
int pos = 2;
while(pos < next.length)
{
if(needle.charAt(pos - 1) == needle.charAt(cn))
next[pos ++] = ++cn;
else if(cn > 0) // 回退
cn = next[cn];
else
next[pos ++] = 0;
}
return next;
}
}

Leetcode28--->字符串的匹配(KMP)的更多相关文章

  1. 数据结构学习之字符串匹配算法(BF||KMP)

    数据结构学习之字符串匹配算法(BF||KMP) 0x1 实验目的 ​ 通过实验深入了解字符串常用的匹配算法(BF暴力匹配.KMP.优化KMP算法)思想. 0x2 实验要求 ​ 编写出BF暴力匹配.KM ...

  2. 字符串匹配算法之 kmp算法 (python版)

    字符串匹配算法之 kmp算法 (python版) 1.什么是KMP算法 KMP是三位大牛:D.E.Knuth.J.H.MorriT和V.R.Pratt同时发现的.其中第一位就是<计算机程序设计艺 ...

  3. 全局匹配KMP算法

    KMP算法是通过分析模式字符串,预先计算每个位置发生不匹配的时候,所需GOTO的下一个比较位置,整理出来一个next数组,然后在上面的算法中使用. 本全局匹配KMP算法针对串的堆式存储数据结构 # d ...

  4. Robin-Karp algorithm 字符串的匹配

    有关字符串的匹配问题,有很好的算法,即KMP算法,但是还有一种其实经常使用到的算法是Rabin-Karp算法,它是使用hash的原理来进行字符串匹配的.具体的做法如下. Rabin-Karp算法是由R ...

  5. [bzoj1892][bzoj2384][bzoj1461][Ceoi2011]Match/字符串的匹配_KMP_树状数组

    2384: [Ceoi2011]Match 1892: Match 1461: 字符串的匹配 题目大意: 数据范围: 题解: 很巧妙的一道题呀. 需要对$KMP$算法有很深的理解才行. 首先我们需要发 ...

  6. Oracle添加数据报文字与格式字符串不匹配错误

    今天在学习Oracle时碰到一个错:文字与格式字符串不匹配. 我在Oracle数据库中创建了一张表: --创建员工表employee create table employee ( empon ) n ...

  7. oracle文字与格式字符串不匹配的解决

    oracle文字与格式字符串不匹配的解决 oracle的日期时间类型 在往oracle的date类型插入数据的时候,记得要用to_date()方法. 如insert into CUSLOGS(STAR ...

  8. 带’*’号字符串的匹配

    目标: 判断源字符串中是否含有指定子串,子串可能会有*号通配符. 初步测试没问题.记录下来.后面要是有问题再来纠正. #include <string> using namespace s ...

  9. Java字符串的匹配问题,String类的matches方法与Matcher类的matches方法的使用比较,Matcher类的matches()、find()和lookingAt()方法的使用比较

    参考网上相关blog,对Java字符串的匹配问题进行了简单的比较和总结,主要对String类的matches方法与Matcher类的matches方法进行了比较. 对Matcher类的matches( ...

  10. java.sql.SQLException:ORA-01861:文字和格式字符串不匹配

    1.错误描述 java.sql.SQLException:ORA-01861:文字和格式字符串不匹配 2.错误原因 字段名为statis_date在数据库中存储的数据类型是Date,而在Java中拼接 ...

随机推荐

  1. To the world you may be one person, but to one person you may be the world.

    To the world you may be one person, but to one person you may be the world.对于世界而言,你是一个人:但对于某人而言,你是他的 ...

  2. 零基础逆向工程15_C语言09_位运算

    1.汇编中的移位指令 算数移位指令 指令格式:SAL/SAR Reg/Mem, CL/Imm SAL(Shift Arithmetic Left):算数左移 SAR(Shift Arithmetic ...

  3. AD 域复制FRS 迁移到DFSR

    假设您尝试将在先前版本的Windows Server上运行的某个Active Directory域控制器(DC)升级到Windows Server 2019. 您可能会看到以下错误: “副本验证失败. ...

  4. Java阻塞队列(BlockingQueue)实现 生产者/消费者 示例

    Java阻塞队列(BlockingQueue)实现 生产者/消费者 示例 本文由 TonySpark 翻译自 Javarevisited.转载请参见文章末尾的要求. Java.util.concurr ...

  5. GWTDesigner_v5.1.0破解码

    GWTDesigner_v5.1.0_win32_x86.exe破解码,双击运行keygeno.jar,然后输入用户名.网卡MAC,然后单击Generate,将生成的文件放在C:\Documents ...

  6. falling object思路总结

    1.用检测的方法把falling object标记为一个类别,然后检测出类别.这种方式不可行的原因:因为falling object可能是任何东西,所以可能是一个路锥,也可能是一个玻璃瓶,还可能是掉下 ...

  7. 解决TS报错Property 'style' does not exist on type 'Element'

    在使用queryselector获取一个dom元素,编译时却报错说property 'style' does not exist on type 'element'. 原因:这是typescript的 ...

  8. Mybatis中关于OGNL表达式冲突

    注意设计表字段不能用bor  xor  and  band  eq  neq  lt  gt  lte  gte  shl  shr  ushr

  9. shell脚本,awk在需要的行上打打印空行。

    注解: 判断每行中是否包含字母a,包含了,就将$1的值赋值给变量a,然后判断变量a是否存在,存在打印一个空行,在将变量的值使用空变量b赋值,最后在打印输出. 结果就是在包含有字符a的行上打印一个空行.

  10. Unity3d 判断物体是否在可见范围内

    unity中自带两个回调函数: void OnBecameVisible()//当物体可见时,回调一次. void OnBecameInvisible()//当物体不可见时,回调一次. 在untiy编 ...