字串的模式匹配 KMP演算法筆記

2021-10-25 18:04:39 字數 1860 閱讀 5493

二、kmp演算法

趁自己還記得,留個筆記,不對的地方請指正。

字串的匹配問題指的是在主串s中尋找乙個與模式串p(pattern)完全相同的子串,稱為字串模式匹配

以主串s的第一位字元為起點,每次與模式串p進行逐位的比較。若當前比較的字元相等,則比較下一位,完全相等時返回s此時的比較起點。若當前比較的字元不相等,則s的比較起點向後挪一位,模式串p的比較起點回到最初的位置,進行同樣的比較。

若直到s的比較起點到s的最後乙個字元長度小於p的長度,未出現匹配成功,則匹配失敗。

從brute force的設計思路可以看出,時間複雜度為o(p

.len

gth∗

s.le

ngth

)o( p.length*s.length )

o(p.le

ngth

∗s.l

engt

h)每次向後挪一格的比較效率過低。然而,其實每次匹配失敗的資訊是可以被有效利用的。

kmp演算法的本質就是對字串p進行預處理,排除許多不可能的情況,將逐位比較的形式直接跳轉到可能情況的比較起點,盡可能減少比較次數。

引入函式f

f (j

)=

largest \ k & p_0...p_k=p_...p_j&kf(

j)=else

if(posp==0)

poss++

;else

if(pospreturn-1

;else

return posp-plen;

//返回s子字串與p完全匹配上時在s此時比較起點的座標

}}當字串p和s比較到了p[j+1],說明此時p0…pj在s中能找到完全匹配的位置

如p[j+1]也能夠與s匹配,此時指向p和s的指標右移繼續比較;

如p[j+1]不能夠與s下一位相匹配,

記t1=p0…pk

t2=pj-k…pj

t2在s此時的比較位置前能夠找到完全匹配的地方,我們可以直接移動p,使t1處於移動前t2在s上的位置,跳過了中間所有的不可能情況。

時間複雜度分析

注意到poss是只增不減的,而且在else中巢狀的else語句posp=f[posp-1]+1

每次至少讓posp減少1,因此此語句最多執行o(s.length),其餘的語句都保證了poss的遞增,複雜度也為o(s.length),綜合下來複雜度為o(s.length)

對 f 的初始化

void

failurefunction

(string p)

}

$f 初始化的推導

由p0…pj-1的f[j-1]找出p0…pj-1與p0…pj最長的相同字首和字尾的關係來遞推f [j].

若p[j]=p[i+1],此時f[j]=f[j-1]+1即i+1

若p[j]!=p[i+1], 就必須重新找i使得p[j]=p[i+1],注意到p0…pj-1由f[j-1]確定的字首和字尾是相等的,因此p0…pj-1字首中最長的相同字首和字尾與p0…pj-1字尾中最長的相同字首和字尾也是完全一致的,由此展開迭代 f[i]=i,直到得到滿意的答案或不可能匹配的結論為止。

時間複雜度分析

每次對 i 的重置要麼讓 i=-1或者讓i=i+1(由上一次的迴圈決定),因此i最多累加p.length次,每次i=f [ i ]的迭代至少讓 i 減少1,因此在整個迴圈看來,這個while語句總共最多執行o(p.length)

總時間複雜度:o(s

.len

gth+

p.le

ngth

)o(s.length+p.length)

o(s.le

ngth

+p.l

engt

h)

字串模式匹配KMP演算法

next的值去改變每次匹配的位置 注意 字串的儲存最好用字元陣列,然後用字元輸入的形式,保證正確!利用求模式串的next值來分析遍歷,可以在不改變主串i的值的基礎上,只改變next j 的下標來遍歷 next j include include using namespace std void ge...

字串模式匹配KMP演算法

字串模式匹配指的是,找出特定的模式串在乙個較長的字串中出現的位置。很直觀的可以寫出下面的 來找出模式串在乙個長字串中出現的位置。1 2 樸素的模式匹配演算法 3 功能 字串的模式匹配 4 引數 5 s 目標串 6 p 模式串 7 pos 開發匹配的位置 8 返回值 9 匹配成功,返回模式串在目標串的...

字串模式匹配KMP演算法

字串模式匹配指的是,找出特定的模式串在乙個較長的字串中出現的位置。很直觀的可以寫出下面的 來找出模式串在乙個長字串中出現的位置。1 2 樸素的模式匹配演算法 3 功能 字串的模式匹配 4 引數 5 s 目標串 6 p 模式串 7 pos 開發匹配的位置 8 返回值 9 匹配成功,返回模式串在目標串的...