next数组两种求法
一、说明
(1)看到网上同一个字符串求 next 数组的值有两种,一种是 -1 开头,一种是 0 开头,虽然有差别,但是以 0 开头的next数组的每一项都比以 -1 开头的next数组的对应项大1,所以,具体是以 0 开头还是以 -1 开头看需要吧,算法都是一样的.KMP 的原始论文 (K,M,P 三个家伙写的原文)中是以 0 开头的,所以下面的写法是以 0 开头的.
(2)关于 next 数组的求法,网上能找到很多流行简洁的写法,也有很多文章对简洁代码讲解得非常细致,然而本文并不是对流行算法的剖析,而只是记录一下自己比较喜欢的计算方法,并用代码实现一下.
二、求法的文字描述
(1)第一种求法:根据前一个字符的next值求字符串记作 p;next 数组记作 next;
约定:
- 下标从 1 开始算,注意,不是从 0 开始算
- 字符串长度 >2
1)第一个字母的 next 值置 0 (next[1] = 0),第二个字母的 next 值置 1(next[2] = 1) ;
2)从第 3 个开始,计算第 i 个位置的 next 值时,检查
p[i-1]== p[next[i-1]] ?(即这两个值是否相等)
解释:第 i 个位置的前一个位置的值(即 p[i-1],记作 m)与以 m 的 next 值(即 next[i-1])为下标的值(即 p[next[i-1]],记作 n)是否相等,(看的懵懵的也没关系,后面会有例子)
- 若相等,则 next[i] = next[i-1] + 1
若不等,则继续往回找,检查
p[i-1]== p[next[next[i-1]]] ?
- 若相等,则 next[i] = next[next[i-1]] + 1
- 若不等,则继续往回找,直到找到下标为 1 还不等(即字符串第一个元素),直接赋值 next[i] = 1
(2)第二种求法:根据最大公共元素长度求
首先附上讲解的博文地址,里面有详细讲解
http://blog.csdn.net/v_july_v/article/details/7041827
1)算出每一个字母前缀后缀的最大公共元素长度
2)最大公共元素长度整体向后移动一个长度,最前面的元素值填 -1,即为 next 数组的第一版本
3)(如果你需要的 next 数组第一个值为 -1,这步就可以省略了)next 数组的每一个值分别+1,即求得 next 数组。
三、实例
字符串 P =“ababaaababaa”
求解:
(1)对应上面第一种求法
1)初始化
P | a | b | a | b | a | a | a | b | a | b | a | a |
---|---|---|---|---|---|---|---|---|---|---|---|---|
下标 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
next | 0 | 1 |
2)求下标为 3 的字符的 next 值
P[3-1] = P[2] = ‘b’;
next[3-1] = next[2] = 1 ;
P[next[3-1]] = P[1] = ‘a’;
P[3-1] != P[next[3-1]] ,但是此时已经回溯到了第一个元素,
∴ 直接P[3] = 1 ;
P | a | b | a | b | a | a | a | b | a | b | a | a |
---|---|---|---|---|---|---|---|---|---|---|---|---|
下标 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
next | 0 | 1 | 1 |
3)求下标为 4 的字符的 next 值
P[4-1] = P[3] = ‘a’;
next[4-1] = next[3] = 1 ;
P[next[4-1]] = P[1] = ‘a’;
P[4-1] == P[next[4-1]] ;
∴ next[4] = next[4-1] + 1 = 2 ;
P | a | b | a | b | a | a | a | b | a | b | a | a |
---|---|---|---|---|---|---|---|---|---|---|---|---|
下标 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
next | 0 | 1 | 1 | 2 |
4)求下标为 5 的字符的 next 值
P[5-1] = P[4] = ‘b’;
next[5-1] = next[4] = 2 ;
P[next[5-1]] = P[2] = ‘b’;
P[5-1] == P[next[5-1]] ;
∴ next[5] = next[5-1] + 1 = 3 ;
P | a | b | a | b | a | a | a | b | a | b | a | a |
---|---|---|---|---|---|---|---|---|---|---|---|---|
下标 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
next | 0 | 1 | 1 | 2 | 3 |
5)求下标为 6 的字符的 next 值
推导过程同上 => next[6] = next[6-1] + 1 = 4 ;
P | a | b | a | b | a | a | a | b | a | b | a | a |
---|---|---|---|---|---|---|---|---|---|---|---|---|
下标 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
next | 0 | 1 | 1 | 2 | 3 | 4 |
6)求下标为 7 的字符的 next 值
P[7-1] = P[6] = ‘a’;
next[7-1] = next[6] = 4 ;
P[next[7-1]] = P[4] = ‘b’;
P[7-1] != P[next[7-1]] && 此时还未回到第一个,继续
next[next[7-1]] = next[4] = 2 ;
P[next[next[7-1]]] = P[2] = ‘b’;番外(1)
P[7-1] != P[next[next[7-1]]] && 但是此时还未回到第一个,继续
next[next[next[7-1]]] = next[2] = 1 ;
P[next[next[next[7-1]]]] = P[1] = ‘a’ ;
P[7-1] == P[next[next[next[7-1]]]] ;
∴ next[7-1] = next[next[next[7-1]]] + 1 = next[2] + 1 = 2 ;
P | a | b | a | b | a | a | a | b | a | b | a | a |
---|---|---|---|---|---|---|---|---|---|---|---|---|
下标 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
next | 0 | 1 | 1 | 2 | 3 | 4 | 2 |
7)求下标为 8 的字符的 next 值
P[8-1] = P[7] = ‘a’;
next[8-1] = next[7] = 2 ;
P[next[8-1]] = P[2] = ‘b’;
P[8-1] != P[next[8-1]] ,但是还没回到第一个元素,继续
next[next[8-1]] = next[2] = 1 ;
P[next[next[8-1]]] = P[1] = ‘a’;
P[8-1] == P[next[next[8-1]]];
∴ next[8] = next[next[8-1]] + 1 = 2
P | a | b | a | b | a | a | a | b | a | b | a | a |
---|---|---|---|---|---|---|---|---|---|---|---|---|
下标 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
next | 0 | 1 | 1 | 2 | 3 | 4 | 2 | 2 |
8)求下标为 9 的字符的 next 值
推导过程同4) => next[9] = next[9-1] + 1 = 3 ;
P | a | b | a | b | a | a | a | b | a | b | a | a |
---|---|---|---|---|---|---|---|---|---|---|---|---|
下标 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
next | 0 | 1 | 1 | 2 | 3 | 4 | 2 | 2 | 3 |
9)求下标为 10 的字符的 next 值
推导过程同4) => next[10] = next[10-1] + 1 = 4 ;
P | a | b | a | b | a | a | a | b | a | b | a | a |
---|---|---|---|---|---|---|---|---|---|---|---|---|
下标 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
next | 0 | 1 | 1 | 2 | 3 | 4 | 2 | 2 | 3 | 4 |
10)求下标为 11 的字符的 next 值
推导过程同4) => next[11] = next[11-1] + 1 = 5 ;
P | a | b | a | b | a | a | a | b | a | b | a | a |
---|---|---|---|---|---|---|---|---|---|---|---|---|
下标 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
next | 0 | 1 | 1 | 2 | 3 | 4 | 2 | 2 | 3 | 4 | 5 |
11)求下标为 12 的字符的 next 值
推导过程同4) => next[12] = next[12-1] + 1 = 6 ;
P | a | b | a | b | a | a | a | b | a | b | a | a |
---|---|---|---|---|---|---|---|---|---|---|---|---|
下标 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
next | 0 | 1 | 1 | 2 | 3 | 4 | 2 | 2 | 3 | 4 | 5 | 6 |
(2)对应上面第二种求法
1)算出每一个字母前缀后缀的最大公共子串长度(下一步会把最后一位移走,所以最后一位可以不算)番外(2)
P | a | b | a | b | a | a | a | b | a | b | a | a |
---|---|---|---|---|---|---|---|---|---|---|---|---|
前后缀最大公共子串长度 | 0 | 0 | 1 | 2 | 3 | 1 | 1 | 2 | 3 | 4 | 5 |
2)最大公共子串长度整体向后移动一个长度,最前面的元素值填 -1,即为 next 数组的第一版本
P | a | b | a | b | a | a | a | b | a | b | a | a |
---|---|---|---|---|---|---|---|---|---|---|---|---|
next 数组第一版 | -1 | 0 | 0 | 1 | 2 | 3 | 1 | 1 | 2 | 3 | 4 | 5 |
3)(如果你需要的 next 数组第一个值为 -1,这步就可以省略了)next 数组的每一个值分别+1,即求得 next 数组。
P | a | b | a | b | a | a | a | b | a | b | a | a |
---|---|---|---|---|---|---|---|---|---|---|---|---|
next 数组第二版 | 0 | 1 | 1 | 2 | 3 | 4 | 2 | 2 | 3 | 4 | 5 | 6 |
next数组两种求法相关推荐
- 树状数组两种基本的模式
树状数数组基本的两种模式: 第一,对初始数组a[i]中的某一元素修改,查询某个区间内的所有的和,(时间复杂度都为logn).(插点问线) 第二,随时修改数组中a[i]中的某个区间的值(O(1)的时间复 ...
- java二维数组两种初始化方法
写这篇博客的原因是因为从大一学习c语言开始 就对二维数组的声明 和初始化 一直没有搞懂....直到学到了Java依旧搞得不是很清楚. 先看一道Java的基础题 这道题 错误的选项 是 B. 二维数组的 ...
- 斐波那契数列通项的两种求法
目录: 一.何为斐波那契数列? 二.解法一 三.解法二 四.合二为一 五.实际实现 一.何为斐波那契数列? 1,1,2,3,5,8,13,⋯1,1,2,3,5,8,13,\cdots 1,1,2,3, ...
- 斐波那契数的两种求法(迭代,递归)
**斐波那契数,通常用 F(n) 表示,形成的序列称为斐波那契数列.该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和.也就是: F(0) = 0, F(1) = 1 F(N) = F( ...
- Ybtoj 最优密码 单调队列(浅谈)树状数组 两种解法
作者:hsez_yyh 链接:https://blog.csdn.net/yyh_getAC/article/details/123956399 来源:湖北省黄石二中竞赛组 著作权归作者所有.商业 ...
- OC动态创建的问题变量数组.有数组,在阵列13要素,第一个数据包阵列,每3元素为一组,分成若干组,这些数据包的统一管理。最后,一个数组.(要动态地创建一个数组).两种方法...
<span style="font-size:24px;">//第一种方法 // NSMutableArray *arr = [NSMutableArra ...
- 合并两个有序数组两种方式
/*** 需求:两个有序数组nums和nums2将nums2合并到nums1中,使得nums1成为一个有序数组***/ public class Mergesz {public static void ...
- 软考--后缀式(逆波兰式)的两种求法
首先理解概念: 后缀式:又叫逆波兰式 -用"左右根"表示 如图1后缀式:左右根-a+* 如图2后缀式:左右根-a-d*+ Tips:相关的知识 前序遍历:根左右 中序遍历:左根右 ...
- 莫比乌斯函数的两种求法(基于欧拉筛、埃氏筛)
给出莫比乌斯函数的定义: 这里的n即u(i)中的i,即i=1时,u(1)=1:i大于1且i中某个质因子的幂超过1,则u(i)=0:否则,u(i)取决于其质因子个数的奇偶性. 这里给出两个莫比乌斯函数的 ...
最新文章
- 推荐系统超级公开课报名!
- 二阶矩阵转置怎么求_矩阵求导术(下)
- 部署基于tomcat 8 的solrCloud 5.5集群
- Linux下c开发 之 线程通信(转)
- ASP注入漏洞基础教程(二)
- JavaScript开发中几个常用知识点总结
- 10款经典的web前端特效的预览及源码
- ASP.Net请求处理模式
- 2017.8.11 亚瑟王 失败总结
- 一篇文章带你熟悉 TCP/IP 协议-(三)
- Turbo码,接近完美的编码
- wifi 频段表_wifi频段如何设置为5ghz
- oracle 返回 xml解析,Oracle xmltable解析返回LPX-00209(Oracle xmltable parsing return LPX-00209)...
- 【报错记录】解决Shell脚本报ambiguous redirect
- python中result的用法_python中result的用法
- 运营数据分析,怎么做才有深度
- 关于写作,村上春树提供的几个方法
- Ubuntu Xfce桌面系统设置项
- 【C语言函数递归】递归计算最大公约数
- CANOE入门:CAPL语言实现诊断发送和接收
热门文章
- python nodemcu_NodeMCU-32S MicroPython固件的使用
- 牛逼!白帽子们把色情版微信的底裤扒了个底朝天.....
- Microsoft Teams Voice语音落地系列-4 实战:Teams语音路由规划与配置
- 详谈机器视觉大师脚本编程
- 电脑重装系统后黑屏提示Reboot and select proper Boot device怎么办
- flask 产生KeyError:‘migrate‘报错
- 英雄联盟手游推荐耳机,南卡Lite Pro 2展现优秀游戏声效处理硬实力
- AutoCAD2021使用方法与小技巧总结1
- 可供Office多种版本使用的无PIA或_VtblGap的加载外接程序
- 工业组态DIAView自定义图库80个