每天一道LeetCode-----KMP算法查找子串,重新实现strStr()函数
Implement strStr()
原題鏈接Implement strStr()
子串查找,方法很多,可以用string內置的接口find解決,這里主要復習一下kmp算法
kmp算法常用于字符串匹配,相比于傳統方式一個一個查找,當遇到不匹配時從頭開始的土方法,kmp可以有效減少比較次數,遇到不匹配時,不需要從頭開始
判斷abababc中是否存在ababc子串,直觀上是存在的
abababc為源字符串source,ababc為目標字符串target
傳統方式
依次比較source[0]和target[0],source[1]和target[1]…source[4]和target[4]
當比較到source[4]和target[4]時,發現字符a和字符c不相等,此時需要從頭第二個字符開始
比較source[1]和target[0]時就不相等,此時需要從第三個字符開始
0 1 2 3 4 5 6 source下標 a b a b a b c sourcea b a b c target0 1 2 3 4 target下標依次比較source[2]和target[0],source[3]和target[1]…source[6]和target[4]
發現終于相等了,說明有子串存在,但是每次失配后都從下一個字符開始從頭查找,每次都需要將target所有字符都比較一次,效率堪憂啊…
kmp算法
0 1 2 3 4 5 6 source下標 a b a b a b c source a b a b c target 0 1 2 3 4 target下標依次比較source[0]和target[0],source[1]和target[1]…source[4]和target[4]
當比較source[4]和target[4]時不相等,于是…
直接比較source[4]和target[2],發現相等,繼續比較source[5]和target[3]…source[6]和target[4],發現存在子串
在比較時,發現target的前兩個字符ab在第二次開始時根本沒有比較,是直接從第三個字符開始的。
直觀的看,當比較source[4]和target[4]時,source[0 : 3]肯定和target[0 : 3]相等,也就是說比較a和c時前面4個字符abab是匹配的,又因為target[0 : 1]和target[2 : 3]相等,那么和target[2 : 3]匹配的source[2 : 3]肯定也和target[0 : 1]匹配,那么就可以直接將target后移兩位,讓source[2 : 3]匹配target[0 : 1],從target[2]開始比較,也就直接讓source[4]和target[2]比較
所以,在失配時移動target而非source,這就需要對target進行預處理以便在失配時直到該移動多少,kmp將預處理后的數據存放在一個prefix數組中,這里成為前綴數組,首先理解什么是字符串中每個字符的前綴
假設當前字符為target[j],存在i < j滿足target[0 : i] == target[j - i : j],此時target[0 : i]為字符target[j]的前綴,而i + 1為target[j]的前綴個數
比如說ababaca字符串
在對目標字符串預處理時,本質就是計算每個字符的前綴個數,前綴的意思在于,若target[i]的前綴個數是n,那么有target[0 : n - 1] == target[i - n + 1, i],也就是說如果target[i+1]和souce[j]比較時失配,可以直接將target[0 : n - 1]移動到target[i - n + 1, i]的位置,而下次開始直接從target[n]和source[j]開始比較。
對于最開始的那個例子,abababc為源字符串source,ababc為目標字符串target ,匹配之前需要對target進行預處理,得到每個字符對應的前綴個數
接著開始依次比較
0 1 2 3 4 5 6 source下標 a b a b a b c source a b a b c target 0 1 2 3 4 target下標 0 0 1 2 0 前綴個數當比較到失配時,這里source[4] != target[4]導致失配,找到target[4 - 1] 即target[3]的前綴個數2,也就是說target[0 : 1] == target[2 : 3],所以可以直接將target[0 : 1]移動到target[2 : 3]的位置
0 1 2 3 4 5 6 source下標 a b a b a b c sourcea b a b c target 0 1 2 3 4 target下標a b a b c target0 1 2 3 4 target下標0 0 1 2 0 前綴個數下面接著比較target[2]和source[4]即可,這樣,失配時一次性移動了2步,而不需要每次都只移動1步,當字符串很大時,target重復字符過多,前綴個數比較大時,效果更加明顯
代碼如下
總結
以上是生活随笔為你收集整理的每天一道LeetCode-----KMP算法查找子串,重新实现strStr()函数的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: muduo网络库学习(六)缓冲区Buff
- 下一篇: muduo网络库学习(七)用于创建服务器