二、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 匹配成功,返回模式串在目標串的...