在Pi中寻找一串数字(可以是生日或者是其他的什么)(KMP算法实现)

目录

在一串字符串中寻找另一串字符串

1.BF的缺陷

2.KMP

1.思路

2.数组next的求法

回归正题:在Pi中寻找一串数字

代码实现

测试样例


在一串字符串中寻找另一串字符串

通常可以采用两种算法,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的定义

  1. 前缀:包含首位字符但不包含末位字符的字符串

  2. 后缀:包含末位字符但不包含首位字符的字符串

  3. next:当主串与模式串不匹配时,模式串回溯的位置

<u>**其值为j前面的子串前缀和后缀重合的字符 </u>

(注:字符串下标从1开始则加1)******

例如

*下标*012345
abaabc
next-100112

表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

  • 13
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值