(原创)数据结构之利用KMP算法解决串的模式匹配问题

给定一个主串S(长度<=10^6)和一个模式T(长度<=10^5),要求在主串S中找出与模式T相匹配的子串,返回相匹配的子串中的第一个字符在主串S中出现的位置。

输入格式:

输入有两行: 第一行是主串S; 第二行是模式T.

输出格式:

输出相匹配的子串中的第一个字符在主串S中出现的位置。若匹配失败,输出0.

输入样例:

在这里给出一组输入。例如:

aaaaaba
ba

输出样例:

在这里给出相应的输出。例如:

6


解题思路:串的模式匹配有两种:一种是BF算法,一种是KMP算法;基于这道题给的数据,若用BF算法便会超时,所以我们这道题用KMP算法;那么问题来了,KMP算法到底怎么用的;简单来讲,就是有两个步骤:1、求模式串的next数组;2、进行主串与模式串的匹配;假设主串和模式串分别为
第一个问题:如何求next数组??next数组求的是模式串的!!!下面就以上面给的模式串为例;next数组便是前缀中的最长相同前后缀,说起来比较绕,什么意思呢,模拟一遍就清楚了;

所以对于模式串对应的next数组为

这样我们就求出了next数组;接下来进行模式匹配,其实这样就会有个问题,所以实际上next数组这样是需要改进的;

假设我们不改进的话,进行匹配会出现什么问题呢;

进行模式匹配的大概代码如下:

1、即匹配,则i++;j++;

2、不匹配,根据刚刚求出的next数组,进行跳next数组;

下面代码中ssize为主串s的长度,tsize为模式串t的长度;

下面我们就根据代码模拟一遍;

 1
 2                int i = 0 ;
 3                int j = 0;
 4         while(i<ssize&&j<tsize)
 5         {
 6
 7                 if(s[i]==t[j])
 8             {
 9                 i++;
10                 j++;
11
12             }
13             else
14             {
15                  j = next1[j];
16             }
17
18
19         }
20
21
22             if(j==tsize)
23             {
24                 cout <<  i-j+1;
25             }

上面我们求出来的next数组为:

现在我们把它们的下面也写上:

现在开始模拟一遍:

我们发现匹配到c的时候不匹配了,跳next数组,则跳到下标为0处,变成:

 

 此时也不匹配,变成应该跳next数组,跳到下标为0处,但是这样就变成死循环了,所以我们应该退一步,将next数组的第0个赋值为-1,且将整个next数组向后移;就不会变成死循环了;

再模拟一次:

此时不匹配跳next数组;

变成:

发现a不匹配,跳next数组:

继续模拟:

发现不匹配,所以此时next应该跳到下标为-1处,但是这里没有下标为-1的,所以实际上就是整体向后移;变成:

发现完全匹配了;

那么基于上面的改进,next数组应该怎么写呢:

代码如下:

 1 string s;
 2 string t;
 3 int ssize;
 4 int tsize;
 5 int next1[2000000];
 6         void nextsz(string t,int tsize)
 7         {
 8             next1[0] = -1;     //防止进入死循环,而且到不能匹配时能整体后移
 9             int k = -1;     //是为了调节next数组;
10             int j = 0 ;
11             while(j < tsize-1)
12             {
13             if(k==-1||t[j]==t[k])   //k=-1进入这个循环是为了整体向后移;
14                 {
15                 ++k;         k实际上也是记录了相同的个数;
16                 ++j;
17
18                     next1[j] = k;   找到next数组;
19
20                 }
21                else
22                 k = next1[k];    //不相同则更新k;
23             }
24
25         }

现在会了next数组,我们则可以进行模式匹配了;

利用上面求的next数组来进行模式匹配;过程原理和上面画的图是一模一样的;

代码如下:

 1     int  kmp(string s,string t,int sszie,int tsize)
 2         {
 3             int j = 0;
 4             int i = 0;
 5             while(i<ssize&&j<tsize)
 6         {
 7
 8                 if(j==-1||s[i]==t[j])  j=-1是为了调节到跳无可跳时,整体向后移;
 9             {
10                 i++;      //匹配整体向前移;
11                 j++;
12
13             }
14             else
15             {
16                  j = next1[j];    不断跳next数组;
17             }
18
19
20         }
21
22
23             if(j==tsize)
24             {
25                 return  i-j+1;  //返回模式串在主串的第一个下标;
26             }
27             else return -1;  //不匹配,则返回-1;
28         }

所以这道题的完整代码如下:

代码如下:
 1 #include<iostream>
 2 #include<string.h>
 3 using namespace std ;
 4
 5 string s;
 6 string t;
 7 int ssize;
 8 int tsize;
 9 int next1[2000000];
10         void nextsz(string t,int tsize)
11         {
12             next1[0] = -1;
13             int k = -1;
14             int j = 0 ;
15             while(j < tsize-1)
16             {
17             if(k==-1||t[j]==t[k])
18                 {
19                 ++k;
20                 ++j;
21
22                     next1[j] = k;
23
24                 }
25                else
26                 k = next1[k];
27             }
28
29         }
30
31         int  kmp(string s,string t,int sszie,int tsize)
32         {
33             int j = 0;
34             int i = 0;
35             while(i<ssize&&j<tsize)
36         {
37
38                 if(j==-1||s[i]==t[j])
39             {
40                 i++;
41                 j++;
42
43             }
44             else
45             {
46                  j = next1[j];
47             }
48
49
50         }
51
52
53             if(j==tsize)
54             {
55                 return  i-j+1;
56             }
57             else return 0;
58         }
59
60
61 int main()
62 {
63     cin>>s;
64     cin>>t;
65
66     ssize =  s.size();
67     tsize = t.size();
68         nextsz(t,tsize);
69         cout<<kmp(s,t,ssize,tsize)<<endl;
70
71
72
73 }

