数据结构-字符串(KMP)

要求:

对于两个串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;
}

猜你喜欢

转载自blog.csdn.net/weixin_62651190/article/details/129773407