子字符串substring 问题 - KMP 字符串匹配算法备忘录
本文为自己对KMP的理解。
对KMP很好的介绍可以参考
http://www.cnblogs.com/yjiyjige/p/3263858.html
本文为对这篇文章的提炼和补充。
KMP算法基本思想:要查看字符串S是否包含P,定义 i = 0, j = 0,比较S[i]和P[j],相等就i,j各++,如果失配,照传统的比较,就是j要变成0,i也要回到最初开始的地方+1,重新比较;现在,i不变,j=next[j],然后重复上述:比较S[i]和P[j]。
next数组的定义方式如下(定义来自数据结构第二版4.4.6节,殷人昆主编):
假设字符串P长为m,由p0p1p2...pm-2pm-1构成,next(j)=
-1, 当j==0。
q+1, 当0<=q<j-1 且使得p0p1p2...pq = pj-q-1pj-q...pj-1的最大整数。
0,其他情况。
(next[0] = -1,在当第一位就失配时用到,其值为-1的含义是:i不再是不变,而是+1,同时j 赋值为0,看起来好像j相对于i 成了-1)
可以用递推思想求next[]:
我们用k表示当前next[j]的值,那么就意味着:p0p1p2...pk-1 = pj-k-1pj-k...pj-1,此时我们可以比较pk和pj,如果pk==pj,那么next[j+1]就是k+1,也就是n[j]+1了(之前说了用k表示n[j])。因为根据定义,如果p0p1p2...pk-1 == pj-k-1pj-k...pj-1而且pk==pj,那各自加上一个相等的,自然p0p1p2...pk-1pk == pj-k-1pj-k...pj-1pj依然成立了。
如果pk不等于pj,此时我们琢磨一下next(j)的定义:“使得p0p1p2...pq == pj-q-1pj-q...pj-1的最大整数”,其实就是找到相同的最长公共串,只不过前一个串必须以p0开头,后一个串必须以pj-1结尾。我们已经知道pk不等于pj,所以p0p1p2...pk == pj-q-1pj-q...pj是不可能了,这个问题其实就是:前面都一样,第j位失配。那么我们可以引用KMP本身的思想,将k赋值成next[k],然后重复上述内容:比较pk和pj,不相等就继续将k赋值成next[k],一直到pk == pj 或者 k变成了0或者-1。
因此next数组的代码如下:
public static int[] getNext(String ps) {
char[] p = ps.toCharArray();
int[] next = new int[p.length];
next[0] = -1;
int j = 0;
int k = -1;
while (j < p.length - 1) {
if (k == -1 || p[j] == p[k]) {
next[++j] = ++k;
} else {
k = next[k];
}
}
return next;
}
代码来自引用博文。
有了next[],下面就是匹配了:
public static int KMP(String ts, String ps) {
char[] t = ts.toCharArray();
char[] p = ps.toCharArray();
int i = 0; // 主串的位置
int j = 0; // 模式串的位置
int[] next = getNext(ps);
while (i < t.length && j < p.length) {
if (j == -1 || t[i] == p[j]) { // 当j为-1时,要移动的是i,当然j也要归0
i++;
j++;
} else {
// i不需要回溯了
// i = i - j + 1;
j = next[j]; // j回到指定位置
}
}
if (j == p.length) {
return i - j;
} else {
return -1;
}
}
子字符串substring 问题 - KMP 字符串匹配算法备忘录的更多相关文章
- 不可变字符串String与可变字符串StringBuilder、StringBuffer使用详解
String字符串 char类型只能表示一个字符,而String可以表示字符串,也就是一个字符序列.但String不是基本类型,而是一个定义好的类,是一个引用类型.在Java中,可以将字符串直接量赋给 ...
- BM和KMP字符串匹配算法学习
BM和KMP字符串匹配算法学习 分类: 研究与学习 字符串匹配BM(Boyer-Moore)算法学习心得 http://www.cnblogs.com/a180285/archive/2011/12/ ...
- 每周一算法之六——KMP字符串匹配算法
KMP是一种著名的字符串模式匹配算法,它的名称来自三个发明人的名字.这个算法的一个特点就是,在匹配时,主串的指针不用回溯,整个匹配过程中,只需要对主串扫描一遍就可以了.因此适合对大字符串进行匹配. 搜 ...
- 字符串的模式匹配算法——KMP模式匹配算法
朴素的模式匹配算法(C++) 朴素的模式匹配算法,暴力,容易理解 #include<iostream> using namespace std; int main() { string m ...
- KMP字符串模式匹配详解(转)
来自CSDN A_B_C_ABC 网友 KMP字符串模式匹配通俗点说就是一种在一个字符串中定位另一个串的高效算法.简单匹配算法的时间复杂度为O(m*n);KMP匹配算法.可以证明它的时间复杂度 ...
- 截取字符串 substring substr slice
截取字符串 substring 方法用于提取字符串中介于两个指定下标之间的字符 substring(start,end) 开始和结束的位置,从零开始的索引 参数 描述 start ...
- Java 从原字符串中截取一个新的字符串 subString()
Java 手册 substring public String substring(int beginIndex) 返回一个新的字符串,它是此字符串的一个子字符串.该子字符串从指定索引处的字符开始,直 ...
- KMP字符串模式匹配详解(zz)
刚看到位兄弟也贴了份KMP算法说明,但本人觉得说的不是很详细,当初我在看这个算法的时候也看的头晕昏昏的,我贴的这份也是网上找的.且听详细分解: KMP字符串模式匹配详解 来自CSDN A_B_ ...
- LayoutParams 命名的时候,最好用与子控件相关的字符串命名,
@Override public View initView() { RelativeLayout container = new RelativeLayout(UIUtils.getContext( ...
随机推荐
- 今日头条 2018 AI Camp 6 月 2 日在线笔试编程题第一道——最大连续区间和扩展
题目 给出一个长度为 n 的数组a1.a2.....ana1.a2.....an,请找出在所有连续区间 中,区间和最大同时这个区间 0 的个数小于等于 3 个,输出这个区间和. 输入描述: 第一行一个 ...
- [转载]Tensorflow中reduction_indices 的用法
Tensorflow中reduction_indices 的用法 默认时None 压缩成一维
- Js全反选DataGrid
// **************************************************************** // // function Trim(value) // -- ...
- 索引值迭代-enumerate
你想在迭代一个序列的同时跟踪正在被处理的元素索引?内置的enumerate() 函数可以很好的解决这个问题: list_c = ['a', 'b', 'c'] for i, c in enumerat ...
- BZOJ 4815 CQOI2017 小Q的表格 欧拉函数+分块
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=4815 题意概述:要认真概述的话这个题就出来了... 分析: 首先分析题目,认真研究一下修 ...
- Cortex-M3(NXP LPC 1788) 启动代码
startup_LPC177x_8x.s启动代码分析. 参考资料: Cortex-M3 (NXP LPC1788)之启动代码分析 ARM启动过程(Cortex-M3 NXP LPC1768为例) ;/ ...
- LVS+Keepalive+Nginx实现负载均衡
本文参考:http://blog.csdn.net/yinwenjie/article/details/47211551 简单粗暴写一下,做备忘,刚刚搭好没做优化呢,后期补充 一.机器准备 LVS-M ...
- 【转载】【翻译】Breaking things is easy///机器学习中安全与隐私问题(对抗性攻击)
原文:Breaking things is easy 译文:机器学习中安全与隐私问题(对抗性攻击) 我是通过Infaraway的那篇博文才发现cleverhans-blog的博客的,这是一个很有意思的 ...
- cURL和file_get_contents实现模拟post请求
以前面试时候,面试官问过我后端有没有跨域问题,但是不敢肯定,现在可以肯定的说没有. 不文用php的cURL和file_get_contents方法分别实现后端跨域.本文场景也是在tp5下实现的. 一, ...
- 【Linux】- 开启远程连接
1.首先看看自己的Ubuntu是不是已经安装或启用了ssh服务,执行 ps -e |grep ssh 我们看到只有ssh-agent 这个是ssh-client客户端服务,如果有sshd,证明你已经装 ...