原文地址:https://www.cnblogs.com/yewanting/p/10674340.html

时间: 2024-08-06 11:49:06

(原创)数据结构之利用KMP算法解决串的模式匹配问题的相关文章

运用kmp算法解决的一些问题的简单题解

学习kmp算法我最后是看的数据结构书上的一本教材学会的..我觉得kmp相对于普通的BF算法就是避免了很多不必要的匹配,而kmp算法的精髓自然就在于next数组的运用...而next数组简而言之就是存储的就是模式串中第j个字符与主串中相应字符"失配"时,在模式串中需要重新和主串中失配的字符相比较的位置...我觉得这句概括挺好的... 题1: hdu   1711  number   sequence 题目链接: http://acm.hdu.edu.cn/showproblem.php?

SA:利用SA算法解决TSP(数据是14个虚拟城市的横纵坐标)问题——Jason niu

%SA:利用SA算法解决TSP(数据是14个虚拟城市的横纵坐标)问题--Jason niu X = [16.4700 96.1000 16.4700 94.4400 20.0900 92.5400 22.3900 93.3700 25.2300 97.2400 22.0000 96.0500 20.4700 97.0200 17.2000 96.2900 16.3000 97.3800 14.0500 98.1200 16.5300 97.3800 21.5200 95.5900 19.4100

KMP算法解决字符串匹配

该算法由D.E.Knuth ,J.H.Morris和 V.R.Pratt提出,用于解决字符串匹配问题. 思想: 设目标串(主串)为s,模式串为t ,并设i指针和j指针分别指示目标串和模式串中正待比较的字符,设i和j的初值均为0.若有s[i]=t[j],则i和j分别加1.否则,i不变,j退回到j=next[j-1]的位置,再比较s[i]和t[j],若相等,则i和j分别加1.否则,i不变,j再次退回到j=next[j]的位置,依此类推.直到下列两种可能: 1. 模式串t中的字符全部匹配,则出现频率+

KMP 解决串的模式匹配问题

首先贴三段代码,一组是回溯法,暴力求解,另外两个是KMP串模式匹配 /* 回溯法字符串匹配算法就是用一个循环来找出所有有效位移, 该循环对n-m+1个可能的位移中的每一个index值,检查条件为P[0-m-1]= S[index-index+m-1] (因为模式串的长度是m,索引范围为0-m-1).该算法思维比较简单(但也常被一些公司做为面试题), 很容易分析出本算法的时间复杂度为O(pattern_length*target_length) int search(char const*, in

数据结构20:KMP算法(快速模式匹配算法)详解

通过上一节的介绍,学习了串的普通模式匹配算法,大体思路是:模式串从主串的第一个字符开始匹配,每匹配失败,主串中记录匹配进度的指针 i 都要进行 i-j+1 的回退操作(这个过程称为“指针回溯”),同时模式串向后移动一个字符的位置.一次次的循环,直到匹配成功或者程序结束. "KMP"算法相比于"BF"算法,优势在于: 在保证指针 i 不回溯的前提下,当匹配失败时,让模式串向右移动最大的距离: 并且可以在O(n+m)的时间数量级上完成对串的模式匹配操作: 故,"

KMP算法解决字符串出现次数

比如主串为:"1001110110" 子串为:"11" 则出现位置分别为:3 4 7 //KMP算法 2015.6.7 #include<iostream> #include<stdlib.h> using namespace std; int main() { char *s = "1001110110"; char *p = "11"; int ar[20] = { 0 }; //next ar[0

24、蛤蟆的数据结构笔记之二十四串的模式匹配算法

24.蛤蟆的数据结构笔记之二十四串的模式匹配算法 本篇名言:"燧石受到的敲打越厉害,发出的光就越灿烂. -- 马克思" 来看下两个算法,BF和KMP算法在串的模式匹配中实现. 欢迎转载,转载请标明出处: 1.  BF算法 BF(Brute Force)算法是普通的模式匹配算法,BF算法的思想就是将目标串S的第一个字符与模式串T的第一个字符进行匹配,若相等,则继续比较S的第二个字符和 T的第二个字符:若不相等,则比较S的第二个字符和T的第一个字符,依次比较下去,直到得出最后的匹配结果.B

KMP算法学习记录----《大话数据结构》部分匹配表学习部分

如需转载,请保留本文链接. 首先先将<大话数据结构>关于KMP算法的讲解部分贴上,本文不提供下载链接,也不会将电子书作为资料留百度云,需要电子书的各位,请自行寻找电子版. 关于上述的KMP算法种的next数组的推导部分,一直不是很明白,本贴是关于上述部分的学习推导记录. 以书中字符串为例: 1|2|3|4|5|6|7|8|9| a|b|a|b|a|a|a|b|a| 0|1|1|2|3|4|2|2|3| string T = "ababaaaba"; int i = 1;j

全局匹配KMP算法

KMP算法是通过分析模式字符串,预先计算每个位置发生不匹配的时候,所需GOTO的下一个比较位置,整理出来一个next数组,然后在上面的算法中使用. 本全局匹配KMP算法针对串的堆式存储数据结构 # define MAXSIZE 45 //固定next数组的长度 # define OK 1 # define ERROR 0 typedef int Status; //返回状态 //存放匹配字符串的位置 int indexArray[MAXSIZE] = {0}; //记录匹配字符串出现的次数 in