子字符串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( ...
随机推荐
- hive创建外部表
Create [EXTERNAL] TABLE [IF NOT EXISTS] table_name [(col_name data_type [COMMENT col_comment], ...)] ...
- 使用Python进行AES加密和解密
摘录于:http://blog.csdn.net/nurke/article/details/77267081 另外参考:http://www.cnblogs.com/kaituorensheng/p ...
- LVS+Keepalive+Nginx实现负载均衡
本文参考:http://blog.csdn.net/yinwenjie/article/details/47211551 简单粗暴写一下,做备忘,刚刚搭好没做优化呢,后期补充 一.机器准备 LVS-M ...
- Comparison of Android versions(strcmp的应用)
Description As an Android developer, itˇs really not easy to figure out a newer version of two kerne ...
- 20145214实验四 Android开发基础
20145214实验四 Android开发基础 实验内容及步骤 安装 JDK 并配置 JDK 环境变量 找到之前path变量中的jdk文件所在位置并复制. 用复制的变量名新建一个 JAVA_HOME ...
- 《剑指offer》---两个栈实现队列
本文算法使用python3实现 1.题目描述: 用两个栈来实现一个队列,完成队列的Push和Pop操作. 队列中的元素为int类型. 时间限制:1s:空间限制:32768K 2.思路描述: ...
- iOS奔溃日志信息统计使用笔记
1.Bugly的集成很简单,直接一个pod就可以搞定 pod 'Bugly' 2.在官网上注册账号 3.初始化SDK 导入头文件 在工程的AppDelegate.m文件导入头文件 #import &l ...
- caffe2安装教程
相比于网上的安装教程不如直接看官方安装教程:https://caffe2.ai/docs/getting-started.html?platform=windows&configuration ...
- 【Linux】CentOS安装redis
CENTOS7下安装REDIS 安装完成之后使用:redis-cli命令连接,如图: 提示:/var/run/redis_6379.pid exists, process is already run ...
- vue-cli3配置postcss-cssnext
1. // npm install autoprefixer --save-dev 此步不需要了,因为postcss-cssnext自带这个依赖 npm install postcss-cssnext ...