DS串应用--KMP算法

186 阅读2分钟

​持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第26天,点击查看活动详情

题目描述

学习KMP算法,给出主串和模式串,求模式串在主串的位置

输入

第一个输入t,表示有t个实例

第二行输入第1个实例的主串,第三行输入第1个实例的模式串

以此类推

输出

第一行输出第1个实例的模式串的next值

第二行输出第1个实例的匹配位置,位置从1开始计算,如果匹配成功输出位置,匹配失败输出0

以此类推

输入样例1

3
qwertyuiop
tyu
aabbccdd
ccc
aaaabababac
abac

输出样例1

-1 0 0
5
-1 0 1
0
-1 0 0 1
8

提示

为什么next值和课本的不一样???

思路分析

KMP确实NB,用KMP查找子串的位置首先要求出子串的对应的next值,而求解next值的过程本身就是运用KMP算法的过程。

next值似乎有两种模样,一种是从下标0开始的,next起始值为-1和0,另一种是从下标1开始的,next的起始值为0和1。

我课上学的是下标从1开始的,next【0】存的是子串的长度,下一个next值需要根据前一个next值来确定,首先判断当前字符的前面所组成的字符串的前后缀(前一个字符和第一个字符)是否是相同的字符,如果相同,那么当前字符的next值为前一个next值+1,如果不同,继续比较前一个字符和前一个next值所对应的字符是否相同,如果都不相同,那么next值为1。

AC代码

#include <bits/stdc++.h>

using namespace std;

int FindNext(string &str, int *next) {
    next[0] = str.size();
    next[1] = 0;
    int i = 2, j = 0;
    while (i <= next[0]) {
        if (j == 0 || str[i - 2] == str[j-1]) {
            next[i] = j + 1;
            i++;
            j = next[i - 1];
        } else j = next[j];
        
    }
	return 0;
}

int KMP(string &master, string &son, int *next) {
    int i = 1, j = 1;
    while (i<=master.size() &&j<=son.size()) {
        if (j == 0 || master[i - 1] == son[j - 1]) {
            ++i;
            ++j;
        } else j = next[j];
    }
    if (j > next[0])return i - next[0];
    return 0;
}

int main() {
    int t;
    cin >> t;
    while (t--) {
        string son, master;
        cin >> master >> son;
        int next[son.size() + 1];
        FindNext(son, next);
        for (int i = 1; i <= son.size(); i++)
            cout << next[i]-1 << ' ';
        cout << endl;
        cout << KMP(master, son, next) << endl;
    }
}