python中计算如何实现_详解KMP算法以及python如何实现

算法思路

knuth-morris-pratt(kmp)算法是解决字符串匹配问题的经典算法,下面通过一个例子来演示一下:

给定字符串"bbc abcdab abcdabcdabde",检查里面是否包含另一个字符串"abcdabd"。

1.从头开始依次匹配字符,如果不匹配就跳到下一个字符

b_0_202009200530524983.png

b_0_202009200530522254.png

2.直到发现匹配字符,然后经过一个内循环严查字符串是否匹配

b_0_202009200530526769.png

3.发现最后一个d不匹配,下面就该思考应该把字符串向右移动多少个位置呢?传统做法可能是移动一格,kmp算法就创新在这里。kmp算法通过查询一个partial match table(表内存有字符串信息),然后计算出需要移动的步数,这个表后面会介绍怎么来的。

b_0_202009200530526582.jpg

这里我们看到d前面是b,查表得到第二个b对应的是2,所以 移动数 = 已匹配字符数 - 查表所得数 也就是 6 - 2 = 4, 需要向右移动四格。

b_0_202009200530523854.jpg

下面也是重复这个步骤

b_0_202009200530524354.jpg

直到发现匹配或者字符长度超出(未发现匹配)。

partial match table

那么这个查询的表是怎么来的呢?仍然以"abcdabd"为例

b_0_202009200530526582.jpg

- "a"的前缀和后缀都为空集,共有元素的长度为0;

- "ab"的前缀为[a],后缀为[b],共有元素的长度为0;

- "abc"的前缀为[a, ab],后缀为[bc, c],共有元素的长度0;

- "abcd"的前缀为[a, ab, abc],后缀为[bcd, cd, d],共有元素的长度为0;

- "abcda"的前缀为[a, ab, abc, abcd],后缀为[bcda, cda, da, a],共有元素为"a",长度为1;

- "abcdab"的前缀为[a, ab, abc, abcd, abcda],后缀为[bcdab, cdab, dab, ab, b],共有元素为"ab",长度为2;

- "abcdabd"的前缀为[a, ab, abc, abcd, abcda, abcdab],后缀为[bcdabd, cdabd, dabd, abd, bd, d],共有元素的长度为0。

python实现

def partial_table(p):

'''''partial_table("abcdabd") -> [0, 0, 0, 0, 1, 2, 0]'''

prefix = set()

res = [0]

for i in range(1, len(p)):

prefix.add(p[:i])

postfix = {p[j:i + 1] for j in range(1, i + 1)}

#print(p[:i+1],prefix,postfix,prefix & postfix or {''})

res.append(len((prefix & postfix or {''}).pop()))

return res

def kmp_match(s, p):

m = len(s);

n = len(p)

cur = 0 # 起始指针cur

table = partial_table(p)

while cur <= m - n: #只去匹配前m-n个

for i in range(n):

if s[i + cur] != p[i]:

cur += max(i - table[i - 1], 1) # 有了部分匹配表,我们不只是单纯的1位1位往右移,可以一次移动多位

break

else:

return true # loop从 break 中退出时,else 部分不执行。

return false

print partial_table1("abcdabd")

print kmp_match("bbc abcdab abcdabcdabde", "abcdabd")

以上就是详解kmp算法以及python如何实现的详细内容,更多关于python实现kmp算法的资料请关注萬仟网其它相关文章!

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值