目录
在一串字符串中寻找另一串字符串
通常可以采用两种算法,BF算法和KMP算法
本题我选择KMP算法求解
好了,在正式开始之前先让我简单介绍一下KMP算法
1.BF的缺陷
提到KMP算法,就不得不提到BF算法了,BF算法通过不断对主串回溯来求解模式串的位置
算法虽然简单易理解,最好的时候时间复杂度为O(m+n)
但是对于如图这样的主串和模式串,其时间复杂度为O(m*n)且有大量的重复操作
图1,图2
2.KMP
这是大佬所不能接受的,于是三位大佬D.E.Knuth,J.H.Morris和V.R.Pratt就研究出了KMP算法
1.思路
KMP通过数组next来实现不对主串回溯,来进行求模式串在主串中的位置
图3
2.数组next的求法
这是目前网上流传最广的版本
图4
那么,让我们一起对其进行研究
了解next的计算,要先明白前缀,后缀,和next的定义
-
前缀:包含首位字符但不包含末位字符的字符串
-
后缀:包含末位字符但不包含首位字符的字符串
-
next:当主串与模式串不匹配时,模式串回溯的位置
<u>**其值为j前面的子串前缀和后缀重合的字符 </u>
(注:字符串下标从1开始则加1)******
例如
*下标* | 0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|---|
a | b | a | a | b | c | |
next | -1 | 0 | 0 | 1 | 1 | 2 |
表1
对于首位next[0]=-1
1 b前面无重复next值为0
2 a前面无重复next值为0
3 a前面有前缀a,后缀a重复next值为1
4 b前面有前缀a,后缀a重复next值为1
5 c前面有前缀ab,后缀ab重复next值为2
转化为代码便是图4
回归正题:在Pi中寻找一串数字
废话不多说
代码实现
#include<iostream>
#include<string>
#include<fstream>
using namespace std;
void get_next(string t, int next[]) {
int i = 0, j = -1;
next[0] = -1;
while (i < (int)t.size()) {
if (j == -1 || t[i] == t[j]) {
next[++i] = ++j;
} else j = next[j];
}
}
int main() {
string s, t;
cout << "请输入你想搜索的数字:";
cin >> t;
int next[t.size() + 1];
get_next(t, next);
ifstream infile;
infile.open("Pi - Dec - Chudnovsky.txt");//由于Pi过大,从文件中读取
infile >> s;
int i = -1, j = -1;
while (i < (int)s.size() && j < (int)t.size()) {
if (j == -1 || s[i] == t[j]) {
i++;
j++;
} else j = next[j];
}
if (j >= (int)t.size()) {
cout << "您所输入的数字在Pi中的第";
cout << i - t.size() + 1;
cout << "位" << "(包括小数点)";
} else {
cout << "很抱歉,您所输入的数据在本程序录入的Pi中不存在";
}
infile.close();//关闭已打开的文件
return 0;
}
测试样例
运用网站程序监测
检测正确,程序运行没错
本人水平有限,如有不足,请指出
End