hdu 2594(扩展kmp算法+kmp算法的两种解法)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_39562952/article/details/82222137

思路:题目意思很好懂,就是求s1的前缀和s2的后缀的最长公共长度;下面两种解法

1.把s1当成字串,s2当成母串,问题就变成了典型的扩展kmp算法问题,只不过要注意,扩展kmp求的ex[i]代表s2[i...len-1]和s1 最长的公共前缀的长度 ,也就是说ex[i]只是s2后缀的前缀字串,而题目要求的是s2的后缀,所以只有当ex[i]+i==s2_len的时候才是正确的答案;

 2.把两个字串拼接一下,问题就变成了求s前缀和后缀的最长公共长度,也就是kmp算法中next数组,但是仍然需要注意的是,next数组求得的数据,前缀有可能包含了s2,后缀有可能包含了s1,所以答案必须是小于其中两者小的的长度,也就是原本应该输出next的最后一个数据,而现在应该是对next的不断进行递归,直到小于其中两者小的的长度;

如果对kmp算法和扩展kmp算法有所疑惑的读者,可以参考以下两篇大牛的文章:

扩展kmp算法:

https://segmentfault.com/a/1190000008663857

kmp算法:

https://blog.csdn.net/v_july_v/article/details/7041827

kmp算法的ac代码:

#include <stdio.h>
#include <iostream>
#include<string>
#include<string.h>
#include<algorithm>
#include<math.h>
#define maxx 100000+10
using namespace std;
int nex[maxx];
void getnext(char *s)
{
    int slen = strlen(s);
    int j = 0;
    nex[0] = -1;
    int k = -1;
    while (j < slen)
    {
        if (k == -1 || s[k] == s[j])
        {
            k++, j++;

            nex[j] = k;
        }
        else
            k = nex[k];
    }
}

int main()
{
    char s1[maxx], s2[maxx];
    while (scanf("%s%s", s1, s2) != EOF)
    {
        int s1len = strlen(s1);
        int s2len = strlen(s2);
        strcat(s1, s2);
        getnext(s1);
        int ans = nex[strlen(s1)];
        while (ans > s1len || ans > s2len)
        {
            ans = nex[ans];
        }
        if (ans == 0 || ans == -1)
        {
            printf("0\n");
        }
        else
        {
            s1[ans] = 0;
            printf("%s %d\n", s1, ans);
        }
    }

    return 0;
}

扩展kmp的ac代码:

扫描二维码关注公众号,回复: 3927710 查看本文章
#include <stdio.h>
#include <iostream>
#include<string>
#include<string.h>
#include<algorithm>
#include<math.h>

using namespace std;
const int maxn = 100010;   //字符串长度最大值
int nex[maxn], ex[maxn]; //ex数组即为extend数组

//预处理计算next数组

void GETNEXT(char *str)

{

	int i = 0, j, po, len = strlen(str);

	nex[0] = len;//初始化next[0]

	while (str[i] == str[i + 1] && i + 1 < len)//计算next[1]

		i++;

	nex[1] = i;

	po = 1;//初始化po的位置

	for (i = 2; i < len; i++)

	{

		if (nex[i - po] + i < nex[po] + po)//第一种情况,可以直接得到next[i]的值

			nex[i] = nex[i - po];

		else//第二种情况,要继续匹配才能得到next[i]的值

		{

			j = nex[po] + po - i;

			if (j < 0)j = 0;//如果i>po+next[po],则要从头开始匹配

			while (i + j < len&&str[j] == str[j + i])//计算next[i]

				j++;

			nex[i] = j;

			po = i;//更新po的位置

		}

	}

}

//计算extend数组

void EXKMP(char *s1, char *s2)

{

	int i = 0, j, po, len = strlen(s1), l2 = strlen(s2);

	GETNEXT(s2);//计算子串的next数组

	while (s1[i] == s2[i] && i < l2&&i < len)//计算ex[0]

		i++;

	ex[0] = i;

	po = 0;//初始化po的位置

	for (i = 1; i < len; i++)

	{

		if (nex[i - po] + i < ex[po] + po)//第一种情况,直接可以得到ex[i]的值

			ex[i] = nex[i - po];

		else//第二种情况,要继续匹配才能得到ex[i]的值

		{

			j = ex[po] + po - i;

			if (j < 0)j = 0;//如果i>ex[po]+po则要从头开始匹配

			while (i + j < len&&j < l2&&s1[j + i] == s2[j])//计算ex[i]

				j++;

			ex[i] = j;

			po = i;//更新po的位置

		}

	}

}
int main()
{
	char s1[maxn], s2[maxn];
	while (~scanf("%s%s", s1, s2))
	{
		EXKMP(s2, s1);
		int len = strlen(s2);
		int maxx= 0;
		int maxx_i = 0;
		int flag = 0;
		for (int i = 0; i < len; i++)
		{
			if (ex[i] > maxx && ex[i] + i == len)//ex[i]代表s2[i...len-1]和s1 最长的公共前缀的长度 
			{
				maxx = ex[i];
				maxx_i = i;
			}
		}
		if (maxx)
		{
			printf("%s %d\n", s2 + maxx_i, maxx);
		}
		else
			puts("0");
	}

	return 0;
}

     

猜你喜欢

转载自blog.csdn.net/qq_39562952/article/details/82222137