想寫一個算法思路(意圖)的系列,從KMP算法開始吧,不講代碼,只講”爲什麼要這麼想,這麼寫“,看網上這麼講的還沒見到,自己想寫的還是必須自己寫啊~
KMP一直看書不明白的,看視頻真的有幫助,老師會自然而然地說出思路而非書上那般生硬。
B站,嚴蔚敏奶奶視頻教程
一、kmp的目標:
1,防止i指針回溯。
需要重新匹配時,其實前面的已經匹配成功,問題可以轉化爲模式串的自比較,從而省去i指針的回溯。
2,讓j指針回溯得儘量少。
模式串的前綴、後綴的最長重複位數可以代表需要跳過幾位。
二、一個實例
一位一位比較時
遇到主串i指針的字符 與 模式串j指針的字符 不匹配時。
-------i
abaabcabbbbb
abaabcac
-------j
發生了i指針回溯,同時產生了已經成功匹配序列的錯位
-i
abaabcabbbbb
-abaabcac
-j
再一位一位比較……
--i
abaabcabbbbb
--abaabcac
--j
---i
abaabcabbbbb
--abaabcac
---j
突破點是已經成功匹配的字符串,錯位後,除了一些特殊情況,必然不能匹配!
那個“特殊情況”就是前綴與後綴的重複,同時,匹配成功的主串、模式串的部分是相等的! 這樣next數組僅僅交給模式串就等於主串、模式串都遵守了!
——回到第一步那裏,接着可以直接進行下一步:j回溯到模式串的b(從第一步的c)。
-------i
abaabcabbbbb
------abaabcac
-------j
三、原理要點
0,明白什麼不用比較,什麼還需比較
1,基於已經成功匹配的字符串(已知匹配成功的位數)
2,i回溯會導致已經匹配成功的串錯位(主串與模式串),如何防止i指針回溯導致的浪費?——除了一些特殊情況,錯位必然不能匹配!
3,特殊情況——只用考慮【已經匹配成功的部分主串(也就是部分模式串!匹配成功的部分代表它們完全一致!)】的錯位是否會有”重複“
4,錯位時,模式串前綴後綴的重複可以避免重新匹配(模式串與模式串——next數組)
5,next數組標記的有關於當前字符前的子串的前綴、後綴的最長重複長度,也就是可以不直接退回j串第一個字符的可以少回溯的重複部分。
四、理解next
教材定義圖引自:https://blog.csdn.net/qq_37969433/article/details/82947411
*注:教材上的”1“是[其他情況],不是[”不匹配時“]
這圖上的精確的數學語言看着就讓人頭疼,不如按着公式試試幾個例子。
這是嚴蔚敏教材P81的next數組值
abaabcac
01122312
驗證公式:我們取第4位的”a“,則這個a的next[4]的值是”k=2“,[1到2-1]=[4-2+1到4-1]即【1到1】=【3到3】即 [a]=[a]。
這也應當是”最長前後綴重複長度“
abaabcac
---2----
驗證公式:我們取第6位的”c“,則這個a的next[6]的值是”k=3“,[1到3-1]=[6-3+1到6-1]即【1到2】=【4到5】即[ab]=[ab]。
這也應當是”最長前後綴重複長度“
abaabcac
-----3--
下面是回溯j指針的實例。
【現在是f比a】同時,在匹配錯誤時跳過多少?
---i
abafbcabbbbb
abaabcac
---2----------------next
回溯至2【現在是f比b了】(j=next[j],就是j賦值當前位置的next數組的值,也就是下一步的位置(已經算好了跳到哪裏))
---i
abafbcabbbbb
--abaabcac
---1-----------------next
回溯至1(回溯到頭都沒有,之前的整串又配不上,GG,真匹配不上了)
這裏發現了又匹配到了f對a,這個涉及”對KMP算法的一種改進“,書上有。
---i
abafbcabbbbb
---abaabcac
---0------------------next
關於前綴後綴放張圖,下圖引自:https://www.cnblogs.com/zhangtianq/p/5839909.html
注意,next[j]內的值不代表j之前的子串前後綴的最大長度,而是“當模式串中第j個字符與主串相應字符‘失配’時,在模式串中需要重新和主串中該字符進行比較的字符的位置”。