1. 程式人生 > 其它 >每天學習一點點Day 19:KMP完全解讀看不懂算我輸

每天學習一點點Day 19:KMP完全解讀看不懂算我輸

1. KMP 實際上相對於Boyer Moore演算法來看,實際上只使用了一個啟發性演算法,那就是找公共子串(左邊是以開頭為字首,右邊是以最後一個字元為字尾),通過這個公共子串就可以減少一些不必要的比較.

2. 我覺得大部分人應該也和我一樣一開始最搞不懂的就是shift表怎麼求的吧?

實際上網上很多解釋都沒有把一些事情用白話說清楚, 因為你上來就Next陣列,i,j啊啥的,其實很多小夥伴就蒙了。。。。

那麼我這裡先定義一下,我這個版本的陣列的內容是:

Array[i]: 指的是在一個pattern串裡從0到下標為i的字元(包括Pattern[i]這個字元)形成的字串裡,

最長的公共子串: 這個公共子串指的是以pattern[0]為字首,和以pattern[i]為字尾的字串的最長公共子串

以abcabc為例子

Array[4]=2;

這裡的最長公共子串就是abcab

標黑的部分
實際上等我們把這個計算出來了,接下來就是算在i位置上匹配失敗時應該移動多少距離: 已經匹配成功的字元數-Array[i].

其實就是先算一下公共子串長度,然後利用這個資訊再算實際要怎麼移動!簡單吧?

那麼我們其他地方就不提直接看Array怎麼算吧?

直接上程式碼:

void CalPrepArray(string & pattern, int* Array)
{
    
    int m=pattern.length();
    int *tmp=new int[m];
    Array[
0]=0; if(m==1) { Array[0]=1; return; } int k=0; int i=1; while(i<=m-1) { if(k>=0&&pattern[k]==pattern[i]) { Array[i++]=++k; } else if(k==0&&pattern[k]!=pattern[i]) { Array[i
++]=0; k=0; } else { k=Array[k-1]; } } for(int i=0;i<m;i++) { tmp[i]=Array[i]; } for(int i=0;i<m;i++) { if(i==0||i==1) { Array[i]=1; } else Array[i]=i-tmp[i-1]; cout<<Array[i]<<endl; } delete[] tmp; }

很多人可能理解不了k的含義到底是啥?

其實就是上一次也就是Array[i-1]的結果. 因為我們發現Array[i]的值和Array[i-1]密切相關:

所以就三種情況:

一種是Array[i]=k+1;

這個時候就是