个人觉得,KMP算法中,讲得最容易懂的是Matrix67那个版本:http://www.matrix67.com/blog/archives/115/
这道题的意思是,给两个字符串a和b,问a和b是否可以连接,求连接后长度最短的,在最短的条件下,再取字典序最小的。比如样例中的asdf和sdfg,可以连接成asdfg和sdfgasdf,明显前者才是符合要求的答案。
要找长度最短的,自然是有两种连接方式,一是a在前b在后,二是b在前a在后。a在前时,拿b去匹配a,求出把a完全匹配完后,b达到的位置即可。比如asdf和sdfg,把a匹配完,即sdf匹配了,返回的是g这个位置。把两种情况都计算一下,匹配得字符越多的肯定越优,因为可以把两者连起来后更短。若两种情况得到的长度相同,则比较a和b的字典序。
同时要注意asdf和sd这种情况,根据题意,这个连起来的答案是asdfsd,而不是asdf。即连接时,某串不能嵌入到另一串中间。故匹配的时候(假设b去匹配a),满足题意的应该是a匹配完了,但b还没完,或者a和b都匹配完了(比如asdf和sdf,答案是asdf)
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define SIZE 100010 int next[SIZE]; char a[SIZE],b[SIZE]; void getNext(char *p) { next[0] = -1; int k = -1; int len = (int)strlen(p); for(int i=1; i<len; i++) { while(k > -1 && p[k+1] != p[i]) k = next[k]; if(p[k+1] == p[i]) ++k; next[i] = k; } } int KMP(char *s,char *p) { getNext(p); int lenp = (int)strlen(p); int lens = (int)strlen(s); int k = -1,i = 0; for(i=0; i<lens && k+1<lenp; i++) { while(k > -1 && p[k+1] != s[i]) k = next[k]; if(p[k+1] == s[i]) ++k; } if(k +1 < lenp || (k+1 == lenp && i == lens)) return k+1; return 0; } int main() { while(~scanf("%s%s",a,b)) { int la = KMP(a,b); int lb = KMP(b,a); if(la > lb || (la == lb && strcmp(a,b) < 0)) { printf("%s",a); printf("%s",b+la); } else { printf("%s",b); printf("%s",a+lb); } puts(""); } }