字符串匹配问题【KMP算法】

一、问题

给定两个字符串S和T,找出T在S中出现的位置。

二、朴素算法

当S[i] != T[j]时,把T往后移一位,回溯S的位置并重新开始比较。

  

(1) 成功匹配的部分(ABC)中,没有一样的字符

S: i A B C A B C E
T: j A B C E      
S: i A B C A B C E
T: j   A B C E    
S: i A B C A B C E
T: j     A B C E  
S: i A B C A B C E
T: j       A B C E

(2) 成功匹配的部分(ABA)中,有一样的部分(A)

S: i A B A A B A C
T: j A B A C      
S: i A B A A B A C
T: j   A B A  
S: i A B A A B A C
T: j     A B
S: i A B A A B A C
T: j       A B A C

三、KMP算法

通过整理模式串T中的元素相似性,减少朴素算法中对S不必要的回溯。

前缀:包含T首字母的子串

后缀:包含T最后一个字母的子串

next数组

next[j]: 求得T[0, ..., j-1] 中最长的相同的前/后缀,next[j] 是该前缀的后一个字符所在位置。当T[j] 和S[i]不相同时,回溯T[j] 到next[j],S[i]的位置不变。

(1) next[j] =-1  if j == 0 //第一个字符的回溯位置为 -1

(2) next[j] = max{k|T0...Tk-1 和 Tj-k-1...Tj-1} //最长的相同的前后缀,回溯时相同的部分不用再比较

(3) next[j] = 0 if 其他情况 //没有找到相同的前后缀,回溯的时候只能从第一个字符重新开始比较

计算next数组 

T中有两个相同的子串X(蓝色部分),i 和 j 是当前比较的两个位置

 (1) T[i] = T[j] = 2: next[j+1] = i+1 //T[0, ..., j] 的前缀Xi 和 后缀Xj 一样 

 (2) 2 = T[i] != T[j] = 3: i = next[i] //对 i 进行回溯,重新寻找满足条件的前后缀。绿色部分,最后一个元素为 3

next数组的使用

(1) 成功匹配的部分(ABC)中,没有一样的字符

S: i A B C A B C E
T: j A B C E      
T: next[j] -1 0 0 0      
S: i A B C A B C E
T: j       A B C E
T: next[j]       -1 0 0 0

S[3] = D, T[3] = E, 不相同。j = next[3] = 0 回溯。(ABC)没有相同的部分,因此不必将 S:i 回溯再尝试匹配。

(2) 成功匹配的部分(ABA)中,有一样的部分(A)

S: i A B A A B A C
T: j A B A C      
T: next[j] -1 0 0 1      
S: i A B A A B A C
T: j       A B A C
T: next[j]       -1 0 0 1

S[3] = D, T[3] = C,第三个位置不匹配。j = next[3] = 1  回溯。下次比较是可以直接从S[3]和T[1]开始匹配,因为T[0] 和 T[2] 相同。

四、KMP算法源码

【hihocoder】 http://hihocoder.com/problemset/problem/1015?sid=808424

 1 #include <iostream>
 2 #include <string>
 3 using namespace std;
 4
 5 //计算next数组
 6 void get_next(string& T, int* next)
 7 {
 8     int i = 0, j = -1, Tlen = T.length();
 9     next[0] = -1;
10     while(i < Tlen)
11     {
12         if(j == -1 || T[i] == T[j])
13         {
14             ++i;
15             ++j;
16             next[i]=(T[i] == T[j] ? next[j]:j);//使得回溯前和回溯后的元素不一样
17         }
18         else
19             j = next[j];
20     }
21 }
22
23 //计算T在S中出现的次数
24 int subStrCnt(string& S, string& T)
25 {
26     int cnt = 0;
27     int Slen = S.length(), Tlen = T.length();
28     int next[10000];
29     int i = 0, j = 0;
30     get_next(T, next);
31     while(i < Slen && j < Tlen)
32     {
33         if(j == -1 || S[i] == T[j])
34         {
35             ++i;
36             ++j;
37         }
38         else
39             j = next[j];
40         if(j == Tlen){//T匹配完成,从T: next[j]再开始
41             cnt++;
42             j = next[j];
43         }
44     }
45     return cnt;
46 }
47 int main()
48 {
49     int cnt;
50     string S, T;
51     cin>>cnt;
52     while(cnt-- > 0)
53     {
54         cin>>T>>S;
55         cout<<subStrCnt(S, T)<<endl;
56     }
57     return 0;
58 }

时间: 2024-07-29 00:39:04

字符串匹配问题【KMP算法】的相关文章

字符串匹配的KMP算法

html, body { font-size: 15px; } body { font-family: Helvetica, "Hiragino Sans GB", 微软雅黑, "Microsoft YaHei UI", SimSun, SimHei, arial, sans-serif; line-height: 1.6; color: ; background-color: ; margin: 0; padding: 16px 20px; } h1, h2, h

[算法系列之二十六]字符串匹配之KMP算法

