看了算法的大致步骤,然后自己一一证明了每一步的正确性,注释里写了一些理解。
这也不是新鲜的做法,只是感觉这个程序非常精巧,反复地使用数学归纳法。
让我感觉很新鲜。
1 /* 2 next[i]存放:match[i]处失配,orig在对应位置将要匹配的值 3 按照KMP的思想, 4 即是1到i-1子串中最长相同前后缀的前缀最后一项的后一项 5 且这一项和match[i]不同 6 7 若不存在同缀子串但是第一项与i项不同,值为1。 8 若不存在同缀子串且第一项与i项相同,值为0,即将j向后移动一个位置。 9 */ 10 #include<stdio.h> 11 int main(void) 12 { 13 char orig[100],match[100]; 14 int nexterval[100],next[100],lengthOrig,lengthMatch; 15 for(lengthOrig=1;;lengthOrig++){ 16 char ch; 17 scanf("%c",&ch); 18 if(ch==‘\n‘||ch==‘ ‘){ 19 lengthOrig--; 20 break; 21 } 22 orig[lengthOrig]=ch; 23 } 24 for(lengthMatch=1;;lengthMatch++){ 25 char ch; 26 scanf("%c",&ch); 27 if(ch==‘\n‘||ch==‘ ‘){ 28 lengthMatch--; 29 break; 30 } 31 match[lengthMatch]=ch; 32 } 33 next[1]=0; 34 next[2]=1; 35 for(int i=3;i<=lengthMatch+1;i++){//next中存储若i位不匹配则将要匹配的对象 36 int k=i-1; //即为 1到i-1中最长前缀最后一项的后一个数 37 while(1){ 38 if(k==1){ 39 next[i]=1; 40 break; 41 } 42 if(match[i-1]==match[next[k]]){ 43 next[i]=next[k]+1; 44 break; 45 } 46 k=next[k];//若不能延长形成子串next[k]+1 47 } //而且还存在子串m,那这个子串一定是前一子串的子串 48 } 49 for(int i=2;i<=lengthMatch+1;i++){//若i!=0,match[next[i]]与match[i]一定不同 50 if(match[i]==match[next[i]])// 若match[i]==match[next[i]] 51 next[i]=next[next[i]];// 已经有match[next[i]]!=match[next[next[i]]] 52 }// 一定有match[i]!=match[next[next[i]]] 53 int i=1,j=1,total=0; 54 while(1){//while结束时i前面的项已经和j前面的匹配,且之前的所有匹配已经尝试过了 55 if(i==lengthMatch+1){ 56 ++total; 57 i=next[i]; 58 continue; 59 }//i-1到头即成功匹配一次 60 if(j==lengthOrig+1) break; 61 //当j-1已经到头 i-1尚未到头时由于orig的长度限制已经不能匹配了 62 if(i==0){ 63 ++j,++i; 64 continue; 65 }//第一项配不上 同时向后考虑一位 66 if(match[i]==orig[j]) ++i,++j; 67 else i=next[i]; 68 } 69 printf("They are match for %d times.",total); 70 }
原文地址:https://www.cnblogs.com/luozhonghao/p/9032723.html
时间: 2024-10-15 04:56:53