要求:
对于两个串A和B ,给出一种算法使得能够保证正确地求出最大的L值,使得A串中长为L的前缀与B串中长为L的后缀相等,并分析该算法的复杂度。
分析:
核心思想:两字符串合并之后,仍然满足前缀等于后缀的话,符合next数组定义。
将串s1与串s2合并得到字符串P,通过求串P的前缀与后缀相同的最大长度,得到题解。
求串P的前缀与后缀相同的最大长度进一步转换为在KMP算法中所求的next数组的值
但是要注意调整的是:要求next数组长度是比字符串长度P多一位,next最后一位的值就是最大的L值
在KMP算法中,求next数组是在一次循环中完成,对于每个位置的next值,都是根据前几个已知的值求得,因此其时间复杂度为O(n),空间复杂度也为O(n)
补充:
关于字符串长度范围:若要遍历一个输入的字符串的字符数时如果是0 - n,应该输入时+1(模板串前后缀匹配应该为p[i] = p[j - 1]),若输入字符串的时候没有+1那因为有“\0“,所以(模板串前后匹配应该是p[i -1] = p[j])这样就不会超限。
两种解题方式:
教材:
#include<iostream>
#include <algorithm>
#include <string>
using namespace std;
int* findNext(string P) {
int i, k;
int m = P.length(); // m为模式P的长度
int* next = new int[m]; // 动态存储区开辟整数数组
next[0] = -1;
i = 0; k = -1;
while (i < m ) { // 若写成 i < m 会越界
while (k >= 0 && P[k] != P[i]) // 采用 KMP 找最大首尾子串
k = next[k]; // k 递归地向前找
i++;
k++;
next[i] = k;
}
return next;
}
int main() {
string s1, s2;
cin >> s1 >> s2;
string P = s1 + s2;
int* next = new int[100];
next = findNext(P);
cout << next[P.length()];
另一种:
/*
* .::::.
* .::::::::.
* :::::::::::
* ..:::::::::::'
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ````':. ':::::::::' ::::..
* '.:::::' ':'````..
*/
/*
* @Description:
* @Author: YOLOKY
* @Date: 2023-03-25 21:25:27
* @LastEditors: YOLOKY
* @LastEditTime: 2023-03-25 22:27:29
*/
#include <iostream>
#include <string>
using namespace std;
const int N = 1000010;
int ne[N];
int main()
{
string s1, s2;
cin >> s1 >> s2;
string p = s1 + s2;
int n = p.length();
int i, j;
for (i = 2, j = 0; i <= n ; i ++)
{
while(j && p[i - 1] != p[j]) j = ne[j];//经典回溯
if(p[i - 1] == p[j]) j ++;
ne[i] = j;
}
printf("%d", ne[n]);//输出next中匹配的字符个数
system("pause");
return 0;
}