一 简介 KMP算法是一种改进的字符串匹配算法,由D.E.Knuth与V.R.Pratt和J.H.Morris同时发现,因此人们称它为克努特-莫里斯-普拉特操作(简称KMP算法).KMP算法的关键是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的. 二 基于部分匹配表的KMP算法 举例来说,有一个字符串"BBC ABCDAB ABCDABCDABDE",我想知道,里面是否包含搜索串"ABCDABD"? 步骤1:字符串"BBC ABC

字符串匹配(KMP 算法 含代码)

主要是针对字符串的匹配算法进行解说 有关字符串的基本知识 传统的串匹配法 模式匹配的一种改进算法KMP算法 网上一比較易懂的解说 小样例 1计算next 2计算nextval 代码 有关字符串的基本知识 串(string或字符串)是由零个或多个字符组成的有限序列,一般记为 当中s是串的名,用单引號括起来的字符序列是串的值:ai(1<=i<=n)能够是字母.数值或其它字符.串中字符的数组 n称为串的长度.零个字符的串称为空串,它的长度为0 串中随意个连续的字符组成的子序列称为该串的子串. 包括子

字符串匹配与KMP算法笔记

>>字符串匹配问题 字符串匹配问题即在匹配串中寻找模式串是否出现, 首先想到的是使用暴力破解,也就是Brute Force(BF或蛮力搜索) 算法,将匹配串和模式串左对齐,然后从左向右一个一个进行比较, 如果不成功则模式串向右移动一个单位,直到匹配成功或者到达匹配串最后仍然不成功,返回失败. 很明显,这种算法有很多的地方可以优化,假设要搜索的串为S,长度为n,要匹配的串为M,长度为m,时间复杂度为O(nm). >>KMP算法 Knuth-Morris-Pratt算法以三个发明者命名

字符串匹配的KMP算法(转)

字符串匹配是计算机的基本任务之一. 举例来说,有一个字符串"BBC ABCDAB ABCDABCDABDE",我想知道,里面是否包含另一个字符串"ABCDABD"? 许多算法可以完成这个任务,Knuth-Morris-Pratt算法(简称KMP)是最常用的之一.它以三个发明者命名,起头的那个K就是著名科学家Donald Knuth. 这种算法不太容易理解,网上有很多解释,但读起来都很费劲.直到读到Jake Boxer的文章,我才真正理解这种算法.下面,我用自己的语言

字符串匹配的KMP算法(转载)

字符串匹配是计算机的基本任务之一. 举例来说,有一个字符串"BBC ABCDAB ABCDABCDABDE",我想知道,里面是否包含另一个字符串"ABCDABD"? 许多算法可以完成这个任务,Knuth-Morris-Pratt算法(简称KMP)是最常用的之一.它以三个发明者命名,起头的那个K就是著名科学家Donald Knuth. 这种算法不太容易理解,网上有很多解释,但读起来都很费劲.直到读到Jake Boxer的文章,我才真正理解这种算法.下面,我用自己的语言

[转] 字符串匹配的KMP算法

字符串匹配是计算机的基本任务之一. 举例来说,有一个字符串"BBC ABCDAB ABCDABCDABDE",我想知道,里面是否包含另一个字符串"ABCDABD"? 许多算法可以完成这个任务,Knuth-Morris-Pratt算法(简称KMP)是最常用的之一.它以三个发明者命名,起头的那个K就是著名科学家Donald Knuth. 这种算法不太容易理解,网上有很多解释,但读起来都很费劲.直到读到Jake Boxer的文章,我才真正理解这种算法.下面,我用自己的语言

字符串匹配之KMP算法

1.前言: leetcode上的28. Implement strStr()就是一个字符串匹配问题.字符串匹配是计算机的基本任务之一.所以接下来的两篇日志,都对相关的算法进行总结. 2.暴力求解算法 如果用暴力匹配的思路,并假设现在文本串S匹配到 i 位置,模式串P匹配到 j 位置,则有: 如果当前字符匹配成功(即S[i] == P[j]),则i++,j++,继续匹配下一个字符: 如果失配(即S[i]! = P[j]),令i = i - (j - 1),j = 0.相当于每次匹配失败时,i 回溯

字符串匹配暴力算法 与 字符串匹配的KMP算法

声明:先看一下阮一峰的网络日志关于字符串的KMP算法的讲解.本文图片均引用于这篇日志. 在先前的笔试中遇到了关于字符串匹配的问题,一时脑袋卡壳没写好算法.现在就来分析分析 暴力算法和KMP算法各自原理,以及代码实现,之间差异,并且总结一下好算法的一般思路. =========================================================================== 各自原理: 暴力算法: 1. 我们把长的字符串做为一个文本字符串,命名为strText,把

字符串匹配的KMP算法(转)

转载:http://kb.cnblogs.com/page/176818/ 字符串匹配是计算机的基本任务之一. 举例来说,有一个字符串"BBC ABCDAB ABCDABCDABDE",我想知道,里面是否包含另一个字符串"ABCDABD"? 许多算法可以完成这个任务,Knuth-Morris-Pratt算法(简称KMP)是最常用的之一.它以三个发明者命名,起头的那个K就是著名科学家Donald Knuth. 这种算法不太容易理解,网上有很多解释,但读起来都很费劲.直