KMP小扩展,找出子串在主串中出现的所有位置
KMP算法能够高效地匹配字符串,找出子串(T串)在主串(S串)中出现的首个位置的原算法网上已经有很多优秀的博文进行详细讲解,这里就不多赘述。
这篇博文主要是对KMP原算法稍作改动,使其能够在主串中把所有匹配的主串找出来。
找出首个匹配的算法好弄,next数组求出来后直接用来匹配,直到出现完全匹配的情况的时候就停止搜索把答案扔出来就行,但是想把所有T串找出来的话就得完全把S串搜完, 就算已经在S串中找到一个T串后也是不能马上停止搜索的。
难点就在已经完全匹配了一个T串以后怎么继续进行下一个匹配。
完全匹配T串后,我们需要将S串的i指针往下挪一位,那么容易知道前面的字符串都已经是匹配过的了,根据KMP算法的思想,我们需要将T串的j指针进行回溯就能继续匹配,问题就在于这个j指针应该回溯到哪里才合适。
这里给出一个例子
主串(S串) ababaab
子串(T串) aba
这里的下标就从0开始吧,我们看到T串在S串中出现的位置是0和2,现在我们先把第一次匹配的情况画出来,这里next数组也顺便给出来了,这是没优化过的next数组

然后根据原KMP算法,i++, j++

按照原算法,在下个循环当中应该已经退出循环了,但是在这里我们当然不能这么做,所以我们应该将j回溯,不过这问题来了,之前我们进行回溯是根据next数组来将j进行回溯的,在上图的情况下,我们可以看到j所指的位置并没有对应的next值,那怎么办?
先不讨论算法,就单纯观察我们知道上图中的j应该是回溯到了b(T串1位置)那里,因为T串末尾的a跟首部的a相同,也就是这部分的后缀分前缀是相同的,根据KMP算法思想,这部分匹配过,就应该回溯到相同前缀的后一位,这就回溯到了b
到这里我们就已经是发现了,其实这种回溯就是在把next数组多往后求一位,虽然传统的KMP算法在求next数组时只是求出跟T串等长长度而已,但其实多往后求一位也是可以的,我们回到求T串求到最后一位时的情景:

指针的情况在如上图所示时,按传统算法本该退出循环的,但是理论上确实还是可以再往后求一位的,这里又有T[i] == T[j],所以i++, j++,然后next[i] = j,这样,我们就又额外得到了一位next数组的值

