字串匹配問題:給定兩個字串s(主串)和t(模式串),假設n=strlen(s) > strlen(t)=m,判斷主串s中是否包含模式t,且返回t在s中所在的起始位置。這裡為簡單起見,若s包含t,則只返回第乙個t所在的位置。
一般的蠻力法如下:
蠻力法在遇到不匹配時,j每次都要回到t的起點,從新開始匹配,這樣來看效率就比較低,蠻力法的時間複雜度是o(n*m)。
思想:盡量利用
已經部分匹配的結果資訊,盡量讓
i 不回溯,加快模式串t的滑動速度。
先舉個啟發性的例子,然後引出理論。例子:
在上一趟s和t匹配結果的基礎上,如果知道t本身的結構資訊,那麼第2、4、5趟的步驟其實是可以省略的,且i可以不用回溯(i不回溯待會兒再來直觀理解)。
1.1、模式串t中的資訊
抓住 部分匹配時的兩個特徵:
如上圖所示,假設s[i]和t[j]不相等後,從t的第k個位置開始和s中的第i個位置比較,那麼:
(1)從圖的後半部分可得:
(2)從圖的後前部分可得:
所以,兩式聯立可得:
所以,由上面的推理可知,只要提前知道模式串t本身的結構資訊,就可以由j計算出k,即下一回t的匹配起點。另外,(3)式可能存在多種不同長度的首尾相等的可能,那麼在這樣的情況下,肯定是k越大越好,這樣一方面可以減少再次匹配的字元數量;另一方面,t向右移動的位置相當s而言也是最慢的,這樣也不會錯過各種匹配的情況。比如:
令k = next[ j ],則:
計算next[j]的方法:
由模式t的字首函式定義易知,next[1]=0,假設已經計算出next[1],next[2],…,next[j],如何計算next[j+1]呢?設k=next[j],則已有:
此時,比較tk和tj,可能出現兩種情況:
(1)tk=tj:說明t1 … tk-1 tk=tj-k+1 … tj-1 tj,由字首函式定義,next[j+1]=k+1;
(2)tk≠tj:此時要找出t1 … tj-1的字尾中第2大真字首,顯然,這個第2大的真字首就是next[next[j]]=next[k]。
再比較tnext[k]和
tj,此時仍會出現兩種情況,當
tnext[k]=tj時,與情況(1)類似,next[j]=next[k]+1;當
tnext[k]≠tj時,與情況(2)類似,再找t1 … tj-1的字尾中第3大真字首。重複執行上述步驟,直到找到t1 … tj-1的字尾中的最大真字首,或確定t1 … tj-1的字尾中不存在真字首,此時,next[j+1]=1。
求next陣列**:
void getnext(char t, int next)
else
k = next[k]; //往前找
}}
kmp中的核心就是求next陣列,之後就沒什麼關鍵的了。kmp的時間複雜度為o(n+m),當n>>m時,時間複雜度是o(n)。完整**如下:
int callen(char *p) //計算字元陣列長度
return count;
}void getnext(char t, int next)
else
k = next[k]; //往前找 }}
#includeusing namespace std;
#define str_len 52
int main(int argc, char* argv)
getnext(t, next);
while (s[i] && t[j]) //判斷字串是否結束
else //將t向右滑動
}} if (t[j] == '\0')
cout << "找到目標子串,從s中的第" << i - t[0] << "個位置開始!" << endl;
else
cout << "沒有匹配的目標子串!" << endl;
system("pause");
return 0;
}
字串匹配問題 KMP匹配演算法
基本思想 字串匹配問題 在文字串中尋找是否有與模式串相同的子串 在字串匹配時,暴力匹配忽略了如果模式串開頭與中間有重複部分,在將模式串的後面的重複部分匹配後,無法繼續匹配的話,此時將模式串開頭實際上也已經被匹配了,可以直接從開頭重複部分之後開始匹配 這裡引入了乙個部分匹配值表,每個與模式串的字元對應...
字串匹配問題 KMP演算法
kmp演算法 kmp是解字串匹配這類題目的演算法,又稱 看毛片 演算法。如下圖,給定乙個長度為n的文字,給定乙個長度為m 的字串,求該字串在給定文字的中出現的次數。kmp就是解決這一類題目的。i 1 zzkzzzkzzzkzkkkz zzkzzkzzkzzk j 1繼續考慮上面的問題。首先我相信每個...
KMP演算法 字串匹配問題
給定倆個字串str和match,長度分別為n和m。實現乙個演算法,如果字串str中含有字串match,則返回match在str中的開始位置,不含有則返回 1 str acbc match bc 返回2.str acbc match bcc 返回 1.我們知道在match中a區域與b區域是匹配的,所以...