HDU 1867 A + B for you again KMP题解

本题又是一个典型的KMP应用。

求两个字符串相加的结果,相加的规律是一个字符串的后缀和另一个字符串的前缀相同,就可以合并这个部分。

不过本题的题意不是很清晰,因为没有太明确指出这两个字符串的出现顺序是无关的,只是需要输出合并后长度最短的结果,如果合并后长度一样,那么就按照字典顺序,输出字典顺序在前的字符串。

思路:

1 使用kmp在s2查找s1,那么最终结束的时候next table的值就是s1前缀和s2的后缀相同的最长的长度了。

2 输入两个字符串s1和s2,那么就可以在s2中查找s1,得到长度len1,s1中查找s2,得到长度len2,比较len1和len2的长短,就可以确定输出哪个字符串了。


const int MAX_N = (int)1E5 + 1;
char s1[MAX_N], s2[MAX_N];
int L1, L2, nxt[MAX_N];

void genTbl(char *str, int len)
{
	memset(nxt, 0, sizeof(int) * len);//又一个忘记清零错误
	for (int i = 1, j = 0; i < len; )
	{
		if (str[i] == str[j]) nxt[i++] = ++j;
		else if (j > 0) j = nxt[j-1];
		else i++;//不清零,也可以nxt[i++] = 0;前面写nxt[0] = 0;
	}
}

void getLongestPreSuf(int &j, char *str1, char *str2, int len1, int len2)
{
	genTbl(str1, len1);
	j = 0;
	int i = 0;
	for (; i < len2; )
	{
		if (str2[i] == str1[j]) i++, j++;
		else if (j > 0) j = nxt[j-1];
		else i++;
	}
}

void printStr(char *str1, char *str2, int l1, int l2, int len)
{
	for (int i = 0; i < l1; i++) putchar(str1[i]);
	for (int i = len; i < l2; i++) putchar(str2[i]);
	putchar('\n');
}

int main()
{
	while (scanf("%s", s1) != EOF)
	{
		scanf("%s", s2);
		L1 = strlen(s1);
		L2 = strlen(s2);
		int len1 = 0, len2 = 0;
		getLongestPreSuf(len1, s1, s2, L1, L2);
		getLongestPreSuf(len2, s2, s1, L2, L1);
		if (len1 < len2)
		{
			//printStr(s1, s2, L1, L2, len2);
			printf("%s%s\n", s1, s2+len2);
		}
		else if (len2 < len1)
		{
			//printStr(s2, s1, L2, L1, len1);
			printf("%s%s\n", s2, s1+len1);
		}
		else
		{
			//if (strcmp(s1, s2) < 0) printStr(s1, s2, L1, L2, len2);
			//else printStr(s2, s1, L2, L1, len1);
			if (strcmp(s1, s2) < 0) printf("%s%s\n", s1, s2+len2);
			else printf("%s%s\n", s2, s1+len1);
		}
	}
	return 0;
}


你可能感兴趣的:(HDU 1867 A + B for you again KMP题解)