这个最后一位的next值意义是一样的,我们可以把这个字符串看成是长度为4的字符串,然后这个T[3]字符非常诡异,任何字符都不与它相等,也就是说,这个位置是必定匹配失败的,但是由于前3位字符都匹配成功了,所以这个回溯依然是合理的。
这样一来,S串中找出多个T串的算法就好弄了,这个T串我们看成是原先T串上多延长了一位,但是这个最后一位怎么匹配也不会匹配成功,所以在这个匹配算法中最多只会匹配到原T串长度,然后匹配到T串+1长度时就会回溯j指针,通过这种方法,我们就可以找出所有的T串出现位置了。
附代码(next数组优化过的那种):
vector<int> KMP(const string& S, const string& T)
{
vector<int> Next;
Next.push_back(-); for (int i = , j = -; i < T.size();) {
if (j == - || T[i] == T[j]) {
i++, j++;
if (i != T.size() && T[j] == T[i]) Next.push_back(Next[j]);
else Next.push_back(j);
}
else j = Next[j];
} vector<int> res;
for (int i = , j = ; i < S.size() && j < (int)T.size();) {
if (j == - || S[i] == T[j]) {
i++, j++;
if (j == T.size()) {
res.push_back(i - j);
j = Next[j];
}
}
else j = Next[j];
} return res;
}
KMP小扩展,找出子串在主串中出现的所有位置的更多相关文章
- search for a range(找出一个数在数组中开始和结束位置)
Given an array of integers sorted in ascending order, find the starting and ending position of a giv ...
- KMP模版 && KMP求子串在主串出现的次数模版
求取出现的次数 : #include<bits/stdc++.h> ; char mo[maxn], str[maxn];///mo为模式串.str为主串 int next[maxn]; ...
- Leetcode30--->Substring with Concatenation of All Words(主串中找出连接给定所有单词的子串的位置)
题目:给定一个字符串S(主串),一个字符串数组words,其中的字符串的长度相同.找到所有的子串位置,要求是words中字符串的一个连接: 举例: For example, given:s: &quo ...
- 小易邀请你玩一个数字游戏,小易给你一系列的整数。你们俩使用这些整数玩游戏。每次小易会任意说一个数字出来,然后你需要从这一系列数字中选取一部分出来让它们的和等于小易所说的数字。 例如: 如果{2,1,2,7}是你有的一系列数,小易说的数字是11.你可以得到方案2+2+7 = 11.如果顽皮的小易想坑你,他说的数字是6,那么你没有办法拼凑出和为6 现在小易给你n个数,让你找出无法从n个数中选取部分求和
小易邀请你玩一个数字游戏,小易给你一系列的整数.你们俩使用这些整数玩游戏.每次小易会任意说一个数字出来,然后你需要从这一系列数字中选取一部分出来让它们的和等于小易所说的数字. 例如: 如果{2,1,2 ...
- HDU 2087 剪花布条(模式串在主串中出现的次数主串中子串不可重叠)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2087 题意:求模式串在主串中出现的次数,与模式串匹配的子串之间不可重叠. 思路:用kmp算法解决,在匹 ...
- 《找出1到正整数N中出现1的次数》
<找出1到正整数N中出现1的次数> 编程思想:依次求出正整数每个位数上出现1的次数,累加即可得到最后想要的结果:而每一位上出现1的个数与和它相邻的其它位数上的数字有关系(以此位置上的数为对 ...
- C语言:对传入sp的字符进行统计,三组两个相连字母“ea”"ou""iu"出现的次数,并将统计结果存入ct所指的数组中。-在数组中找出最小值,并与第一个元素交换位置。
//对传入sp的字符进行统计,三组两个相连字母“ea”"ou""iu"出现的次数,并将统计结果存入ct所指的数组中. #include <stdio.h& ...
- java基础知识回顾之---java String final类普通方法的应用之“子串在整串中出现的次数”
/* * 2 一个子串在整串中出现的次数. * "loveerlovetyloveuiloveoplove" * 思路: * 1,要找的子串是否存在,如果存在获取其出现的位置.这个 ...
- 找出N个无序数中第K大的数
使用类似快速排序,执行一次快速排序后,每次只选择一部分继续执行快速排序,直到找到第K个大元素为止,此时这个元素在数组位置后面的元素即所求 时间复杂度: 1.若随机选取枢纽,线性期望时间O(N) 2.若 ...
随机推荐
- 浅谈python的第三方库——pandas(一)
pandas作为python进行数据分析的常用第三方库,它是基于numpy创建的,使得运用numpy的程序也能更好地使用pandas. 1 pandas数据结构 1.1 Series 注:由于pand ...
- webpack安装jQuery报错
使用webpack搭建项目,并使用了node下载了jQuery使用,使用命令行完成构建时发现报错了, ERROR in ./node_modules/jquery/lib/node-jquery.js ...
- BLOB-数据库中用来存储二进制文件的字段类型
BLOB (binary large object)----二进制大对象,是一个可以存储二进制文件的容器. 在计算机中,BLOB常常是数据库中用来存储二进制文件的字段类型. BLOB是一个大文件,典型 ...
- Pikachu-Unsafe Fileupload(不安全的文件上传)
不安全的文件上传漏洞概述 文件上传功能在web应用系统很常见,比如很多网站注册的时候需要上传头像.上传附件等等.当用户点击上传按钮后,后台会对上传的文件进行判断 比如是否是指定的类型.后缀名.大小等等 ...
- pyqt5-下拉框联动效果
from PyQt5.Qt import * class MyWindow(QWidget): def __init__(self): super().__init__() self.setWindo ...
- Python3标准库:collections容器数据类型
1. collections容器数据类型 collections模块包含除内置类型list.dict和tuple以外的其他容器数据类型. 1.1 ChainMap搜索多个字典 ChainMap类管理一 ...
- 【database】oracle关联查询主表对应的特定一行从表结果集
主表: 从表: 结果集: 查询从表中年龄最大的一行数据,如果存在年龄相等的则为了保证唯一取id(主键)最大的一行. 一.利用sql子查询嵌套 -- -------------------------- ...
- Hadoop学习之路(7)MapReduce自定义排序
本文测试文本: tom 20 8000 nancy 22 8000 ketty 22 9000 stone 19 10000 green 19 11000 white 39 29000 socrate ...
- Java课后总结-原码、补码、反码
1.原码.补码.反码的定义和表示方法. 数在计算机中是以二进制形式表示的. 数分为有符号数和无符号数. 原码.反码.补码都是有符号定点数的表示方法. 一个有符号定点数的最高位为符号位,0是正,1是副. ...
- laravel 解决 sql mode only_full_group_by
this is incompatible with sql_mode=only_full_group_by 先贴报错是这样的哦,sql 中使用到了 group by 然后这是mysql-5.7以上版本 ...