題目連結:http://acm.hdu.edu.cn/showproblem.php?pid=1841
表示這個題目做起來還是有點意思的
首先分析一下解這個題目要考慮的兩種情況
1、一個串在另外一個串中,那麼結果就是兩個串中長度長的哪一個
2、一個串的頭部是另外一個串的尾部,這裡分兩種情況(每個串都有一頭一尾嘛)
明白上面兩點之後開始用KMP解題
首先直觀的普通解法是兩個串相互前後拼接一次,然後求出next值,最後一個位置的next值,也就是next[len1+len2]
就是兩個串最長頭尾公用部分(由於後面要討論串內含項目關聯性,所以這裡不考慮next[len1+len2]大於位置在前面那個串
的長度
這個完成之後就是判斷有沒有內含項目關聯性了,其實這個也簡單,就是短串在長串裡面求匹配嘛,對短串求一次next
然後在長串裡面匹配一下,看看能否找到匹配就OK了嘛,這樣做完全可以,而且複雜度也不高,能通過這個題目
但是這裡僅僅要找短串是否在長串裡面出現過,如果直接重新求next值,再求匹配,那麼先前求的兩個串拼接起
來的串的next值就木有用上,那麼怎麼利用原有的兩個拼接串來判斷一個串在另外一個串中是否有匹配呢,其實
很簡單了,就是判斷next[len1*2](len1<len2)之後的next值,如果有next[i]>=len1的那麼說明在後面的串部分的i
位置存在一個長度大於等於len1的在i前面的部分和整個串的首碼部分相等,好了,找到了!
其實這樣做只是對KMP有一定理解,其實這個題目還是很卡常數的!
#include <iostream>#include <string.h>#include <stdio.h>using namespace std;#define maxn 1000010#define MIN(a,b) (a<b?a:b)#define MAX(a,b) (a>b?a:b)char str[maxn],rec[maxn],temp[maxn*2];int next[maxn*2];int get_next(){ int i=0,j=-1; next[0]=-1; while(temp[i]) { if(j==-1 || temp[i]==temp[j]) { i++,j++; next[i]=j; } else j=next[j]; } return 0;}bool find_ans(int len1,int len2,int len){ for(int i=len1*2;i<=len;i++) if(next[i]>=len1) return 1; return 0;}int main(){ int t; int len1,len2,len,ans; scanf("%d",&t); while(t--) { scanf("%s%s",str,rec); len1=strlen(str); len2=strlen(rec); len=len1+len2; ans=len; strcpy(temp,str); strcpy(temp+len1,rec); get_next(); ans=len-next[len];// 這裡不需要做特殊判斷,如果兩個串有內含項目關聯性後面會檢測出來 if(len1 <=len2) { if(find_ans(len1,len2,len)) { printf("%d\n",MAX(len1,len2)); continue; } } strcpy(temp,rec); strcpy(temp+len2,str); get_next(); if(len2<=len1) { if(find_ans(len2,len1,len)) { printf("%d\n",MAX(len1,len2)); continue; } } ans=MIN(ans,len-next[len]); printf("%d\n",ans); } return 0;}