然後說說我刷題之路遇到的第二題吧:《PID328/自然地謎語》。
5月13號中午,複習了string類後,用str.compare()函數很快搞定了這道題,哈哈,不過提交後只得了80分,顯示TLE,百度:超出時間限制。看了一下最後兩個測評超時了。。完全沒接觸過超時啊,這可怎麼改。看了一下評論,貌似必須用一個KMP算法。。。艹,學!看不懂有木有。。。於是Google了好幾個版本的教程,下到手機上,不斷地看不斷地研究……(順便認識了一個BF算法,複習了指針一堆東西,引用等等。。好吧,我承認我TM快把去年學的東西忘光了。。。)
KMP學習文章一:http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html
KMP學習文章二:http://www.cnblogs.com/dolphin0520/archive/2011/08/24/2151846.html
KMP學習文章三:http://www.cnblogs.com/yjiyjige/p/3263858.html
附上BF與KMP練習代碼:
#include <iostream>
#include <cstring>
using namespace std;
int KMPMatch(char *s,char *p);
int BFMatch(char *s, char *p);
void getNext(char *p,int *next);
int main()
{
char s1[11] = {'a','b','a','b','c','a','b','a','b','a'};
char s2[6] = {'a','b','a','b','c'};
cout << BFMatch(s1 , s2) << endl;
cout << KMPMatch(s1 , s2) << endl;
return 0;
}
//BF算法
int BFMatch(char *s , char *p)
{
int i,j;
i=0;
while(i<strlen(s))
{
j=0;
while(s[i]==p[j]&&j<strlen(p))
{
i++;
j++;
}
if(j==strlen(p))
return i-strlen(p);
i = i - j + 1 ; //指針i回溯
}
return -1;
}
//KMP算法
int KMPMatch(char *s,char *p)
{
int next[100];
int i,j;
i=0;
j=0;
getNext(p,next);
while(i<strlen(s))
{
if(j==-1||s[i]==p[j])
{
i++;
j++;
}
else
{
j=next[j]; //消除了指針i的回溯
}
if(j==strlen(p))
return i-j;
}
return -1;
}
void getNext(char *p,int *next)
{
int j,k;
next[0]=-1;
j=0;
k=-1;
while(j<strlen(p)-1)
{
if(k==-1||p[j]==p[k]) //匹配的情況下,p[j]==p[k]
{
j++;
k++;
next[j]=k;
}
else //p[j]!=p[k]
k=next[k];
}
}
5月14號,帶着稍稍能看懂那麼一點的KMP算法,重寫了這一題,提交檢測成果……靠,服務器壞了 - -。
2014年5月16日23:46:25更新:
NND,服務器終於好了,TM一看竟然WA30,大失所望。排查出錯誤後再提交,最後三個測試點超時 - -。再改。又錯。再改。又超時……
無奈了,問隊友曹大神,果然他也WA了幾次,哈哈。不過還是被他分分鐘AC了 - -。看他的代碼,感覺和我的差不多啊。。。鬱悶。改來改去無效。放下不管了。。。
晚上,決定刪了自己的代碼仿着曹大神的重寫,可是,竟然又有兩道超時。。。我可抄的就剩輸入輸出不一樣了。。。換成他的輸出函數,果然AC了。。。然後曹大神告訴我,cin和cout超級慢……(有時可在主函數使用 ios::sync_with_stdio(false);能加快速度)。
額額額,好吧,又漲姿勢了:scanf + printf 要比 cin + cout 運行快。
唉,不管怎麼說,今天終於算是把這道題解決了。看得出來我欠的知識實在太多,需要努力啊。
附上曹大神解此題的源代碼:(很多地方值得我去學習)
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int MAXN = 100010,MAXM = 100010;
char T[MAXN],P[MAXM];
int Next[MAXM],N,M,C;
int Ans[MAXN];
void MakeNext(int M)
{
int i=0,j=-1;
Next[i] = -1;
while(i<M)
{
if(j==-1||P[i]==P[j])Next[++i] = ++j;
else j = Next[j];
}
}
int KMP(int pos,int N,int M)
{
int i = pos, j = 0,ans = 0;
while(i<N){
if(T[i]==P[j]||j==-1)i++,j++;
else j = Next[j];
if(j==M){
Ans[++ans]=i-j+1;
j = Next[j-1];
i--;
}
}
return ans;
}
int main()
{
scanf("%s%s",P,T);
N = strlen(T),M = strlen(P);
MakeNext(M);
int ans=KMP(0,N,M);
if(ans==0)
{
puts("There must be something wrong.");
return 0;
}
printf("%d\n",ans);
for(int i=1;i<=ans;i++)
printf("%d\n",Ans[i]);
return 0;
}