1. 程式人生 > 實用技巧 >KMP演算法模板

KMP演算法模板

概述

模板出自kuangbin的部落格

典型應用:

給你兩個字串,尋找其中一個字串是否包含另一個字串,如果包含,返回包含的起始位置。

(1) 標頭檔案

1 #include <bits/stdc++.h>
2 using namespace std;
3 const int N = 1e5+10;
4 int Next[N];
5 char S[N],T[N];   // S:主串  T:模式串
6 int slen,tlen;

(2) getNext()函式

 1 void getNext()
 2 {
 3     int j,k;
 4     j = 0;  k = -1
; Next[0] = -1; 5 while(j < tlen) 6 { 7 if(k == -1 || T[j] == T[k]) 8 Next[++j] = ++k; 9 else 10 k = Next[k]; 11 } 12 }

(3) 返回模式串T在主串S中首次出現的位置

 1 // 返回模式串T在主串S中首次出現的位置
 2 // 返回的位置是從0開始的
 3 int KMP_Index()
 4 {
 5     int i = 0,j = 0;
 6     getNext();
7 8 while(i < slen && j < tlen) 9 { 10 if(j == -1 || S[i] == T[j]) 11 { 12 i++; j++; 13 } 14 else 15 j = Next[j]; 16 } 17 if(j == tlen) 18 return i-tlen; 19 else 20 return -1; 21 }

(4) 返回模式串在主串S中出現的次數

 1 int KMP_Count()
 2 {
 3     int ans = 0;
 4     int i,j = 0;
 5 
 6     if(slen == 1 && tlen == 1)
 7     {
 8         if(S[0] == T[0])
 9             return 1;
10         else 
11             return 0;
12     }
13     getNext();
14     for(i = 0;i < slen;i++)
15     {
16         while(j > 0 && S[i] != T[j])
17             j = Next[j];
18         if(S[i] == T[j])
19             j++;
20         if(j == tlen)
21         {
22             ans++;
23             j = Next[j];
24         }
25     }
26     return ans;
27 }

(5) 全家福

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 /***************KMP***************/
 5 const int N = 1e5+10;
 6 int Next[N];
 7 char S[N],T[N];   // S:主串  T:模式串
 8 int slen,tlen;
 9 
10 void getNext()
11 {
12     int j,k;
13     j = 0;  k = -1; Next[0] = -1;
14     while(j < tlen)
15     {
16         if(k == -1 || T[j] == T[k])
17             Next[++j] = ++k;
18         else 
19             k = Next[k];
20     }
21 }
22 
23 // 返回模式串T在主串S中首次出現的位置
24 // 返回的位置是從0開始的
25 int KMP_Index()
26 {
27     int i = 0,j = 0;
28     getNext();
29 
30     while(i < slen && j < tlen)
31     {
32         if(j == -1 && S[i] == T[j])
33         {
34             i++;    j++;
35         }
36         else 
37             j = Next[j];
38     }
39     if(j == tlen)
40         return i-tlen;
41     else 
42         return -1;
43 }
44 
45 // 返回模式串在主串S中出現的次數
46 int KMP_Count()
47 {
48     int ans = 0;
49     int i,j = 0;
50 
51     if(slen == 1 && tlen == 1)
52     {
53         if(S[0] == T[0])
54             return 1;
55         else 
56             return 0;
57     }
58     getNext();
59     for(i = 0;i < slen;i++)
60     {
61         while(j > 0 && S[i] != T[j])
62             j = Next[j];
63         if(S[i] == T[j])
64             j++;
65         if(j == tlen)
66         {
67             ans++;
68             j = Next[j];
69         }
70     }
71     return ans;
72 }
73 /***************END***************/
74 
75 int main()
76 {
77     int TT;
78     cin >> TT;
79     while(TT--)
80     {
81         cin >> S >> T;
82         slen = strlen(S);
83         tlen = strlen(T);
84         cout << "模式串T在主串中首次出現的位置是: " << KMP_Index() << endl;
85         cout << "模式串T在主串S中出現的次數為: " << KMP_Count() << endl;
86     }
87     return 0;
88 }
View Code

(6) 補充

KMP的優化

 1 void getNext()
 2 {
 3     int j,k;
 4     j = 0,k = -1,Next[0] = -1;
 5     while(j < tlen)
 6     {
 7         if(k == -1 || T[j] == T[k])
 8         {
 9             j++,k++;
10             if(T[j] == T[k])
11                 Next[j] = Next[k];   // 直接走到下一個不相等的地方
12             else 
13                 Next[j] = k;
14         }
15         else 
16             k = Next[k];
17     }
18 }

Next[]陣列求迴圈節
性質:

  • len-next[i]為此字串的最小迴圈節(i為字串的結尾)
  • 另外如果len%(len-next[i])==0,此字串的最小週期就為len/(len-next[i])
  • 如果len%(len-next[i]) != 0 則沒有迴圈節???(小聲逼逼)