日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【数据结构-查找】2.字符串(逐步演绎过程,超级详解KMP算法)

發布時間:2025/3/20 编程问答 16 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【数据结构-查找】2.字符串(逐步演绎过程,超级详解KMP算法) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

串的定義

串(string)是有0~n個字符組成的有限序列,一般記為
S=′a1a2…an′(n≥0)S = 'a_1a_2…a_n'(n≥0) S=a1?a2?an?(n0)
S 是字符串的名稱,aia_iai? 可以是字母數字或其他字符。

其中,串中任意連續的字符組成的子序列稱為該串的 子串

字符在串中的位置 通常是該字符在序列中的序號

子串在主串中的位置 指的是子串第一個字符在主串中的位置

串的模式匹配

子串的定位操作通常稱之為串的模式匹配,它的目的是要獲取子串在主串的位置。

一般的,我們想到的是一種暴力破解的方法

也就是說,從主串 S 的第 pos 個字符起,與模式串的一個字符比較,若相等,則繼續逐個比較主串和模式的后續字符;否則,從主串的下一個字符起,重新和模式的字符比較,以此類推,直至成功或失敗。

int IndexSubstring(string s, string sub, int pos) {int i = pos;int j = 0;while(i < s.size() && j < sub.size()) {if(s[i]==sub[j]) {i++;j++;} else {i = i - j + 1;j = 0;}}if(j >= sub.size()) return i - sub.size() + 1; // 查找成功else return 0; // 查找失敗 }

但這種暴力破解的算法的最壞時間復雜度為O(mn),m和n分別是主串和模式串的長度。


KMP算法——改進的模式匹配算法

在回顧上面暴力破解的算法,我們可以得到,暴力算法每一次回溯都是回到模式串最初的起點,事實上,這一步是可以改進的。

【KMP算法】利用比較過的信息,i 指針不需要回溯,僅將子串向后滑動一個合適的位置,并從這個位置開始和主串比較,這個合適的位置僅與 子串本身結構有關,與主串無關

【KMP算法】實際上是一種【備忘錄設計模式】,下面通過幾個步驟或許可以讓你了解這個算法的使用。

我們以主串 s='ababcabcacbab',模式串 sub=‘abcac’

1.獲取模式串的 next 數組(備忘錄)

子串前綴后綴前后綴相同的最長
a--0
abab0
abca,abc,bc0
abcaa,ab,abca,ca,bca1
abcaca,ab,abc,abcac,ac,cac,bcac0

所以 模式串sub 的 next數組 為

sabcac
next00010

2.匹配過程

要滿足一個公式:移動位數 = 已經匹配的位數 - 對應的部分匹配值

第一趟:發現 a 與 c 不配

ababcabcacbab
abc

但是前面兩個字符 'ab' 是匹配的,查表可知,最后一個匹配字符 b 對應匹配部分值為 0,按公式,計算 $ 2-0=2 $,所以,模式串向后移動 2 位。

第2趟:模式串向后移動 2 位后,發現 b 與 c 不配

ababcabcacbab
abcac

但是前面兩個字符 'abca' 是匹配的,查表可知,最后一個匹配字符 a 對應匹配部分值為 1 ,按公式,計算 4?1=34-1=34?1=3,所以,模式串向后移動 3 位。

第3趟:模式串向后移動 3 位后,匹配成功

ababcabcacbab
abcac

使用【KMP算法】后,時間復雜度變為了O(m+n)


KMP原理

已知公式:移動位數 = 已經匹配的位數 - 對應的部分匹配值

改為代碼:
move=(j?1)?next[j?1]move = (j -1) - next[j-1] move=(j?1)?next[j?1]
優化公式,如果我們將 next數組 向后挪一位,就不需要 next[j-1] ,只需要直接使用 next[j] 即可

sabcac
next00010
右移-10001

于是上述公式(2)既可以改為
move=(j?1)?next[j]move = (j -1) - next[j] move=(j?1)?next[j]
此時,得到串移動的公式
j=j?move=j?((j?1)?next[j])=next[j]+1j = j - move =j -((j -1) - next[j])=next[j]+1 j=j?move=j?((j?1)?next[j])=next[j]+1
進一步優化,我們可以將右移后是 next數組 總體+1,那么,最后的數組就變成了
j=next[j]j = next[j] j=next[j]

sabcac
next00010
右移-10001
右移+101112

最后一行的意思是,把模式串的第 next[j] 個值,移動 j 這個位置。或者說,從模式串的第 next[j] 個數組開始查找,主串繼續移動即可。

3.使用了改進后的next數組再匹配過程

第一趟:發現 a 與 c 不配

ababcabcacbab
abc

在 c(pos=2) 這個位置匹配失敗,查表得,c 的對應值是 1 ,也就是將模式串的第一個字符 (a) 移到 c(pos=2) 這個位置

第2趟:模式串向后移動 2 位后,發現 b 與 c 不配

ababcabcacbab
abcac

在 c(pos=6) 這個位置匹配失敗,查表得,c 的對應值是 2 ,也就是將模式串的第二個字符 (b) 移到 c(pos=6) 這個位置

第3趟:模式串向后移動 3 位后,匹配成功

ababcabcacbab
abcac

參考代碼

獲取next數組

void getNext(string sub, int next) {int i = 0;int j = 0;next[0] = 0;while(i<sub.size()) {if(j == 0|| s[i]==s[j]){i++;j++;next[i] = j;} else {j = next[j];}} }

【KMP算法】

int Index(string s, string sub, int next[], inr pos) {int i = pos;int j = 0;while(i<s.size()&&j<sub.size()) {if(j==0||s[i]==sub[j]){i++;j++; } else {j = next[j]; // 模式串右移}if(j >= sub.size()) {return i - sub.size() + 1;} eles {return 0;}} }

總結

以上是生活随笔為你收集整理的【数据结构-查找】2.字符串(逐步演绎过程,超级详解KMP算法)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。