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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

字符串-kmp

發布時間:2024/4/13 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 字符串-kmp 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

KMP

next

next數組就是一個前綴表(prefix table)。

前綴表有什么作用呢?

前綴表是用來回退的,它記錄了模式串與主串(文本串)不匹配的時候,模式串應該從哪里開始重新匹配。記錄了包含當下字符的最長公共前后綴的長度

匹配過程

要在文本串:aabaabaafa 中查找是否出現過一個模式串:aabaaf。




可以看出,文本串中第六個字符b 和 模式串的第六個字符f,不匹配了。如果暴力匹配,會發現不匹配,此時就要從頭匹配了。

但如果使用前綴表,就不會從頭匹配,而是從上次已經匹配的內容開始匹配,找到了模式串中第三個字符b繼續開始匹配。

那么什么是前綴表:記錄下標i之前(包括i)的字符串中,有多大長度的相同前綴后綴。

文章中字符串的
前綴是指不包含最后一個字符的所有以第一個字符開頭的連續子串。

后綴是指不包含第一個字符的所有以最后一個字符結尾的連續子串。
前綴表要求的就是相同前后綴的長度。

而最長公共前后綴里面的“公共”,更像是說前綴和后綴公共的長度。這其實并不是前綴表所需要的
所以字符串a的最長相等前后綴為0。 字符串aa的最長相等前后綴為1。 字符串aaa的最長相等前后綴為2。 等等…。

next數組的代碼實現

j是前綴的末尾(所以j也是公共最長前后綴的長度 因為從下標0開始的 next[i]也是包含i的公共最長前后綴的長度),i是后綴的末尾

  • 初始化 j=0 next[0]=0(0位置回退到0) i從1開始 for(i=1;i<len(s);i++)
  • 前后綴不同 s[i]!=s[j] 發生沖突 j回退到j前一位指向的值 因為是個不斷回退的過程 因為可能不止一次沖突 即while(j>0&&s[i]!=s[j] ) j=next[j-1]

(ps 為什么需要退回沖突的前一位 因為沖突前的位置是匹配的 所以退回到前一位所指向的值 即是最長公共前綴的后一位)
如下圖在f處沖突,所以退回到f的前一位a所指向的下標是2 說明最長前綴是2即aa 所以從下標2即b開始匹配

def getnext(s):next=[]#初始化j=0next.append(0)for i in range(1,len(s)):#前后綴不同 回退while j>0 and s[i]!=s[j]:j=next[j-1]# 前后綴相同 j自增if s[i]==s[j]:j+=1# 更新nextnext.append(j)return next
  • 前后綴相同 s[i]==s[j] j++ i++
  • 更新next數組 next[i]=j

28. 實現 strStr()

實現 strStr() 函數。

給你兩個字符串 haystack 和 needle ,請你在 haystack 字符串中找出 needle 字符串出現的第一個位置(下標從 0 開始)。如果不存在,則返回 -1 。

說明:

當 needle 是空字符串時,我們應當返回什么值呢?這是一個在面試中很好的問題。

對于本題而言,當 needle 是空字符串時我們應當返回 0 。這與 C 語言的 strstr() 以及 Java 的 indexOf() 定義相符。

示例 1:

輸入:haystack = “hello”, needle = “ll” 輸出:2
示例 2:

輸入:haystack = “aaaaa”, needle = “bba” 輸出:-1
示例 3:

輸入:haystack = “”, needle = “” 輸出:0

class Solution:def strStr(self, haystack: str, needle: str) -> int:def getnext(s):next=[]#初始化j=0next.append(0)for i in range(1,len(s)):#前后綴不同 回退while j>0 and s[i]!=s[j]:j=next[j-1]# 前后綴相同 j自增if s[i]==s[j]:j+=1# 更新nextnext.append(j)return nextif needle=='' :return 0 next=getnext(needle)j=0for i in range(len(haystack)):# 字符不匹配 沖突 回退while j>0 and haystack[i]!=needle[j]:j=next[j-1]# 匹配if haystack[i]==needle[j]:j+=1# 說明匹配完成if j==len(needle):return(i-len(needle)+1)return -1

459. 重復的子字符串

給定一個非空的字符串 s ,檢查是否可以通過由它的一個子串重復多次構成。

示例 1:

輸入: s = “abab” 輸出: true 解釋: 可由子串 “ab” 重復兩次構成。
示例 2:

輸入: s = “aba” 輸出: false
示例 3:

輸入: s = “abcabcabcabc” 輸出: true 解釋: 可由子串 “abc” 重復四次構成。 (或子串 “abcabc”
重復兩次構成。)

說明 (數組長度-最長相等前后綴的長度) 正好可以被 數組的長度整除,說明有該字符串有重復的子字符串。

數組長度減去最長相同前后綴的長度相當于是第一個周期的長度,也就是一個周期的長度,如果這個周期可以被整除,就說明整個數組就是這個周期的循環。

使用了前綴表統一減一的實現方式

前提:
next[len - 1] !=-1 說明是有重復子串的
next[len - 1] = 7,next[len - 1] + 1 = 8,8就是此時字符串asdfasdfasdf的最長相同前后綴的長度。

(len - (next[len - 1] + 1)) 也就是: 12(字符串的長度) - 8(最長公共前后綴的長度) = 4, 4正好可以被 12(字符串的長度) 整除,所以說明有重復的子字符串(asdf)。

class Solution:def repeatedSubstringPattern(self, s: str) -> bool:def getnext(s):next=[]#初始化j=0next.append(0)for i in range(1,len(s)):#前后綴不同 回退while j>0 and s[i]!=s[j]:j=next[j-1]# 前后綴相同 j自增if s[i]==s[j]:j+=1# 更新nextnext.append(j)return nextnext=getnext(s)rest=len(s)-next[len(s)-1]if len(s)%rest==0 and next[len(s)-1]!=0:return Truereturn False

總結

以上是生活随笔為你收集整理的字符串-kmp的全部內容,希望文章能夠幫你解決所遇到的問題。

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