【C++】算法集锦(10)通俗讲kmp算法

《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门,即可获取!

显然,主串的字符A仍然是坏字符,这时候的匹配前缀缩短成了GTG:

在这里插入图片描述

按照第一轮的思路,我们来重新确定最长可匹配后缀子串和最长可匹配前缀子串:

在这里插入图片描述

第三轮,我们再次把模式串向后移动两位,让两个“G”对齐,继续从刚才主串的坏字符A开始进行比较:

在这里插入图片描述

···

···

next数组


什么是next数组?next数组用来干什么?

next数组是决定kmp算法快速移动的核心。

好,我们来看一下next数组是如何生成的。

在这里插入图片描述

有了next数组,我们就可以通过已匹配前缀的下一个位置(坏字符位置),快速寻找到最长可匹配前缀的下一个位置,然后把这两个位置对齐。

比如下面的场景,我们通过坏字符下标5,可以找到next[5]=3,即最长可匹配前缀的下一个位置:

在这里插入图片描述

生成next数组

我先放一段代码再这里:

(如果用上面那张图里的方法,那生成next数组的过程是非常低效的)

void getnext(string p, vector &next) //next在传入时应该进行扩容

{

int len = p.size();

int k = -1;

int j = 0;

next[0]=-1;

while (j < len - 1)

{

if (k == -1 || p[k] == p[j])

{

k++;

j++;

next[j] = k;

}

else {

k = next[k];

}

}

}

能看懂吗?

首先为了后面运算方便,将next[0]设置为-1,不得不说这个设置为-1非常之巧妙。

先不说巧妙在哪里,自己去写的话就知道了。

也先不说那个令人绞尽脑汁的 k = next[k],我们先把基础弄明白。

先看next[j] = k,这一句。

来我们来个简单的栗子:“ababcba”.

要对这个子串求它的next数组,是这样的。

1、a

2、ab

3、aba

4、abab

5、ababc

6、ababcb

7、ababcba

将这个字符串这样分一下,然后对号入座,看到我标的号了没,对应的是next数组中的号,最后那个可以去掉,因为如果整个串都对上了还回溯什么。

首先我们来看一下“前后子集“的概念,我自己起的名字,还不错吧。

拿4来说把,它的前子集有:

{

a,

ab,

aba

}

后子集有:

{

b,

ab,

bab

}

规律不难找啊。

那,他俩子集里面有一个同类,“ab”,将ab的长度填入next[4]里面。

接下来难度要稍微升级了。

这个next数组,也有半自动推导,碧如说4(abab),它的对称度为2,那么如果在4的基础上,加上一个字符,这个字符刚好跟对称度+1的位置的字符对上,即如果加上的字符是a,那么便可以知道 5 的对称度为3,因为前面两个已经有 4 做了铺垫。

这就是:

if (k == -1 || p[k] == p[j])

{

k++;

j++;

next[j] = k;

}

这一个部分的原理。next[++j] = ++k;,是这样来的。

可惜,上面那个例子加上去的是 ‘c’。那就·是另外一部分代码的事情了:

else {

k = next[k];

}


k = next[k]

要理解这行代码,我们用另外一个字符串会比较直观一些。

“a b a b a b c b”

一步一步来啊,

1、a

next[0] = -1;

k = -1,j=0;

k = 0,j=1;

next[1] = 0; //进入了if

//这两个简直是铁索连环,就写一起吧

2、a,b

j = 1,k = 0; //进入else

k = -1; //所以,嗯

//再一圈循环

k = 0,j = 2; //进入if

next[2] = 0;

3、a,b,a

//进入if

k = 1,j = 3;

next[3] = 1;

4、a,b,a,b

k = 2,j = 4;

next[4] = 2;

//看啊,用到上面讲的了。

//其实还有一条铁律忘记说了,如果有耐心看到这里那我就说。后一位的对称度,顶多比前一位,多1!!!

5、a,b,a,b,a

k = 3,j = 5;

next[5] = 3;

6、a,b,a,b,a,b

k = 4,j = 6;

next[6] = 4;

//越来越接近目标了啊,马上就要断了香火了

7、a,b,a,b,a,b,c

// ‘c’!=‘a’!

// 进入else

k = next[4] = 2

// 循环,进入else

k = next[2] = 0

// 再循环,

k = -1

// 再循环,进入if

k = 0,j = 7

next[7] = 0


这时候你会发现,它新加上来的那个字符,和对称度后面一位字符不匹配,‘c’!=‘a’!,那里我打了星标。

KMP匹配、


这个匹配就比较好理解了,该注释的地方我注释了

int kmp(string s, string p)

{

int i = 0;

int j = 0;

int sLen = s.size();

int pLen = p.size();

if (pLen == 0 )

return 0;

vector vec(pLen, 0);

getnext(p,vec); //获取next数组

while (i < sLen && j < pLen)

{

if (j == -1 || s[i] == p[j])

{

i++;

j++;

}

else

{

//②如果j != -1,且当前字符匹配失败(即S[i] != P[j]),则令 i 不变,j = next[j]

//next[j]即为j所对应的next值

j = vec[j];

}

}

if (j >= pLen)

return(i - j);

return -1;

}

KMP算法整体实现(LeetCode测试通过)


#include

#include

#include

using namespace std;

void getnext(string p, vector &next) //next在传入时应该进行扩容

{

int len = p.size();

int k = -1;

Java核心架构进阶知识点

面试成功其实都是必然发生的事情,因为在此之前我做足了充分的准备工作,不单单是纯粹的刷题,更多的还会去刷一些Java核心架构进阶知识点,比如:JVM、高并发、多线程、缓存、Spring相关、分布式、微服务、RPC、网络、设计模式、MQ、Redis、MySQL、设计模式、负载均衡、算法、数据结构、kafka、ZK、集群等。而这些也全被整理浓缩到了一份pdf——《Java核心架构进阶知识点整理》,全部都是精华中的精华,本着共赢的心态,好东西自然也是要分享的

image

image

image

内容颇多,篇幅却有限,这就不在过多的介绍了,大家可根据以上截图自行脑补
《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门,即可获取!
n = p.size();

int k = -1;

Java核心架构进阶知识点

面试成功其实都是必然发生的事情,因为在此之前我做足了充分的准备工作,不单单是纯粹的刷题,更多的还会去刷一些Java核心架构进阶知识点,比如:JVM、高并发、多线程、缓存、Spring相关、分布式、微服务、RPC、网络、设计模式、MQ、Redis、MySQL、设计模式、负载均衡、算法、数据结构、kafka、ZK、集群等。而这些也全被整理浓缩到了一份pdf——《Java核心架构进阶知识点整理》,全部都是精华中的精华,本着共赢的心态,好东西自然也是要分享的

[外链图片转存中…(img-ePVNQMkL-1714689632110)]

[外链图片转存中…(img-1mmmGosQ-1714689632110)]

[外链图片转存中…(img-dy4rHniC-1714689632110)]

内容颇多,篇幅却有限,这就不在过多的介绍了,大家可根据以上截图自行脑补
《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门,即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值