<?php function bf($s,$t){ $i=0; $j=0; $k; while($i<strlen($s) && $j<strlen($t)){ if($s[$i] == $t[$j]){ $i++; $j++; }else{ $i = $i - $j + 1; $j = 0;; } } if($j >= strlen($t)) $k = $i - strlen($t); else $k = -1; return $k; } $str1 = "abaabcabclkjlkff"; $str2 = "abc"; echo bf($str1,$str2); ?>
最壞狀況的時間複雜度O(m*n)。m爲模式串長度。n爲目標串長度。php
<?php function GetNext($t,&$next){ $j = 0; $k = -1; $next[0] = -1; while($j<strlen($t)){ if($k==-1||$t[$j] == $t[$k]){ $j++; $k++; $next[$j]=$k; } else $k = $next[$k]; } // var_dump($next); } function KMPIndex($s,$t){ $i = 0; $j = 0; $v; $next = []; GetNext($t,$next); // var_dump($next); while($i<strlen($s) && $j<strlen($t)){ if($j==-1 || $s[$i]==$t[$j]){ $i++; $j++; }else{ $j = $next[$j]; } } if($j>=strlen($t)) $v = $i - strlen($t); else $v = -1; return $v; } $s="ababcabcacbab"; $t="abcac"; $k; $k = KMPIndex($s,$t); echo $k; ?>
時間複雜度爲O(m+n)。m爲模式串長度。n爲目標串長度。
算法簡單記憶分爲兩步:1.模式串掃描,生成next數組,O(m)。2.主串掃描,匹配,O(n)。
KMP算法對BF算法的回溯問題進行了改進,在整個匹配過程當中對主串僅需從頭到尾掃描一遍。java
php函數參數傳遞。在定義函數時在參數前加上'&'改成引傳遞。通常狀況爲值傳遞,對象除外。算法
php在字符串索引某個字符。若包含中文字符須要另行處理。js能夠經過"[]"直接索引。java用charat函數。數組
BM算法。函數
看一個生成next數組的簡單例子。
考慮模式串t="abab",觀察一下next數組的生成過程。指針
初始化。j=0 k=-1 next[0]=-1code
第一趟。j=1 k=0 next[1]=0對象
第二趟。k=next[0]=-1索引
第三趟。j=2 k=0 next[2]=0字符串
第四趟。匹配。j=3 k=1 next[3]=1
第五趟。匹配。j=4 k=2 next[4]=2
這裏首先能夠注意到在第六步中j=4,而實際在咱們的模式串"abab"中4這個下標已經越界了,嗯嗯,不要着急,咱們先來看看在每一趟循環中到底作了什麼。
if($k==-1||$t[$j] == $t[$k]){ $j++; $k++; $next[$j]=$k; } else $k = $next[$k];
代碼不過5行,一個if...else...的判斷語句。假設看的同窗已經在其餘地方看過這裏先後綴的原理了。
若是k=-1或t[j]=t[k],j++,k++,next[j]=k。
這裏的k=-1暫時不考慮他的做用,那麼就是若是主串(模式串)與子串中的字符匹配,則主串指針向後一位,子串指針向後一位,給next數組賦值。
不然k=next[k]。不然向前移動子串指針。這裏也是根據next數組移動子串指針而且須要注意抽象出子串的概念。
因此在第六步中匹配成功之後主串子串移動,在這以後已經跳出循環了。而實際上next[4]在目標串中匹配是用不到的。
嗯。。要記住是先嚐試匹配,成功後在向後移動指針,不匹配則重置指針。
這裏的k=-1能夠理解爲當首位不匹配時移動指針的一個條件。
緊接着能夠思考模式串"abcab","abcabd","ababab"等next數組的生成過程。理解kmp的重點在於next數組是如何生成的。