查找子字符串----KMP算法深入剖析
假设主串:a b a b c a b c a c b a b
子串:a b c a c
1、一般匹配算法
逐个字符的比较,匹配过程如下:
第一趟匹配
a b a b c a b c a c b a b
a b c
第二趟
a b a b c a b c a c b a b
a
第三趟
a b a b c a b c a c b a b
a b c a c
第四趟
a b a b c a b c a c b a b
a
第五趟
a b a b c a b c a c b a b
a
第六趟
a b a b c a b c a c b a b
a b c a c
匹配成功。
性能分析:情况好:时间复杂度O(m+n);情况差:时间复杂度O(m*n)。
2、一般匹配算法改进
即KMP算法。可以发现上面的算法,每一趟匹配过程中出现字符不等时,回溯指针,如果将其改进,指针不回溯,利用已经得到的部分匹配的结果将模式向右移动的更远一些,然后继续比较。那么算法性能会得到大大的提高。
看到上面的过程,在第三趟的匹配过程中,当i=6,j=4字符不等时,又从i=3,j=0重新开始比较。其实可以容易发现,在i=3和 j=0,i=4和i=0以及i=5和j=0这3次比较都是不必进行的。因为从第三趟部分匹配结果就可以得出,主串中第3,4,5个字符是’b’,’c’,’a’。而模式中第一个字符是’a’,因此无需和这3个字符进行比较了,紧需要向右移动3个字符继续进行i=6,j=1时字符串比较就行了。那么一种理想的模式匹配就可以的出来了。
KMP匹配过程如下:
第一趟
a b a b c a b c a c b a b
a b c
第二趟
a b a b c a b c a c b a b
a b c a c
第三趟
a b a b c a b c a c b a b
a b c a c
匹配成功,可以看出算法效率提高了不少。
3、剖析KMP算法:
假设(n>m)
主串:s0 s1 s2 s3 s4 s5 s6 …… s(n)
模式:p0 p1 p2 p3 p4……….p(m)
当匹配过程中产生失配(s(i)!=p(j))时,主串的第i个字符应与模式中的哪个字符相比较?假设此时与模式中的第k(k<j)个字符相比较,那么就有p0p1…p(k-1)=s(i-k)s(i-k+1)…s(i-1) --式1(就好像上面中绿的的字符a,这里是从模式中第1个字符开始比较与主串中字符a相同)。
当匹配失配时(s(i)!=p(j)),可以得到p0p1p2p3…p(j-1)=s(i-j)s(i-j+1)…s(i-1) --式2
从式2可以得到p(j-k)p(j-k+1)…p(j-1)=s(i-k)s(i-k+1)..s(i-1) --式3
由式1和式3可以得到p0p1…p(k-1)=p(j-k)p(j-k+1)…p(j-1) --式4
若令next[j]=k,则next[j]表明当模式中第j个字符与主串中相应字符失配时,在模式中需要重新和主串中该字符进行比较的字符位置。那么next 函数定义为:
(1)-1 当j=0时
next[j]= (2)max{k|0<k<j 且式4成立}
(3)0 其他情况
那么此时next值如何求得呢?
由定义知道next[0]=-1;设next[j]=k,这表明在模式串中有这样关系p0p1…p(k-1)=p(j-k)p(j-k+1)…p(j-1) (0<k<j) --式5。此时next[j+1]的值有两中情况:
(1)若p(k)=p(j), 则:p0p1…p(k)=p(j-k)p(j-k+1)…p(j) --式6,即next[j+1]=k+1。
(2)若p(k)!=p(j),则:p0p1…p(k)!=p(j-k)p(j-k+1)…p(j)--式7,此时可以把该问题看成模式匹配的问题,整个模式串既是主串又是模式串,这里应将模式向右移动next[k](模式中第k个字符与主串失配时,需要移动的位置)位置,和主串中的第j个字符相比较。若next[k]=k’,且p(j)=p(k’),则可以得到next[j+1]=next[k]+1即 next[j+1]=next[next[j]]+1。那么还要注意下当模式中上一个字符串与下一个字符串相等时候,它们next值是相等的。
4、KMP算法代码:
- #include "stdafx.h"
- #include "iostream.h"
- #include "string.h"
- //next数组
- void GetNext(char *subStr,int *next)
- {
- int len=strlen(subStr);
- next[0]=-1;
- int i=0,j=-1;
- while(i<len)
- {
- if(j==-1||subStr[i]==subStr[j])
- {
- i++;
- j++;
- //前后缀字符相等
- if(subStr[i]==subStr[j])
- next[i]=next[j];
- else
- next[i]=j;
- }
- else
- j=next[j];
- }
- }
- //KMP算法
- int KMP(char *str,char *subStr)
- {
- int lenStr=strlen(str);
- int lenSubstr=strlen(subStr);
- int i=0,j=0;
- int *next=new int[lenStr];
- GetNext(subStr,next);
- //遍历主串和子串
- while(i<lenStr&&j<lenSubstr)
- {
- //与一般匹配算法增加了j==-1判断
- if(j==-1||str[i]==subStr[j])
- {
- i++;
- j++;
- }
- //j回溯,i不变
- else
- j=next[j];
- }
- delete[] next;
- //返回子串的位置
- if(j>=lenSubstr)
- return i-lenSubstr;
- else
- return -1;
- }
- int main()
- {
- char *str="iloveyouoooyouloveme";
- char *subStr1="youoooyou";
- char *subStr2="youoooyou2";
- cout<<KMP(str,subStr1)<<endl;
- cout<<KMP(str,subStr2)<<endl;
- return 0;
- }
转载于:https://www.cnblogs.com/Vae1990Silence/p/4345090.html
查找子字符串----KMP算法深入剖析相关推荐
- 459. 重复的子字符串-KMP算法
459. 重复的子字符串 给定一个非空的字符串 s ,检查是否可以通过由它的一个子串重复多次构成. 示例 1: 输入: s = "abab" 输出: true 解释: 可由子串 & ...
- C语言检查一个字符串是否为另一个字符串的子字符串的算法(附完整源码)
C语言检查一个字符串是否为另一个字符串的子字符串的算法 C语言检查一个字符串是否为另一个字符串的子字符串的算法完整源码(定义,实现,main函数测试) C语言检查一个字符串是否为另一个字符串的子字符串 ...
- python 子字符串 位置_python查找子字符串位置Python变量和数据类型详解
Python变量和数据类型 Python中数据类型 Python之print语句 Python的注释 Python中什么是变量 Python中定义字符串 Python中raw字符串与多行字符串 Pyt ...
- python KMP算法查找子字符串
最近在刷leecode,碰见字符串检索题.原题是这样的,有两个字符串,一长一短,就看看短的是不是在长的里面,如果在返回第一个字符的下标. 因为总忘记,所以记录下我的思路是咋捋顺的,其实看这一篇就够了, ...
- Python在字符串中查找子字符串
这是小白博主在刷leetcode时遇到的一道题,这是博主近日刷的leetcode题库时结果表现最好的一道题,故在此分享这份喜悦. 希望在以后的日子里可以继续进步,持之以恒. 目录 题目介绍 解题思路及 ...
- 汇编原理实验 --查找子字符串的位置
实验2:(子字符串,查找字符串在另一个字符串中出现的位置) 设计算法:将用户输入关键字和句子,将bx为关键字起始位置地址,dx赋初值为句子起始位置地址,将dx和bx内容进行匹配,如果不匹配则dx指向句 ...
- 在Python中查找子字符串索引的5种方法
在Python中查找字符串中子字符串索引的5种方法 (5 Ways to Find the Index of a Substring in Strings in Python) str.find() ...
- 在字符串中查找子字符串
今天中午一觉睡醒,刷b站,看见一个视频: 最浅显易懂的 KMP 算法讲解https://www.bilibili.com/video/BV1AY4y157yL?spm_id_from=333.1007 ...
- C语言strstr()函数(在主字符串里查找子字符串,返回第一次找到的子字符串以及后面的字符串)
需包含头文件:C 标准库 - <string.h> 文章目录 描述 声明 参数 返回值 实例 描述 C 库函数 char *strstr(const char *haystack, con ...
最新文章
- Android --- This project contains Java compilation errors,which can cause rendering failures for
- 红米airdots掉了怎么查找_红米K30至尊版与realmeX7 Pro,两款性价比手机,谁才是第一位...
- jsbridge实现及原理_如何实现一个优雅的jsBridge
- 前端学习(1903)vue之电商管理系统电商系统之调用api添加用户
- 环形队列出队的元素怎么输出出来_队列的知识讲解与基本实现(数据结构)
- 二维均匀分布的边缘密度函数_理解概率密度函数
- asp.net 移除Server, X-Powered-By, 和X-AspNet-Version头
- java list打乱顺序_「collections.shuffle」Collections.shuffle()打乱List - seo实验室
- 如何利用图像识别、语音识别、文本挖掘做好鉴黄?
- 算数计算机在线应用,数学计算器
- 安卓CTS官方文档之兼容性方案概览
- 计算机识别键盘流程,电脑键盘拼音打字操作过程
- xp系统安装ftp服务器,xp系统安装ftp服务器
- 施密特正交化_量化投资因子正交化
- 微软测试管理框架(Microsoft Test Manager)
- 国际知名财务和ERP软件系统
- 求助:程序员得了结膜炎+干眼症怎么办?
- 动态活体检测 | 算法分析
- 广告刷屏世界杯,联想Filez助力海信全球营销运营
- python爬虫知乎点赞_Python爬虫爬取知乎小结
热门文章
- java设计app_一个APP的诞生——从零开始设计你的手机应用
- linux /proc/stat 计算线程cpu,Linux下用/proc/stat文件来计算cpu的利用率(附源码)
- java线程main异常,‘java.lang.NoSuchMethodError:main的原因’线程中的异常“main”’...
- Android运行时修改Manifest,Android如何动态修改Manifest文件
- c语言静态函数调用静态变量_C语言中的静态变量和函数
- box-sizing,你的宽高度计算对了吗?
- js中split之正则运用(模式匹配)
- Spring+SpringMVC+mybatis+Quartz整合
- 如何用四个简单的步骤加速 LibreOffice
- 2014牡丹江——Hierarchical Notation