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小扩展,找出子串在主串中出现的所有位置的更多相关文章

  1. search for a range(找出一个数在数组中开始和结束位置)

    Given an array of integers sorted in ascending order, find the starting and ending position of a giv ...

  2. KMP模版 && KMP求子串在主串出现的次数模版

    求取出现的次数 :  #include<bits/stdc++.h> ; char mo[maxn], str[maxn];///mo为模式串.str为主串 int next[maxn]; ...

  3. Leetcode30--->Substring with Concatenation of All Words(主串中找出连接给定所有单词的子串的位置)

    题目:给定一个字符串S(主串),一个字符串数组words,其中的字符串的长度相同.找到所有的子串位置,要求是words中字符串的一个连接: 举例: For example, given:s: &quo ...

  4. 小易邀请你玩一个数字游戏,小易给你一系列的整数。你们俩使用这些整数玩游戏。每次小易会任意说一个数字出来,然后你需要从这一系列数字中选取一部分出来让它们的和等于小易所说的数字。 例如: 如果{2,1,2,7}是你有的一系列数,小易说的数字是11.你可以得到方案2+2+7 = 11.如果顽皮的小易想坑你,他说的数字是6,那么你没有办法拼凑出和为6 现在小易给你n个数,让你找出无法从n个数中选取部分求和

    小易邀请你玩一个数字游戏,小易给你一系列的整数.你们俩使用这些整数玩游戏.每次小易会任意说一个数字出来,然后你需要从这一系列数字中选取一部分出来让它们的和等于小易所说的数字. 例如: 如果{2,1,2 ...

  5. HDU 2087 剪花布条(模式串在主串中出现的次数主串中子串不可重叠)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2087 题意:求模式串在主串中出现的次数,与模式串匹配的子串之间不可重叠. 思路:用kmp算法解决,在匹 ...

  6. 《找出1到正整数N中出现1的次数》

    <找出1到正整数N中出现1的次数> 编程思想:依次求出正整数每个位数上出现1的次数,累加即可得到最后想要的结果:而每一位上出现1的个数与和它相邻的其它位数上的数字有关系(以此位置上的数为对 ...

  7. C语言:对传入sp的字符进行统计,三组两个相连字母“ea”"ou""iu"出现的次数,并将统计结果存入ct所指的数组中。-在数组中找出最小值,并与第一个元素交换位置。

    //对传入sp的字符进行统计,三组两个相连字母“ea”"ou""iu"出现的次数,并将统计结果存入ct所指的数组中. #include <stdio.h& ...

  8. java基础知识回顾之---java String final类普通方法的应用之“子串在整串中出现的次数”

    /* * 2 一个子串在整串中出现的次数. * "loveerlovetyloveuiloveoplove" * 思路: * 1,要找的子串是否存在,如果存在获取其出现的位置.这个 ...

  9. 找出N个无序数中第K大的数

    使用类似快速排序,执行一次快速排序后,每次只选择一部分继续执行快速排序,直到找到第K个大元素为止,此时这个元素在数组位置后面的元素即所求 时间复杂度: 1.若随机选取枢纽,线性期望时间O(N) 2.若 ...

随机推荐

  1. sublime中写python代码

    SublimeREPL插件 这个是首先要安装的,此插件主要功能是为了实现交互,在安装后需要一些简单的配置 在Preferences--> Key Bindings--> user下添加如下 ...

  2. Oracle实例占用超高CPU排查

    CPU主要功能:处理指令.执行操作.要求进行动作.控制时间.处理数据. 结合数据库实例CPU占用高,可能的原因是数据库在执行大量的操作(全表查询.大量排序等). 由于公司没有DBA,遇到数据库问题只能 ...

  3. 发ajax响应json格式数据

    1.maven依赖 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="h ...

  4. C# WPF聊天界面(3/3)

    微信公众号:Dotnet9,网站:Dotnet9,问题或建议:请网站留言, 如果对您有所帮助:欢迎赞赏. C# WPF聊天界面(3/3) 阅读导航 本文背景 代码实现 本文参考 1.本文背景 系列文章 ...

  5. VSCode(主进程)

    Overview(总览) SETUP(设定) Overview(总览) Linux(略) macOS(略) Windows 使用WSL,您可以在Windows上安装和运行Linux发行版.这使您能够在 ...

  6. STL-优先级队列-priority_queue

    头文件是<queue> 操作很简单 #include <iostream> #include <cstdio> #include <queue> usi ...

  7. udp_demo(傻瓜来回发送)

    代码讲解 import socket # 发送数据 def send_data(udp_socket, dest_ip, dest_port): send_msg = input('请输入要发送的数据 ...

  8. 记录 Docker 的学习过程 (自建私有仓库)

    私有仓库的创建 node1#wget http://harbor.orientsoft.cn/harbor-v1.4.0/harbor-offline-installer-v1.4.0.tgz nod ...

  9. 微信公众号和小程序可以共用access_token值吗?

    微信公众号和小程序可以共用access_token值吗? 答案:是不能的 因为两者都可通过统一接口(https://api.weixin.qq.com/cgi-bin/message/subscrib ...

  10. AI 数学基础:概率分布,幂,对数

    1.概率分布  参考: https://blog.csdn.net/ZZh1301051836/article/details/89371412 p 2.幂次的意义 物理理解:幂次描述的是指数型的变化 ...