题目: 题目的本质是给定两个字符串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. 浅析HTML的元素类型及其转换

    大家都知道html是由标签元素组成的,在了解元素的类型转换之前,让我们先来了解一下html的元素类型. 一.html元素类型分为两种:块级元素和内联元素,内联元素又被称为行内元素.  常见的块级元素有 ...

  2. [20190620]日常学习记录(三)-初识promise及vuex

    在学习promise之前重温了Ajax的原生js实现, 在原生js中发送一个http请求首先new XMLHttpRequest() 然后定义状态变更事件 浏览器监听请求的状态,触发不同状态下相应的代 ...

  3. 动态加载sd卡或者手机内置存储卡的so库

    package com.wsc.utils; import android.content.Context; import com.wsc.common.Entrance; import com.ws ...

  4. object flash

    <!-- html插入flash --> <object type="application/x-shockwave-flash" width="100 ...

  5. Garmin APP开发之布局

    上一章节介绍了garmin app开发的入门,包括garmin-sdk,开发工具的安装部署,文章结尾我们新建了我们的第一个app程序Garmin开发-入门: http://tieba.baidu.co ...

  6. Nginx服务器301跳转到带www的域名的方法

    为什么要这么做? 我们的域名在做解析时经常会解析2个域名,即带www的和不带www的.这样做的目的是,当用户使用不带www的域名时,也可以正常访问你的网站.但是这样做的后果是,你站点主域名的PR值分散 ...

  7. WinForm form属性

    一.布局 Autostroll   控件内容大于可见区域是否自动显示滚动条 Maximumsize 窗体可调到最大尺寸 minimumsize  窗体可调到最小尺寸 size  窗体看到的尺寸 Sta ...

  8. Java TCP通信

    1.Socket原理 1)Socket简介 socket通常称作“套接字”,用于描述IP地址和端口号,是一个通信链的句柄.在Internet上的主机一般运行了多个服务软件,同时提供几种服务.每种服务都 ...

  9. UI的组织形式

    UI的组织形式是树状结构: 根据层次的不同分为叶子节点和干节点. 叶子节点负责简单的信息展示. 复杂的主干复杂叶子节点的组织和整体展示. http://www.cnblogs.com/feng9exe ...

  10. Python-OpenCV——Image inverting

    通常我们将读入的彩色图转化成灰度图,需要将灰度图反转得到掩码,如何正确快速的得到某个图像的反转图呢? 首先看一种看似很正确的写法,对其中每个像素进行如下处理: img[x,y] = abs(img[x ...